Zigbee / Z-Wave IoT
Overview
Zigbee and Z-Wave are wireless mesh protocols used in smart home and building IoT deployments. KYRA MDR collects device event logs from IoT gateways (Zigbee2MQTT, Home Assistant, Hubitat, SmartThings) to detect unauthorized device pairing, anomalous command patterns, and firmware tampering across IoT networks.
Prerequisites
- KYRA MDR account (MDR tier or above)
- KYRA Collector installed and reachable from the IoT gateway host
- IoT gateway with logging capability:
- Zigbee2MQTT (recommended for Zigbee monitoring)
- Home Assistant with ZHA or Zigbee2MQTT integration
- Hubitat Elevation hub
- SmartThings hub
- MQTT broker (Mosquitto or similar) if using Zigbee2MQTT
Configuration
Option A: Zigbee2MQTT (Recommended)
Zigbee2MQTT provides the most detailed logging for Zigbee device monitoring.
Step 1: Configure Zigbee2MQTT Logging
Edit /opt/zigbee2mqtt/data/configuration.yaml:
# Zigbee2MQTT configurationadvanced: log_level: info # debug, info, warn, error log_output: - console - file log_directory: /opt/zigbee2mqtt/data/log log_rotation: true log_symlink_current: true # symlink to current log file
# Security settings network_key: GENERATE # auto-generate network encryption key pan_id: GENERATE # auto-generate PAN ID
# Enable device join notificationspermit_join: false # disable open pairing by default
# MQTT settingsmqtt: base_topic: zigbee2mqtt server: mqtt://localhost:1883Step 2: Subscribe to MQTT Bridge Events
The MQTT bridge publishes structured events to specific topics:
# Subscribe to all Zigbee2MQTT bridge eventsmosquitto_sub -h localhost -t 'zigbee2mqtt/bridge/#' -v
# Key topics for security monitoring:# zigbee2mqtt/bridge/event - device join, leave, interview# zigbee2mqtt/bridge/log - general bridge logs# zigbee2mqtt/bridge/state - bridge online/offline state# zigbee2mqtt/bridge/devices - full device list on startup
# Subscribe to device-specific eventsmosquitto_sub -h localhost -t 'zigbee2mqtt/+' -vExample bridge event payloads:
// Device joined (zigbee2mqtt/bridge/event){"type":"device_joined","data":{"friendly_name":"0x00158d000XXXXXXX","ieee_address":"0x00158d000XXXXXXX"}}
// Device left (zigbee2mqtt/bridge/event){"type":"device_leave","data":{"ieee_address":"0x00158d000XXXXXXX","friendly_name":"living_room_sensor"}}
// Device interview completed{"type":"device_interview","data":{"friendly_name":"new_device","status":"successful","ieee_address":"0x00158d000XXXXXXX"}}Step 3: Forward MQTT Events to KYRA Collector
Create a log forwarder that subscribes to MQTT and sends to syslog:
#!/bin/bashCOLLECTOR="<COLLECTOR_IP>"
mosquitto_sub -h localhost -t 'zigbee2mqtt/bridge/event' -t 'zigbee2mqtt/bridge/log' | while read -r line; do echo "$line" | logger -t zigbee2mqtt -n "$COLLECTOR" -P 514 --tcpdonesudo chmod +x /opt/kyra/zigbee-mqtt-forwarder.sh
# Create systemd servicesudo tee /etc/systemd/system/kyra-zigbee-forwarder.service << 'EOF'[Unit]Description=KYRA Zigbee MQTT Log ForwarderAfter=mosquitto.service zigbee2mqtt.service
[Service]ExecStart=/opt/kyra/zigbee-mqtt-forwarder.shRestart=alwaysRestartSec=10
[Install]WantedBy=multi-user.targetEOF
sudo systemctl enable --now kyra-zigbee-forwarderStep 4: Forward Zigbee2MQTT File Logs via rsyslog
module(load="imfile" PollingInterval="5")
input(type="imfile" File="/opt/zigbee2mqtt/data/log/current/log.txt" Tag="zigbee2mqtt" Facility="local6" Severity="info")
local6.* @@<COLLECTOR_IP>:514sudo systemctl restart rsyslogOption B: Home Assistant
Forward Home Assistant logs that include ZHA or Zigbee2MQTT events:
# Home Assistant configuration.yamllogger: default: warning logs: homeassistant.components.zha: info homeassistant.components.mqtt: info zigpy: infoForward Home Assistant logs via rsyslog:
module(load="imfile" PollingInterval="5")
input(type="imfile" File="/config/home-assistant.log" Tag="homeassistant" Facility="local6" Severity="info")
local6.* @@<COLLECTOR_IP>:514Option C: Hubitat Elevation
Hubitat provides event logs via its built-in API:
# Get recent device eventscurl -s "http://<HUBITAT_IP>/apps/api/<APP_ID>/devices/all?access_token=<TOKEN>" \ | jq '.[].name'
# Get events for a specific devicecurl -s "http://<HUBITAT_IP>/apps/api/<APP_ID>/devices/<DEVICE_ID>/events?access_token=<TOKEN>" \ | jq '.[] | {name, value, date, deviceId}'Create a periodic collection script:
#!/bin/bash# /opt/kyra/hubitat-collector.sh - run via cron every 5 minutesHUBITAT="http://<HUBITAT_IP>/apps/api/<APP_ID>"TOKEN="<ACCESS_TOKEN>"COLLECTOR="<COLLECTOR_IP>"
curl -s "$HUBITAT/devices/all/events?access_token=$TOKEN" \ | logger -t hubitat -n "$COLLECTOR" -P 514 --tcpVerify on KYRA Collector
kyra-collector statuskyra-collector logs --source zigbee --tail 10Collected Log Types
| Log Type | Description | Security Use |
|---|---|---|
| Device Join | New device pairing with IEEE address and model | Unauthorized device detection |
| Device Leave | Device removal or loss of connectivity | Device inventory tracking |
| Device Interview | Device capability discovery and endpoint enumeration | New device profiling |
| State Changes | Device state transitions (on/off, open/close, motion) | Anomalous behavior detection |
| Command Events | Commands sent to devices (set temperature, unlock door) | Unauthorized control detection |
| Bridge State | Gateway online/offline, coordinator status | Gateway health monitoring |
| Network Map | Zigbee mesh routing table and link quality | Network integrity |
Security-Critical IoT Events
| Event | Indicator | Description |
|---|---|---|
device_joined when permit_join: false | Unauthorized pairing | Device paired without explicit permission |
Unknown IEEE address in device_joined | Rogue device | Previously unseen device on the network |
device_leave for critical device | Tampering | Security sensor or lock removed from network |
| Rapid state changes on door lock | Lock manipulation | Potential brute force or replay attack on smart lock |
permit_join changed to true remotely | Network opened | Zigbee network opened for pairing without authorization |
| OTA update triggered for unknown firmware | Firmware tampering | Unauthorized firmware update pushed to devices |
Bridge state offline unexpectedly | Gateway attack | Zigbee coordinator taken offline |
Z-Wave Specific Monitoring
Z-Wave hubs typically provide less granular logging. Key approaches:
| Gateway | Log Source | Collection Method |
|---|---|---|
| Z-Wave JS | /var/log/zwave-js.log | rsyslog file monitoring |
| SmartThings | SmartThings API | REST API polling |
| Hubitat | Maker API | REST API polling |
| Home Assistant Z-Wave | home-assistant.log with Z-Wave JS integration | rsyslog file monitoring |
Troubleshooting
- No MQTT events: Verify Zigbee2MQTT is running and connected to the MQTT broker. Check
mosquitto_sub -t '#' -vto confirm MQTT is operational. - Missing device join events: Ensure
permit_joinwastruewhen the device was paired. Join events are only logged during active pairing. - High volume from state changes: Motion sensors and temperature sensors generate frequent state updates. Filter to log only security-relevant devices (locks, alarms, cameras) if volume is excessive.
- Zigbee2MQTT log file not found: Verify
log_outputincludesfileinconfiguration.yamland thelog_directorypath exists with write permissions. - Z-Wave limited logging: Z-Wave protocol logging is inherently less detailed than Zigbee. Focus on gateway-level events (device join/leave, commands) rather than protocol-level data.
- Network key exposure: The Zigbee network encryption key in
configuration.yamlmust be protected. Restrict file permissions:chmod 600 /opt/zigbee2mqtt/data/configuration.yaml.
Contact kyra@seekerslab.com for integration support.