mqtt_bus / home_bus.md
1 contributor
310 lines | 9.282kb

Home Bus

Purpose

The home bus exposes room-centric and user-facing telemetry, state, and control topics for the living environment.

Typical systems connected to this bus include:

  • environmental sensors
  • lighting and switches
  • motion/contact/presence sensors
  • thermostats and climate devices
  • smart sockets for on/off control semantics

The home bus models living-space behavior, not electrical topology.

This document defines the home-specific topic grammar and semantic ownership.

Shared rules for payload profiles, metadata, time semantics, quality, and operational topics are defined in mqtt_contract.md.

Scope and Ownership

The home bus owns room and automation semantics.

The energy bus owns electrical accounting semantics.

Examples:

  • vad/home/living-room/power/tv/value is room control state
  • vad/home/living-room/power/tv/set is room control command
  • vad/energy/load/living-room-entertainment/active_power/value is electrical telemetry

Rule:

  • publish user-oriented control/state on home
  • publish electrical measurement and accounting on energy

Normative Topic Contract (v1)

All home topics MUST follow:

<site>/home/<location>/<capability>/<device_id>/<stream>

Where:

  • <site>: deployment/site id, for example vad
  • <location>: normalized area identifier in kebab-case
  • <capability>: semantic capability in snake_case
  • <device_id>: stable device/entity identifier in kebab-case
  • <stream>: one of value, last, set, meta, availability

Examples:

  • vad/home/bedroom/temperature/bedroom-sensor/value
  • vad/home/living-room/motion/radar-south/value
  • vad/home/kitchen/light/ceiling-switch/value
  • vad/home/living-room/power/tv/set

Canonical Identity Model

The home bus is built around stable room semantics.

Rules:

  • <location> MUST describe the living-space area, not the vendor room name if the two differ
  • <device_id> MUST identify the logical endpoint exposed to consumers
  • one physical device MAY publish multiple capabilities under the same <device_id>
  • replacing a physical Zigbee sensor SHOULD keep the same canonical <device_id> when the logical endpoint remains the same

Examples:

  • bedroom-sensor is a logical endpoint
  • 0x00158d0008aa1111 is a vendor identity and belongs in meta.source_ref, not in the topic path

This keeps HomeKit, historian, and automations insulated from vendor identity churn.

Stream Semantics

  • value: live semantic sample, whether measurement, held state, or transition notification
  • last: retained last-known timestamped sample for startup/bootstrap decisions
  • set: command/request topic for controllable capabilities
  • meta: static or slowly-changing metadata
  • availability: online/offline state

Rules:

  • adapters SHOULD emit live hot-path data only on value
  • adapters SHOULD deduplicate repeated value samples when the semantic value did not change
  • adapters SHOULD publish retained last for the latest known timestamped sample
  • legacy state and event topics SHOULD be treated as compatibility-only during migration

Command safety:

  • set MUST NOT be retained
  • stateful devices SHOULD acknowledge commands via value
  • payload profile and time semantics follow mqtt_contract.md

Payload Contract

To keep Node-RED flows efficient, two payload profiles are allowed.

Profile A: Hot Path Scalar (recommended)

For frequent updates, payload SHOULD be scalar.

Examples:

  • vad/home/bedroom/temperature/bedroom-sensor/value -> 23.6
  • vad/home/living-room/motion/radar-south/value -> true

Metadata is published separately on retained meta.

Example:

  • Topic: vad/home/bedroom/temperature/bedroom-sensor/meta
  • Payload:
{
  "unit": "C",
  "source": "zigbee_adapter",
  "precision": 0.1
}

Profile B: Envelope JSON (optional)

For streams that need inline quality/timestamp:

{
  "value": 23.6,
  "unit": "C",
  "observed_at": "2026-03-08T10:15:12Z",
  "quality": "good"
}

Recommendation:

  • prefer Profile A on high-frequency paths
  • use Profile B where source quality/time must travel with each sample
  • if exact source timestamp must be preserved, use Profile B
  • use last with Profile B and observed_at when control consumers need a startup sample with freshness information
  • do not repeat metadata or adapter internals in value payloads
  • keep Profile B envelopes small and canonical

Capability Catalog (initial)

Environmental capabilities:

  • temperature
  • humidity
  • pressure
  • illuminance
  • co2
  • voc
  • pm25
  • pm10

