Files
2026-04-05 09:45:41 -04:00

2.1 KiB

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.pySensorBridge: 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.pySensorEvent 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.