The energy bus exposes telemetry for the electrical energy domain: production, storage, grid exchange, and electrical load measurement points.
This bus is used for energy accounting and historian ingestion, not for user-facing room automation semantics.
Shared payload, metadata, time, and operational rules are defined in mqtt_contract.md.
Typical systems connected to this bus include:
The energy bus owns telemetry that describes electrical topology and electrical flows.
The home bus owns room-centric control semantics.
Examples:
vad/home/living-room/power/tv/value is home automation statevad/energy/load/living-room-entertainment/active_power/value is electrical load telemetryRule:
homeenergyAll energy topics MUST follow:
<site>/energy/<entity_type>/<entity_id>/<metric>/<stream>
Where:
<site>: deployment/site id, for example vad<entity_type>: one of source, storage, grid, load, transfer<entity_id>: stable kebab-case identifier (no spaces)<metric>: canonical metric name in snake_case<stream>: one of value, last, set, meta, availabilityExamples:
vad/energy/source/pv-roof-1/active_power/valuevad/energy/storage/battery-main/soc/valuevad/energy/grid/main-meter/import_power/valuevad/energy/load/living-room-entertainment/active_power/valuevad/energy/transfer/pv-to-battery/power/valuevalue: live semantic sample, whether it represents a numeric measurement, a durable state, or a transition-like signallast: retained last-known timestamped sample for startup/bootstrap decisionsmeta: static or slowly changing metadataavailability: online/offline statusset: write/request command topic (only where command is supported)Rules:
valuevalue samples when the semantic value did not changelast for the latest known timestamped samplestate and event topics SHOULD be treated as compatibility-only during migration and SHOULD NOT be introduced by new adaptersCommand safety:
set topics MUST NOT be retainedvaluemqtt_contract.mdTo optimize Node-RED flow cost, two payload profiles are defined.
For high-frequency telemetry, value payload SHOULD be scalar (number or boolean).
Example:
vad/energy/source/pv-roof-1/active_power/value3245.7Metadata is published separately on retained meta.
Example:
vad/energy/source/pv-roof-1/active_power/meta{
"unit": "W",
"description": "PV inverter AC active power",
"source": "modbus_adapter",
"precision": 0.1
}
When observation time or quality must travel with each point:
{
"value": 3245.7,
"unit": "W",
"observed_at": "2026-03-08T10:15:12Z",
"quality": "good"
}
Recommendation:
last with Profile B and observed_at when startup decisions require freshness evaluationvalue payloadsobserved_at means device observation time, not broker receive timeCanonical units SHOULD follow SI conventions:
WWh or kWhVAHz%Naming rules:
entity_id: kebab-case (example battery-main)metric: snake_case (example active_power, import_energy_total)The energy bus may carry both measurement-style metrics and counter-style metrics.
Measurement-style examples:
active_powervoltagecurrentfrequencysoccharge_powerdischarge_powerCounter-style cumulative examples:
energy_totalimport_energy_totalexport_energy_totalDefault policy:
value: QoS 1, retain falselast: QoS 1, retain truemeta: QoS 1, retain trueavailability: QoS 1, retain true (use LWT where available)set: QoS 1, retain falseCold-start rule:
last for the latest known measurementlast SHOULD include observed_at so consumers can reject stale measurementslast after bootstrap and continue on live valueIf uncertain, choose QoS 1.
Because translation is implemented in Node-RED, the contract is optimized for low-overhead flows.
Guidelines:
<site> to simplify wildcard routingmeta topics to avoid repeated payload bloatmsg objectsvalue streams extremely lightweightfunction or change node set (device id, metric id, unit)# subscriptions in hot paths; use specific wildcard patternsSuggested Node-RED routing subscriptions:
+/energy/+/+/+/value+/energy/+/+/+/last+/energy/+/+/+/meta+/energy/+/+/+/availabilityEnergy generated by a source, usually under entity_type=source.
Examples:
active_powerenergy_totalEnergy held in storage, under entity_type=storage.
Examples:
soccharge_powerdischarge_powerImport/export metrics at connection points, under entity_type=grid.
Examples:
import_powerexport_powerimport_energy_totalexport_energy_totalElectrical load measurement points, under entity_type=load.
Examples:
active_powerenergy_totalNote: this is electrical telemetry semantics, not room-control semantics.
Flow between subsystems, under entity_type=transfer.
Examples:
pv-to-batterybattery-to-homeThe energy bus is a primary source for historian ingestion, but not all energy metrics use the same persistence path.
Measurement-style metrics such as active_power, voltage, current, frequency, soc, charge_power, and discharge_power are compatible with tdb_ingestion/mqtt_ingestion_api.md.
For those metrics, workers should map each incoming message to:
metric_namedevice_idvalueobserved_atdevice_id recommendation:
<entity_type>.<entity_id>Historian defaults:
value streams SHOULD be ingested by default for measurement-style metricslast streams SHOULD NOT be ingested as normal telemetry samplesmeta.historian.mode SHOULD describe whether a value stream represents sample, state, or event semanticsobserved_at will usually fall back to ingestion timeenergy_total, import_energy_total, and export_energy_total SHOULD remain on the energy bus but SHOULD follow the separate contract in tdb_ingestion/counter_ingestion_api.md rather than being forced through the current measurement APIExample:
vad/energy/storage/battery-main/soc/valuemetric_name = socdevice_id = storage.battery-mainenergy topics