WomoNET Protocol

Version 1

Das WomoNET-Netzwerk verwendet MQTT als primäres Protokoll für die Kommunikation zwischen verschiedenen Geräten. Diese Einrichtung ermöglicht effizienten und flexiblen Datenaustausch innerhalb des Netzwerks.

Struktur

Die MQTT-Topics im WomoNET-Netzwerk sind systematisch in die folgenden Hauptkategorien gegliedert:

c (config)

conf (Konfiguration)

Dieses Topic speichert Konfigurationseinstellungen, einschließlich Benutzeroberflächeneinstellungen, Geräteparametern und anderen wichtigen Konfigurationen. Das Hauptmerkmal dieses Topics ist, dass die Einstellungen persistent sind, was bedeutet, dass sie auch nach einem Systemneustart erhalten bleiben.

  • ui: Enthält UI-Layout von der WomoNET.app. Layouts werden als JSON für jedes verfügbare Layout geschrieben
  • driver: Kann verwendet werden, um Konfigurationen für Treiber zu speichern

dev (Virtuelle Geräte, Auto-Discovery)

Dieses Topic ist für Treiber reserviert, um ihre Auto-Discovery-Konfiguration zu veröffentlichen. Die Konfigurationsdaten für die Geräteerkennung werden hier definiert, wie unten detailliert beschrieben.

s (state/Zustand)

Jeder MQTT-Client innerhalb des WomoNET-Netzwerks hat ein dediziertes Zustands-Topic, wo er Nachrichten veröffentlicht, die seinen aktuellen Zustand oder Daten widerspiegeln. Alle Daten müssen menschenlesbare UTF-8-Daten sein. Numerische Werte müssen als UTF-8-String gesendet werden. Dezimaltrennzeichen ist . (Punkt). Wir parsen mit Dart’s double.tryParse.

Zustandsupdates und Befehle sollten QoS 1 verwenden.

Struktur

Der Zustandsbaum ist wie folgt strukturiert: s/<client_id>/<device_id>/<object_id>/[set/]<state/value/command>, wobei:

  • client_id ist die MQTT-Client-ID
  • device_id ist die Kennung des virtuellen Geräts
  • object_id ist die Objekteinheit eines Typ-Werts
  • set (optional) ist eine Konstante, die nur bereitgestellt wird, wenn dies ein Befehl ist
  • state/value/command ist der tatsächliche Zustand, Wert oder Befehl

Die Struktur kann abweichen. Verwenden Sie den Auto-Discovery-Mechanismus, um den tatsächlichen Pfad für den benötigten state/value/command zu finden.

Offene Fragen

  • TODO Fehlerbehandlung: Wir könnten s/error/<dev-id> für Fehlermeldungen einführen
  • TODO Geräte gehen Offline: Last Will Messages für Clients. Verfügbarkeit für Gruppen aktiv pushen? Ideen:
    • Behaltene Auto-Discovery-Nachrichten löschen
    • available_t für jeden Auto-Discovery-Typ

Auto-Discovery

Die Konfigurationsdaten müssen als MQTT-Nachrichten in einem spezifischen JSON-Format veröffentlicht werden. Jede Entität benötigt einen eindeutigen Topic-Namen und eine JSON-Konfiguration. Das Topic-Format ist c/dev/<client_id>/<device_id>/<type>/<entity>, wobei:

  • <client_id> ist die MQTT-Client-ID (global eindeutig)
  • <device_id> ist eine Kennung für das virtuelle Gerät (Treiber-Ebene). Diese ID muss für den Client eindeutig sein, um Kollisionen zu vermeiden
  • <type> ist der Typ der Entität. Siehe unten für verfügbare Typen
  • <entity> ist der Name der Entität. Er muss für alle Entitäten des gegebenen Typs dieses virtuellen Geräts eindeutig sein

Beim Veröffentlichen von Auto-Discovery-Konfigurationen muss das retain-Flag für die MQTT-Nachricht gesetzt werden.

Auto-Discovery ist anders organisiert als bei Home Assistant: Wir verwenden dev_id und dann type anstatt umgekehrt. Dies ermöglicht es uns, WidgetGroups in der App für jede dev_id zu verwenden.

