Skip to content

Status

Status is the current observable state of a device or function right now.

Adapters do not publish status messages directly. Adapter code changes status through generated function methods, framework-managed functions, command helpers, or StatusBatch during polling. The framework turns those state changes into status messages.


What is Status?

       Question: "What is the current state?"
            |
            v
+------------------+      +------------------+      +------------------+
|    PQ System     |      |    Framework     |      | Physical Device  |
+------------------+      +------------------+      +------------------+
                                   ^
                                   |
                          Adapter reports facts:
                          - event-driven function call
                          - poll snapshot via StatusBatch
                                   |
                                   v
                          +------------------+
                          | Current Status   |
                          | "Door: open"     |
                          | "Power: fault"   |
                          +------------------+

Status is:

  • Present tense - describes state right now
  • Snapshot - captured at specific moment
  • Changeable - same device may report different status later
  • Queryable - PQ can ask "what's your current status?"

Status vs Event vs Command

I want to... Use
Report current state Status
Report something that happened Event
Request an action Command
STATUS:  "Door is unlocked"        (right now)
EVENT:   "Door was unlocked"       (in the past)
COMMAND: "Unlock the door"         (in the future)

Status vs Event: Key Difference

Timeline:  ----[unlock cmd]----[door opens]----[door closes]----
                    |               |               |
Events:             |         "door.opened"   "door.closed"
                    |               |               |
Status:       "locked"         "unlocked"       "locked"
              "closed"          "open"          "closed"

Events mark points in time (something happened). Status describes continuous state (current condition).


Common Status Types

Connection Status

+------------+     +------------+     +------------+
|  offline   | --> |  connecting| --> |   online   |
+------------+     +------------+     +------------+
      ^                                     |
      +-------------------------------------+
                  (connection lost)
Status Meaning
online Device connected and responding
offline Device not reachable
connecting Attempting to connect
degraded Connected but with issues

Door Status

Status Meaning
locked Lock is engaged
unlocked Lock is disengaged
open Door is physically open
closed Door is physically closed

Function Status

Status Meaning
ready Function ready to operate
busy Function processing
error Function in error state
disabled Function turned off

Fire Status

Status Meaning
fire.alarm Fire alarm active
fire.alarm.general General fire alarm active
fire.alarm.section Section or zone-level alarm active
fire.alarm.conditional Conditional alarm active
fire.trouble Fire trouble/fault active
fire.disabled Fire address, sounder, routing, or control output disabled
fire.test Fire panel, group, or address in test
fire.input.active Fire input address active
fire.output.active Fire output/control address active
fire.panel.day / fire.panel.night Fire panel operating mode

Status Structure

+--------------------------------------------------+
|                   StatusMessage                   |
+--------------------------------------------------+
| AdapterId:  (which adapter)                       |
| NodeId:     (which device/thing, or Guid.Empty)  |
| Data:       {                                     |
|               "connection": "online",             |
|               "doors": {                          |
|                 "door-1": "locked",               |
|                 "door-2": "unlocked"              |
|               },                                  |
|               "lastUpdate": "2025-01-15T10:15:03Z"|
|             }                                     |
+--------------------------------------------------+

How Status Changes

1. Event-Driven State Change

Device state: locked --> unlocked
                    |
                    +---> Adapter calls generated function method
                          Framework updates status

Example: a device reports that a door opened. The adapter routes the event to the door Thing and calls Opened(timestamp). That call publishes the event and updates the Door function status.

2. Poll Snapshot

Poll interval:
    +---> Adapter reads current device state
    +---> Adapter writes one StatusBatch snapshot
    +---> Framework publishes the changed status diff

Polling is for devices that do not push every state change. Use StatusBatch so related function states are updated atomically.

3. Framework-Managed Status

Connection lost:
    +---> ConnectionBaseFunction updates connection status
    +---> Framework propagates the effective state

Connection, lifecycle, enrollment, pending command states, and similar operational statuses are framework-owned. Adapter code should not create raw StatusMessage objects for them.

4. Startup Discovery

Adapter starts:
    |
    +---> Query all device states
    +---> Build initial Thing state
    +---> Framework has the first current status snapshot

Status Aggregation

Devices form hierarchy. Status aggregates upward:

Adapter Status: "degraded"
    |
    +-- Door Controller 1: "online"
    |       |
    |       +-- Reader 1: "online"
    |       +-- Reader 2: "offline"  <-- problem here
    |
    +-- Door Controller 2: "online"
            |
            +-- Reader 3: "online"

Child "offline" -> Parent "degraded" -> Adapter "degraded"

Framework handles aggregation via FunctionStatusAggregator.


Example: Status Updates

// Event-driven device report: one function call updates event + status.
private static async Task HandleDoorOpened(DoorThing door, DoorEvent evt)
{
    await door.Opened(evt.Timestamp);
}

// Polled device report: one batch updates the current snapshot.
public static async Task PollStatus(DoorThing door, IProtocol protocol, CancellationToken ct)
{
    var state = await protocol.ReadDoorState(door.Address, ct);

    await door.StatusBatch()
        .Set(state.IsOpen ? DoorState.Open : DoorState.Closed)
        .Commit(ct);
}

The adapter reports facts to the framework. The framework owns the status message shape, aggregation, and publishing.


Status vs Properties

Common confusion:

Aspect Status Property
Question "What state is it in?" "How is it configured?"
Changes Frequently (device reports) Rarely (admin sets)
Source Device tells adapter PQ tells adapter
Examples online/offline, open/closed IP address, door name
STATUS:   "Door is open"      (device reports this)
PROPERTY: "Unlock duration: 5s" (admin configured this)

Common Mistakes

1. Publishing Event Instead of Updating Status

// WRONG - "online" is status, not event
PublishEvent("device.online", ...);
PublishEvent("device.online", ...);  // publishing same "event" repeatedly

// RIGHT - use the connection function/lifecycle path so framework updates status
await Connect(ct);

2. Publishing Status Directly From Adapter Code

// WRONG - adding adapter-owned status publishing plumbing
await myStatusPublisher.PublishDoorState(door, ct);

// RIGHT - update through generated functions or StatusBatch
await door.Opened(timestamp);

3. Incomplete Status on Startup

// WRONG - mark device online without discovering current states
await Connect(ct);

// RIGHT - query device for complete state before the first poll snapshot
var doorStates = await _protocol.GetAllDoorStates();
await ApplyInitialSnapshot(doorStates, ct);

Status Freshness

Scenario How status becomes fresh
Device pushes events Generated function calls update status immediately
Device is polled PollStatus writes a StatusBatch snapshot
Connection changes ConnectionBaseFunction updates status
Startup Initial discovery/poll establishes current state
Recovery Reconnect flow and first successful poll refresh status

Next: Commands - Handling action requests