streamdeck_client 0.1.0 copy "streamdeck_client: ^0.1.0" to clipboard
streamdeck_client: ^0.1.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 DialPressEvent(:final payload):
        print('dialPress: pressed=${payload.pressed}');

      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
0
points
247
downloads

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

unknown (license)

Dependencies

freezed_annotation, json_annotation, logging, rxdart

More

Packages that depend on streamdeck_client