Verfügbare Typen

toggle

Eine schaltbare Einheit, die ein- oder ausgeschaltet werden kann.

NameBeschreibung
state_tTopic mit dem aktuellen Zustand, nur true und false sind erlaubt
cmd_tBefehls-Topic zum Setzen des Toggle-Zustands. false, 0, off (alle groß-/kleinschreibungsunabhängig) werden als false interpretiert, alles andere als true. Wenn allow_timed true ist, wird das Setzen dieses Werts einen laufenden Timer abbrechen
allow_timedtrue oder false, gibt an, ob der Wert zeitgesteuert ausgelöst werden kann, indem ein CSV-String geschrieben wird, der den Zustand und die Dauer in Millisekunden repräsentiert (z.B. true,5000, Ausgang für 5000 Millisekunden einschalten). Wenn der zeitgesteuerte Zustand bereits der gewünschte Zustand ist (z.B. true,5000 wird gesendet, aber der Zustand ist bereits true), wird der Befehl ignoriert

actuator

Ein Aktuator, der in zwei Richtungen geschaltet werden kann, z.B. schieben/ziehen, vorwärts/rückwärts und hat auch einen neutralen Stopp-Zustand. Wichtig: Der Treiber muss sicherstellen, dass die Bewegung automatisch stoppt, wenn keine gültigen Nachrichten mehr empfangen werden.

NameDescription
state_tTopic holding the numeric value representing the actuator’s state. Can be 1 (push/forward), 0 (neutral/stop), or -1 (pull/reverse)
cmd_tCommand topic for setting the actuator’s state. Can be 1 (push/forward), 0 (neutral/stop), or -1 (pull/reverse). If allow_timed is true, setting this value will cancel any running timer
allow_timedOptional (defaults to false). true or false, representing whether the value can be triggered in a timed manner by writing a CSV string representing the state and the duration it should be held in milliseconds (e.g., -1,5000, setting the direction to pull on for 5000 milliseconds). If the timed state is already the requested state (e.g -1,5000 is sent, but the state is already -1), the command is ignored

binary

A boolean sensor with states on and off.

NameDescription
state_tTopic holding the current state, only true and false are allowed

sensor

A sensor publishing a value.

NameDescription
state_tTopic holding the value. The value is UTF-8 (e.g 42.1234 or heating)
unit_of_measurementOptional. Specifies the unit of the sensor’s value for display purposes. Examples include °C for temperature, % for humidity, m/s for speed, kWh for energy, etc. If not provided, the value is treated as unitless. Use standardized units (SI) whenever possible to ensure compatibility

mode

Selectable options for a dropdown.

NameDescription
state_tTopic holding the current mode. The value is a UTF-8 string representing the current selection (e.g. heat, cool, auto, etc.)
cmd_tTopic used to send commands to change the mode. The value should be a UTF-8 string corresponding to one of the selectable options (e.g. heat, cool, off, etc.). NOTE: for translations, we could define common english options and provide translations via a lookup table for them.
optionsList of available modes for the dropdown, provided as a JSON array of strings (e.g. ["off", "heat", "cool", "auto"]). User interfaces should respect the order of the options

slider

A controllable level value (slider in UI), which can be changed between a min and max value with a specified number of steps, e.g. for controlling heater/cooler temperatures, light dimmers, power consumption, charger output, …

NameDescription
state_tTopic holding the current value
cmd_tTopic used to send commands for setting the target value
min_valueThe minimum value for the slider
max_valueThe maximum value for the slider
step_sizeThe size of a step, e.g. 0.5

Example Structure

