Notifications

Subscribe to real-time PLC variable changes via SSE or WebSocket. Requires feature flag Notifications enabled.

Server-Sent Events (SSE)

Endpoint: Server-Sent Events (SSE) API_NOTIFICATIONS_SSE
status: implemented
component: Notifications
method: SSE
route: /api/plcs/{plcId}/notifications/sse?symbols={symbolPath}
policy: ReadAccess
implements: FEAT_NOTIFICATIONS

Simple HTTP-based streaming. Best for AI agents and lightweight clients.

Event types

These are the only events the stream emits:

event: subscribed
data: {"symbols":["MAIN.nCounter","MAIN.bRunning"]}

event: change
data: {"symbol":"MAIN.nCounter","value":42,"type":"UDINT","timestamp":"2026-03-18T14:22:01Z"}

event: heartbeat
data: {}

A missing heartbeat is currently the only in-band signal that something is wrong. Treat a gap of more than two heartbeat intervals as a lost stream and reconnect. Errors that occur before the stream opens — unknown plcId, too many symbols, connection limits — come back as an ordinary JSON error response with a 4xx status, not as an SSE event.

Not emitted (planned). Earlier revisions of this page documented error, disconnected and reconnected events. The server has never sent them, so a client that waits for disconnected to learn the PLC dropped will wait forever and read the silence as good health. They are listed here as a planned addition only — do not write a client against them yet.

event: error
data: {"symbol":"MAIN.old","code":"SYMBOL_INVALIDATED","message":"Symbol no longer exists"}

event: disconnected
data: {"plcId":"Line1","code":"PLC_UNAVAILABLE"}

event: reconnected
data: {"plcId":"Line1"}

They are kept rather than dropped because they are now implementable for the first time: Dahlke.TwinCAT.Ads exposes ConnectionStateChanged on IAdsConnection, so the PLC-level connect/disconnect signal the previous ADS layer never provided is available to SseController.StreamSse.

Example

curl -N "http://localhost:5000/api/plcs/Line1/notifications/sse?symbols=MAIN.nCounter"

WebSocket (SignalR)

Endpoint: WebSocket (SignalR) API_NOTIFICATIONS_WS
status: implemented
component: Notifications
method: WS
route: /api/plcs/{plcId}/notifications/ws
policy: ReadAccess
implements: FEAT_NOTIFICATIONS

Bidirectional communication via SignalR. Best for HMI applications needing rich interaction.

Authentication

Browser WebSocket connections cannot send Authorization headers. Pass the JWT via query string: ?access_token=<jwt>

Hub methods

Method

Direction

Description

Subscribe(string[] symbols)

Client -> Server

Subscribe to variable changes

Unsubscribe(string[] symbols)

Client -> Server

Unsubscribe from variables

SubscriptionConfirmed(string[] symbols)

Server -> Client

Confirms subscription

VariableChanged(object event)

Server -> Client

Variable value changed

Shared Subscriptions

Multiple clients subscribing to the same symbol on the same PLC share a single ADS notification. Reference-counted: the ADS notification is removed only when the last client unsubscribes.

Limits

  • MaxSymbolsPerClient: 50 (configurable)

  • Heartbeat interval: 30s (configurable)

  • Default cycle time: 100ms (configurable)