# 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.