Skip to content

RaftStatePublisherSysMod

Rob Dobson edited this page Oct 27, 2026 · 10 revisions

StatePublisher SysMod

Overview

The StatePublisher module is responsible for handling the publication of state information from other SysMods. It supports subscriptions, dynamic updates, and efficient data transfer by using a hashing mechanism to detect changes in state that might trigger publishing. The module is highly configurable via JSON, allowing for flexible publication settings.

Any SysMod can be a publisher of state information.

Publication Records

Publication sources are created dynamically when SysMods register as data sources via the registerDataSource API. There is no need to pre-configure publication topics - they are automatically added when a SysMod registers with its unique PubTopic. Each publication source must have a unique topic name.

A SysMod with data to publish must register with the StatePublisher, specifying the PubTopic under which it wants to publish its data, along with message generation and state detection callbacks.

For further information see Registering a Data Source for Publishing

JSON Configuration

The StatePublisher is configured using minimal JSON settings. Publication sources are now created automatically when SysMods register as data sources - there is no need to pre-configure publication topics. Publishing requires explicit subscription via the REST API for ALL interfaces (including BLE and serial). Subscriptions specify publishing rate, trigger type, and minimum time between messages.

See StatePublisher Settings

Example JSON Configuration for StatePublisher

The StatePublisher configuration is minimal - publication topics are added automatically when SysMods register:

"Publish": {
    "enable": 1
}

Note: When a SysMod calls registerDataSource with a topic name, the publication source is automatically created. Clients must explicitly subscribe via the REST API to receive data on any interface (including BLE, WebSocket, and serial).

StatePublisher publishing operation

Once the state change is detected, the system calls the msgGenCB to generate the actual data to be published. This message is then sent through the appropriate communication channel.

Here’s the flow for publishing data:

  1. Check Interface: Before publishing, the system checks whether the specified communication channel is available for sending data.
  2. Generate Message: The msgGenCB is invoked to generate the message content.
  3. Send Data: The message is sent using the CommsCoreIF::outboundHandleMsg function.

Subscription Mechanism

Subscriptions are created and updated through the /subscription REST API endpoint. This allows clients to dynamically subscribe to specific messages based on the publication name, interface, and rate. All publishing now requires explicit subscription - there are no pre-configured automatic publications.

  • Subscription Request: The client sends a request to the /subscription endpoint with the details of the publications they want to subscribe to. The request contains:
    • action: update updates the subscription to each topic in pubRecs, or creates it if there isn't one (a rateHz of 0 removes it). unsubscribe removes the subscription to topic.
    • pubRecs: The publication records to subscribe to, including the topic, rate, and optional trigger and minimum time between messages. A single record can be given instead as topic, rateHz and minMs parameters (e.g. subscription?action=update&topic=Camera&rateHz=2).

Subscriptions are specific to the communication channel on which the request is made, and last while the client is connected:

  • A client's subscription is removed when a publish finds no connection on its channel: a WebSocket connection slot with no client, or BLE with no central connected. A WebSocket channel belongs to a connection slot, so otherwise the next client in the slot would get the publishes without subscribing. Clients subscribe when they connect (raftjs does).
  • An MQTT channel reports no connection while the broker isn't connected (and an inbound-topic channel always does), so a client's subscription on it is removed by a publish made while MQTT is disconnected.
  • Subscriptions created by a SysMod or config with createSubscription (e.g. the MQTTManager pubSources config) are kept while their channel has no connection; they are retried at their normal interval and publish once it connects. (RaftSysMods versions after 1.29.0; earlier they were removed like a client's.)
  • Channels that don't report connections (serial) keep their subscriptions.
  • (In RaftSysMods 1.27 and earlier, a subscription was kept when its connection had gone, and a rateHz of 0 kept it with a rate of 0, which published as fast as minMs allowed.)

Example Subscription Request:

{
    "action": "update",
    "pubRecs": [
        {
            "topic": "devjson",
            "rateHz": 1.0,
            "trigger": "timeorchange",
            "minMs": 100
        }
    ]
}

Subscription Parameters:

  • topic (required): Topic name to subscribe to (must match a topic registered by a SysMod via registerDataSource)
  • rateHz (required): Publishing rate in Hz, or 0 to remove the subscription
  • trigger (optional): Override the default trigger type ("change", "time", "timeorchange")
  • minMs (optional): Minimum interval between messages in milliseconds

Note: For information about the devjson and devbin topics automatically published by DeviceManager, see Device Data Publishing.

Connection State Management

When there is no connection on a subscription's channel, a client's subscription is removed and one created with createSubscription is kept (see Subscription Mechanism). Other publish failures (e.g. a message that couldn't be sent) back off progressively, to reduce overhead:

  • ACTIVE: Publishing normally
  • LOST: Failing, retried at the normal interval
  • BACKOFF_STAGE_1: After 3 consecutive failures, the interval is twice as long
  • BACKOFF_STAGE_2: After 10, 10 times as long
  • BACKOFF_STAGE_3: After 20, 20 times as long

A successful publish restores the normal rate.

Clone this wiki locally