diff --git a/docs/architecture/subsystems/sensors.md b/docs/architecture/subsystems/sensors.md new file mode 100644 index 0000000..d8a5ba7 --- /dev/null +++ b/docs/architecture/subsystems/sensors.md @@ -0,0 +1,38 @@ +# sensors + +## Purpose + +Ingests events from physical sensors (Zigbee door/window contacts, motion PIRs, leak sensors, GPIO-attached hardware) and republishes them onto the internal Vigilar bus in a normalized form. Maintains the current sensor state in SQLite so the web UI and rule engine always know whether a contact is open/closed, a leak is active, etc. + +## Key files + +- `vigilar/sensors/bridge.py` — `SensorBridge`: subscribes to `zigbee2mqtt/#`, normalizes payloads via `normalize_zigbee_payload`, republishes to `vigilar/sensor/{id}/{event_type}` +- `vigilar/sensors/gpio_handler.py` — direct GPIO input handling; publishes the same `vigilar/sensor/{id}/{event_type}` topics +- `vigilar/sensors/registry.py` — loads configured sensors, maps Zigbee friendly names to sensor IDs +- `vigilar/sensors/models.py` — `SensorEvent` dataclass and protocol enum +- `vigilar/sensors/__init__.py` + +## MQTT topics + +**Subscribes:** `{zigbee2mqtt.mqtt_topic_prefix}/#` (external Zigbee2MQTT broker, usually `zigbee2mqtt/#`) +**Publishes:** +- `vigilar/sensor/{id}/{event_type}` — normalized sensor events (contact_open, contact_closed, motion, leak, etc.) + +## Database tables + +- `sensors` — static sensor registry (read by `SensorRegistry`) +- `sensor_states` — current-state table, kept up to date via `upsert_sensor_state` + +## Depends on + +- External Zigbee2MQTT broker (same Mosquitto instance, `zigbee2mqtt/...` topic prefix configurable via `[zigbee2mqtt]` TOML section) +- `storage` — uses `vigilar.storage.queries.upsert_sensor_state` + +## Consumed by + +- `events` — classifies `vigilar/sensor/#` messages into `CONTACT_OPEN`, `CONTACT_CLOSED`, `MOTION_START`, etc. and persists them to the `events` table +- `web` — the `sensors` blueprint reads `sensors` / `sensor_states` for the dashboard + +## Notes + +`SensorBridge` deliberately skips `zigbee2mqtt/bridge/...` status messages and ignores unknown friendly names with a debug log. Both the Zigbee bridge and the GPIO handler produce identical `vigilar/sensor/{id}/{event_type}` topics so the rest of the system cannot tell a Zigbee door contact from a GPIO-wired one — that's intentional.