c/
├── conf/
│   ├── ui/
│   │   ├── 1 = "{ layout JSON }"
│   │   ├── main = "{ layout JSON }"
│   │   └── heater_only = "{ layout JSON }"
│   └── driver/
│       ├── core-gpio = "{ driver configuration JSON }"
│       └── core-adc = "{ driver configuration JSON }"
└── dev/
    ├── womonet-core-123.../
    │   ├── adc/
    │   │   └── sensor/
    │   │       ├── vin0 = "{'unit_of_measurement': 'V', 'state_t': 's/womonet-core-123.../adc/0/state'}"
    │   │       ├── vin1 = "{'unit_of_measurement': 'V', 'state_t': 's/womonet-core-123.../adc/1/state'}"
    │   │       └── ...
    │   ├── extrelay/
    │   │   └── toggle/
    │   │       ├── relay0 = "{'state_t': 's/womonet-core-123.../extrelay/0/state', 'cmd_t': 's/womonet-core-123.../extrelay/0/set/state', 'allow_timed': true}"
    │   │       ├── relay1 = "{'state_t': 's/womonet-core-123.../extrelay/1/state', 'cmd_t': 's/womonet-core-123.../extrelay/1/set/state', 'allow_timed': true}"
    │   │       └── ...
    │   ├── truma-d4e-651.../
    │   │   ├── mode/
    │   │   │   └── heat = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../heat/state', 'cmd_t': 's/womonet-core-123.../truma-d4e-651.../heat/set/state', 'options': '[\"off\", \"heating\", \"venting\"]'}"
    │   │   ├── sensor/
    │   │   │   ├── current_temp = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../current_temp/state'}"
    │   │   │   └── boiler_temp = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../boiler_temp/state'}"
    │   │   └── slider/
    │   │       └── target_temp = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../target_temp/state', 'cmd_t': 's/womonet-core-123.../truma-d4e-651.../target_temp/set/state', 'min_value': 16, 'max_value': 36, 'step_size': 0.5}"
    │   └── ...
    └── womonet-power-524.../
        ├── toggle/
        │   └── pump = "{'state_t': 's/womonet-power-524.../pump/state', 'cmd_t': 's/womonet-power-524.../pump/set/state'}"
        ├── actuator/
        │   ├── step = "{'state_t': 's/womonet-power-524.../step/state', 'cmd_t': 's/womonet-power-524.../step/set/state', 'allow_timed': true}"
        │   ├── awning = "{'state_t': 's/womonet-power-524.../awning/state', 'cmd_t': 's/womonet-power-524.../awning/set/state'}"
        │   ├── valve0 = "{'state_t': 's/womonet-power-524.../valve0/state', 'cmd_t': 's/womonet-power-524.../valve0/set/state', 'allow_timed': true}"
        │   └── valve1 = "{'state_t': 's/womonet-power-524.../valve1/state', 'cmd_t': 's/womonet-power-524.../valve1/set/state', 'allow_timed': true}"
        └── ...

s/
├── womonet-core-123.../
│   ├── adc/
│   │   ├── 0/
│   │   │   └── state = "1.33"
│   │   ├── 1/
│   │   │   └── state = "0.452"
│   │   └── ...
│   ├── extrelay/
│   │   ├── 0/
│   │   │   ├── state = "ON"
│   │   │   └── set/
│   │   │       └── state (writable only, no retain)
│   │   ├── 1/
│   │   │   ├── state = "OFF"
│   │   │   └── set/
│   │   │       └── state (writable only, no retain)
│   │   └── ...
│   ├── truma-d4e-651.../
│   │   ├── heat/
│   │   │   ├── state = "heating"
│   │   │   └── set/
│   │   │       └── state (writable only, no retain)
│   │   ├── current_temp/
│   │   │   └── state = "18.62"
│   │   └── target_temp/
│   │       ├── state = "22.0"
│   │       └── set/
│   │           └── state (writable only, no retain)
│   └── ...
└── womonet-power-524.../
    ├── pump/
    │   ├── state = "ON"
    │   └── set/
    │       └── state (writable only, no retain)
    ├── step/
    │   ├── state = "0"
    │   └── set/
    │       └── state (writable only, no retain)
    └── ...

Cloud Connectivity

For cloud connectivity, a service is syncing the desired topics (states/) between the local and a cloud broker. This is only done when a sub topic in sync_requested exists. Each client connecting to the cloud broker writes its name into the sync_requested topic and defines a Last Will Message to delete it.

When the last client deletes its sync topic, the broker in the cloud deletes all state topics, after a predefined timeout. (Maybe by not accepting the retain flag)

An active connection between the local and cloud broker is signaled by a flag synced (with a timestamp of the last message from the local broker.)

All states should be synced in a given timeframe to ensure consistency between local and cloud environments.