MQTT Topics¶
suncast publishes shadow visualizations, health information, and errors to a set of
MQTT topics under the suncast/ prefix. suncast is a pure telemetry service — there
are no inbound command topics.
Topic Overview¶
| Topic | Dir | Payload | Retain | QoS |
|---|---|---|---|---|
suncast/status |
outbound | Heartbeat JSON | yes | 1 |
suncast/shadow/svg |
outbound | Raw SVG string | yes | 1 |
suncast/shadow/png |
outbound | Base64 PNG | yes | 1 |
suncast/shadow/availability |
outbound | "online"/"offline" |
yes | 1 |
suncast/shadow/error |
outbound | Error JSON | no | 1 |
suncast/error |
outbound | Error JSON | no | 1 |
Payload Schemas¶
Status (Heartbeat)¶
Topic: suncast/status
Periodic heartbeat published by the cosalette health reporter. Also used as the Last
Will and Testament (LWT) — the broker publishes "offline" if suncast disconnects
unexpectedly.
{
"status": "online",
"uptime": 3600.5,
"version": "0.1.0",
"devices": {
"shadow": { "status": "online", "last_seen": 1700000000.0 }
}
}
Shadow SVG¶
Topic: suncast/shadow/svg
Raw SVG string. Published every poll cycle. Subscribe and render directly in your dashboard (e.g. Home Assistant picture-elements card, Grafana HTML panel).
Shadow PNG¶
Topic: suncast/shadow/png
Base64-encoded PNG image. Only published when SUNCAST_PNG_ENABLED=true.
Requires the png extra:
Shadow State¶
The shadow device publishes visualization data via the svg and png channels
rather than the standard state topic. The telemetry handler returns None,
so no suncast/shadow/state message is published by the framework.
Availability¶
Topic: suncast/shadow/availability
Each device publishes its availability status. The cosalette framework manages these automatically.
Error¶
Topics: suncast/error, suncast/shadow/error
Published (not retained) when a device encounters an error. The cosalette framework deduplicates consecutive identical errors.
{
"type": "OSError",
"message": "Geometry file not found",
"device": "shadow",
"timestamp": 1700000000.0
}
Per-device error topics
In addition to the global error topic, cosalette publishes device-specific
errors to suncast/shadow/error. Both topics use the same payload format.
Framework Topics¶
Alongside the suncast-specific topics above, cosalette itself publishes two framework-owned topics. Both are always on — no setting disables them — retained, QoS 1, and republished byte-identically on every broker connect.
| Topic | Payload | Retain | QoS |
|---|---|---|---|
suncast/_meta/registry |
Canonical AsyncAPI 3.0.0 document | yes | 1 |
suncast/_meta/state_model_drift |
state_model drift snapshot JSON |
yes | 1 |
Registry (suncast/_meta/registry)¶
The canonical AsyncAPI document describing every channel suncast publishes and subscribes to. Inbound command channels are stripped from the published copy so the command surface is not exposed to anyone who can subscribe on a shared broker.
State Model Drift (suncast/_meta/state_model_drift)¶
A machine-readable snapshot of state_model declaration drift (ADR-069): a handler
whose state_model= argument disagrees with its return type annotation. The topic is
published even when there is no drift — a clean app publishes drift_count: 0 rather
than omitting the topic, so "no drift" is distinguishable from "never ran a version
that publishes this topic".
| Field | Type | Description |
|---|---|---|
schema_version |
integer | Envelope version; bumped only on an incompatible payload change |
drift_count |
integer | Number of handlers with a declaration/annotation conflict |
entries[].handler |
string | Registered handler name |
entries[].archetype |
string | "telemetry" or "command" |
entries[].kind |
string | Drift kind — currently only "annotation_conflict" |
entries[].declared_model |
string | The state_model= class name declared on the handler |
entries[].effective_annotation |
string | The handler's actual return type annotation |
Fleet-wide scraping
One subscription across a whole broker distinguishes a healthy app from one that predates this topic:
An app publishing drift_count: 0 is healthy. An app with no retained message
on this topic at all has not been upgraded past cosalette 0.9.0.
ACL guidance¶
Both topics disclose handler names, channel addresses, and payload schemas. If you
run a production broker ACL file, protect _meta/# the same way you protect
_meta/registry. Every mosquitto.conf shipped in this repo is
dev-only (allow_anonymous true, no ACL file), so there is nothing to change
in-repo — this note only applies if you deploy your own broker ACLs.
Topic Naming Convention¶
suncast follows the cosalette topic convention:
| Segment | Value |
|---|---|
prefix |
App name — suncast by default |
device |
Device name: shadow |
channel |
svg, png, availability, or error |
Global topics (status, error) omit the device segment: