streamdeck_client 0.3.0 copy "streamdeck_client: ^0.3.0" to clipboard
streamdeck_client: ^0.3.0 copied to clipboard

Pure Dart client for the Elgato Stream Deck WebSocket protocol. Handles connection, reconnection, event parsing, and manifest models.

streamdeck_client #

Pure Dart client for the Elgato Stream Deck WebSocket protocol. Handles connection, reconnection, event parsing, manifest models, and device layout constants.

Usage #

The Stream Deck app launches your plugin with CLI args: -port, -pluginUUID, -registerEvent, -info. Parse them with ConnectionInfo.fromArgs, connect, and react to events.

import 'dart:convert';
import 'dart:io';

import 'package:streamdeck_client/streamdeck_client.dart';

void main(List<String> args) async {
  // Parse CLI args from the Stream Deck app.
  final connection = ConnectionInfo.fromArgs(args);
  final client = Client(connection);
  await client.connect();

  // Track which actions are visible on the device.
  client.actions.listen((actions) {
    for (final action in actions.values) {
      print('Active: ${action.action} at '
          '(${action.payload.coordinates.column}, '
          '${action.payload.coordinates.row})');
    }
  });

  // Listen to all events globally.
  client.events.listen((event) {
    switch (event) {
      case ActionInfo():
        // An action appeared on the device. ActionInfo is the
        // willAppear event — it carries the action UUID, context,
        // device, coordinates, settings, and controller type.
        final scoped = client.scoped(event.context);
        scoped.setTitle(title: 'Ready');
        print('willAppear: ${event.action} '
            'controller=${event.payload.controller}');

      case WillDisappearEvent():
        print('willDisappear: ${event.context}');

      case KeyDownEvent():
        client.showAlert(event.context);
        print('keyDown: ${event.context}');

      case KeyUpEvent(:final payload):
        print('keyUp: state=${payload.state}');

      case DialRotateEvent(:final payload):
        print('dialRotate: ${payload.ticks} ticks');

      case DialDownEvent():
        print('dialDown');

      case DialUpEvent():
        print('dialUp');

      case TouchTapEvent(:final payload):
        print('touchTap: pos=${payload.tapPos}');

      case DidReceiveSettingsEvent(:final payload):
        print('settings: ${jsonEncode(payload.settings)}');

      default:
        break;
    }
  });

  // Or listen to events for a specific action context.
  // This is more efficient — events are filtered and cached.
  client.eventsFor('some-context-id').listen((event) {
    switch (event) {
      case KeyDownEvent():
        final scoped = client.scoped(event.context);
        scoped.setSettings(settings: {'count': 42});
        scoped.showOk();
      default:
        break;
    }
  });

  // Keep the process alive.
  await ProcessSignal.sigint.watch().first;
  await client.dispose();
}

Connection Lifecycle #

connect() → Connection.connecting → Connection.connected
                                          ↓ (socket drops)
                                   Connection.disconnected
                                          ↓ (auto)
                                   Connection.reconnecting → connected
                                          ↓ (max attempts)
                                   Connection.failed

Monitor connection state:

client.connection.listen((state) {
  print('Connection: $state');
});

// Or read synchronously:
if (client.connectionValue == Connection.connected) { ... }

Scoped Client #

When working with a specific action, use scoped() to avoid passing the context on every call:

client.events.listen((event) {
  if (event case ActionInfo()) {
    final action = client.scoped(event.context);
    action.setTitle(title: 'Hello');
    action.setSettings(settings: {'key': 'value'});
    action.showAlert();
    // All calls auto-fill context from the scoped client.
  }
});

Features #

  • WebSocket client with automatic reconnection (exponential backoff, configurable max attempts).
  • Full protocol coverage: all received events (keyDown, dialRotate, touchTap, willAppear, etc.) and sent commands (setImage, setFeedback, setSettings, etc.).
  • Typed event models using freezed — toString, ==, hashCode, copyWith, fromJson/toJson.
  • Manifest models for generating manifest.json from Dart code.
  • Device layouts with key sizes, gaps, margins, and encoder dimensions for all Stream Deck models.
  • Scoped clientclient.scoped('context-id') returns a lightweight wrapper that auto-fills the action context on all send methods.
0
likes
130
points
247
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Pure Dart client for the Elgato Stream Deck WebSocket protocol. Handles connection, reconnection, event parsing, and manifest models.

Repository (GitHub)
View/report issues

Topics

#streamdeck #elgato #websocket

License

BSD-3-Clause (license)

Dependencies

freezed_annotation, json_annotation, logging, rxdart

More

Packages that depend on streamdeck_client