Presence and safety capabilities:

  • motion
  • presence
  • contact
  • water_leak
  • smoke
  • gas
  • tamper

Control and user-facing capabilities:

  • light
  • power
  • lock
  • cover_position
  • thermostat_mode
  • target_temperature
  • fan_mode
  • button

Device health capabilities that are still user-relevant:

  • battery
  • battery_low

Rules:

  • use power on home only for control semantics
  • use electrical telemetry such as active_power and cumulative counters such as energy_total on energy
  • radio diagnostics such as linkquality SHOULD NOT go on home by default
  • presence SHOULD normally be a higher-level derived state, not a raw single-device detection
  • raw mmWave detection, including Zigbee presence with fading_time=0, SHOULD be published as motion

MQTT Delivery Policy

Default policy:

  • value: QoS 1, retain false
  • last: QoS 1, retain true
  • set: QoS 1, retain false
  • meta: QoS 1, retain true
  • availability: QoS 1, retain true (LWT preferred)

Cold-start rule:

  • control consumers such as thermostats SHOULD subscribe to retained last to obtain the latest known sample at startup
  • last SHOULD include observed_at so staleness can be evaluated immediately after subscribe
  • consumers MAY unsubscribe from last after bootstrap and continue consuming lightweight live updates on value
  • consumers that depend on deterministic retained bootstrap SHOULD use a dedicated MQTT client session instead of sharing the same broker config with unrelated subscribers

If uncertain, choose QoS 1.

Node-RED Implementation Optimizations

Translation is done in Node-RED, so the contract is optimized for low processing overhead.

Guidelines:

  • keep topic shape stable to simplify wildcard routing and switch nodes
  • avoid unnecessary JSON parse/build in high-rate pipelines
  • publish device metadata on retained meta to avoid payload repetition
  • publish canonical MQTT-ready messages as early as possible after normalization
  • emit MQTT-ready messages only at the publish boundary
  • do not carry adapter-internal normalization structures on forwarded msg objects
  • discard temporary normalization fields before publish
  • keep value streams extremely lightweight
  • centralize mapping rules (location, capability, device_id) in reusable subflows
  • keep one ingress subflow per protocol and one normalization subflow shared by all
  • avoid broad # subscriptions in hot paths

Suggested Node-RED subscriptions:

  • +/home/+/+/+/value
  • +/home/+/+/+/last
  • +/home/+/+/+/set

Interaction with Other Buses

Cross-bus correlations are implemented by consumers, not by changing bus semantics.

Examples:

  • combine home presence with energy load telemetry for occupancy-aware energy decisions
  • combine home climate data with network device state for diagnostics

Historian Relationship

The home bus is a major historian source.

For ingestion worker compatibility, each message should map to:

  • metric_name
  • device_id
  • value
  • observed_at

device_id recommendation:

  • <location>.<device_id>

Historian defaults:

  • value streams SHOULD be ingested by default
  • last streams SHOULD NOT be ingested as normal telemetry samples
  • meta.historian.mode SHOULD describe whether a value stream represents sample, state, or event semantics
  • when Profile A scalar is used, observed_at will usually fall back to ingestion time
  • string enum states are semantically valid, but the current PostgreSQL ingestion API directly supports only numeric and boolean samples

Example:

  • Topic: vad/home/bedroom/temperature/bedroom-sensor/value
  • metric_name = temperature
  • device_id = bedroom.bedroom-sensor

Zigbee2MQTT projection examples:

  • zigbee2mqtt/bedroom_sensor.temperature -> vad/home/bedroom/temperature/bedroom-sensor/value
  • zigbee2mqtt/front_door_contact.contact -> vad/home/entrance/contact/front-door/value
  • zigbee2mqtt/bedside_remote.action -> vad/home/bedroom/button/bedside-remote/value

Relationship with HomeKit

The home bus is a primary source for HomeKit adapters.

HomeKit integration remains a consumer layer concern:

  • Device -> Protocol Adapter -> MQTT Bus -> HomeKit Adapter -> HomeKit

The home bus contract SHOULD remain independent from HomeKit-specific modeling constraints.

Design Principles

  • keep room-centric semantics explicit and stable
  • separate control semantics (home) from electrical accounting (energy)
  • optimize for deterministic, low-cost Node-RED translation
  • keep topic grammar strict and payload overhead low
  • keep canonical IDs independent from vendor identifiers