Holoseat Controller Communications Protocol

Introduction

The Holoseat controller has a two layer communication stack. The lower (private) layer is a custom serial protocol, implemented in JSON messages. The upper (public) layer is a Socket.io event/message API wrapping around the serial protocol. This architecture places the bulk of the responsibility for implementation on the firmware, accessed using the private layer. The public layer is then only responsible for passing messages in/out of the private API and reporting when the Holoseat is disconnected.

This page serves to document both layers. Each event/message will be covered at a conceptual level followed by layer specific information and examples.

Serial Port Configuration

Field Value
Baud Rate 115200
Data Bits 8
Parity None
Stop Bit 1

Controller Events/Messages

This section covers the events and message that the controller responds to (aka those sent to the controller by clients).

Note, the various set_* events only broadcast their corresponding client events when they receive data that leads to an actual state change. So, if the Holoseat is already enabled and set_enabled is called with a value of True, then no state change will occur and in turn the enabled event will not be broadcast to the clients.

connect (event)

Purpose: Used to establish client connection

Event Specific Inputs

  • none

Response

  1. controller-version message sent to connecting client
  2. enabled event sent to connecting client
  3. cadence event sent to connecting client
  4. configuration event sent to connecting client
  5. resistance event sent to connecting client FUTURE DEVELOPMENT

Public Layer Details

Event Name: connect
Event Data: none

Private Layer Details

Serial Message: {"event_name":"connect", "client_id":<socket.id>}

set_enabled (event)

Purpose: Used to toggle enabled state

Event Specific Inputs

  • enabled: boolean - new enabled state for the holoseat controller

Response

  1. enabled event sent to all clients

Public Layer Details

Event Name: set_enabled
Event Data: {"enabled":<True|False>}

Private Layer Details

Serial Message: {"event_name":"set_enabled", "client_id":<socket.id>, "data":{"enabled":<True|False>}}

set_configuration (event)

Purpose: Used to give Holoseat a new configuration (aka tell it how to react to cadences)

Event Specific Inputs

  • configuration: configuration data (see below) or an empty dictionary to reset Holoseat to hardware default configuration (wasd)

Response

  1. configuration event sent to connecting client

Configuration Schema

  • name(string): label for the current configuration
  • forward = dictionary: how to respond to forward pedaling
    • hid(string <"keyboard" | "mouse" | "joypad">): what device is being emulated for this direction (v1.0.x will only support keyboard)
    • responses(array of dictionaries): list of responses keyed off of trigger cadences
      • triggerCadence(int): action occurs when current cadence >= triggerCadence; use 0 for at all cadences
      • actions(array): set of discrete hid actions to take (e.g. [“shift”, “w”] could indicate pressing the shift+w on keyboard); specifics are device emulation dependent, will be specified in a separate doc; actions are always to hold some hid signal until cadence changes and action is reevaluated (in other words actions cannot be single press/click)
  • reverse(dictionary): how to respond to reverse pedaling (same structure as forward)
Hardware defaults in configuration JSON

{"name":"wasd", "forward":{"hid":"keyboard", "responses":[{"triggerCadence":0, "actions":["w"]}]}, "reverse":{"hid":"keyboard", "responses":[{"triggerCadence":0, "actions":["s"]}]}}

This string would be hard coded into the firmware and used to initialize the default configuration object.

The No Op configuration JSON

Used by games responding to the cadence stream instead of hid actions.

{"name":"noop", "forward":{"hid":"keyboard", "responses":[]}, "reverse":{"hid":"keyboard", "responses":[]}}

Note the use of empty arrays for the responses. This can be used separately for configurations where only one direction makes sense.

Public Layer Details

Event Name: set_configuration
Event Data: {"configuration":<configuration object>}

Private Layer Details

Serial Message: {"event_name":"set_configuration", "client_id":<socket.id>, "data":{"configuration":<configuration object>}}

set_resistance (event) FUTURE DEVELOPMENT

Purpose: Manage the resistance level of the execise equipment Holoseat is connected to

Public Layer Details

TBD

Private Layer Details

TBD

Client Events/Messages

This section covers the events and message that clients must respond to (aka those sent by the controller to clients).

Note, events and messages read from the private layer may leave out the client_id. No client_id indicate public layer shoud broadcast the event/message to all connects clients (this ia the typcial behavior). Otherwise, the event/message should be sent only to th specified client.

enabled (event)

Purpose: Updates clients of enabled state when it changes

Event Specific Inputs

  • state: string indicating state <"enabled" | "disabled" | "disconnected">

Public Layer Details

Event Name: enabled
Event Data: {"state":<"enabled" | "disabled" | "disconnected">}

Note, The public layer is the layer which determines if the state is "disconnected". This determination is made every time an event is handled by the public layer. If Holoseat is disconnectd, this event will be broadcast to all clients regardless of value in the client_id field or the original event received.

Private Layer Details

Serial Message: {"event_name":"enabled", "client_id":<socket.id>, "data":{"state":<"enabled" | "disabled">}}

cadence (event)

Purpose: Updates clients of cadence when it changes

Event Specific Inputs

  • cadence: integer indicating how fast user is pedalling/stepping

Public Layer Details

Event Name: cadence
Event Data: {"cadence":<current cadence>}

Private Layer Details

Serial Message: {"event_name":"cadence", "client_id":<socket.id>, "data":{"cadence":<current cadence>}}

configuration (event)

Purpose: Updates clients of cadence when it changes

Event Specific Inputs

  • configuration: configuruation data (see above)

Public Layer Details

Event Name: configuration
Event Data: {"configuration":<configuration object>}

Private Layer Details

Serial Message: {"event_name":"configuration", "client_id":<socket.id>, "data":{"configuration":<configuration object>}}

resistance (event) FUTURE DEVLOPMENT

Purpose: Updates clients on exercise equipment resistance

Public Layer Details

TBD

Private Layer Details

TBD

controller_version (message)

Purpose: Inform clients of attached Holoseat device and its hardware and firmare versions (see Version Scheme for details).

Message Specific Inputs

  • type: "controller_version"
  • message (dictionary):
    • device (string): name of connected device (e.g. "Holoseat", "Holoseat Alpha")
    • hwVer (string): major version number of hardware (e.g. 1)
    • fwVer (string): major.minor.patch version number of firmware (e.g. 1.0.0)

Public Layer Details

Message Data: {"type":"controller_version", "message":{"device":"<device name>", "hwVer":"<major version number>", "fwVer":"<major.minor.patch version number>"}}

Private Layer Details

Serial Message: {"event_name":"message", "client_id":<socket.id>, "data":{"type":"controller_version", "message":{"device":"<device name>", "hwVer":"<major version number>", "fwVer":"<major.minor.patch version number>"}}}

controller_error (message)

Purpose: Inform clients of error message

Message Specific Data

  • type: contoller_error
  • message (string): the error message from the controller

Public Layer Details

Message Data: {"type":"controller_error", "message":"<error message>"}

Private Layer Details

Serial Message: {"event_name":"message", "client_id":<socket.id>, "data":{"type":"controller_error", "message":"<error message>"}}

Also available in: HTML TXT