This guide covers advanced configuration, security hardening, performance optimization, and enterprise deployment strategies for Zigbee2MQTT.
Security Hardening
Network Security
MQTT Security Configuration
# configuration.yaml - Secure MQTT setup
mqtt:
server: mqtts://mqtt.internal.domain:8883
ca: /opt/zigbee2mqtt/security/ca.crt
cert: /opt/zigbee2mqtt/security/client.crt
key: /opt/zigbee2mqtt/security/client.key
user: zigbee2mqtt_secure
password: !secret mqtt_password
client_id: zigbee2mqtt_production
reject_unauthorized: true
keepalive: 30
TLS Certificate Setup
#!/bin/bash
# create_certificates.sh - Generate TLS certificates
# Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=Zigbee2MQTT-CA"
# Create client certificate
openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr \
-subj "/C=US/ST=State/L=City/O=Organization/CN=zigbee2mqtt-client"
# Sign client certificate
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt -days 730
# Set permissions
chmod 600 *.key
chmod 644 *.crt
Access Control
User-Based Access Control
# configuration.yaml
advanced:
log_level: info
log_output: ['file']
log_file: zigbee2mqtt.log
# Disable web interface in production
frontend:
port: false
# Restrict API access
experimental:
new_api: true
# Limit device access
blocklist:
- "guest_network_*"
MQTT Topic Permissions
# mosquitto.conf - Topic-based access control
acl_file /etc/mosquitto/acl.conf
# acl.conf
user zigbee2mqtt
topic readwrite zigbee2mqtt/#
topic read homeassistant/status
user homeassistant
topic read zigbee2mqtt/#
topic write zigbee2mqtt/+/set
topic write zigbee2mqtt/bridge/request/#
user monitoring
topic read zigbee2mqtt/bridge/state
topic read zigbee2mqtt/bridge/info
topic read zigbee2mqtt/+/linkquality
Performance Optimization
Large Network Optimization
Coordinator Selection
# configuration.yaml - Optimized for large networks
serial:
port: /dev/ttyUSB0
adapter: zstack # CC2652P/CC1352P recommended for large networks
baudrate: 115200
rts_cts: false
advanced:
channel: 20 # Choose channel with minimal WiFi interference
pan_id: 0x1A62
ext_pan_id: [0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD]
network_key: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13]
# Performance optimizations
adapter_concurrent: 16
adapter_delay: 0
cache_state: true
cache_state_persistent: true
cache_state_send_on_startup: true
Reporting Optimization
# Device-specific optimizations
device_options:
# Battery devices - reduce reporting frequency
"battery_sensor_*":
reporting_config:
temperature:
min_interval: 900 # 15 minutes
max_interval: 3600 # 1 hour
change: 1.0 # 1°C change threshold
battery:
min_interval: 7200 # 2 hours
max_interval: 86400 # 24 hours
change: 5 # 5% change threshold
# Mains powered - faster reporting
"smart_plug_*":
reporting_config:
power:
min_interval: 5 # 5 seconds
max_interval: 300 # 5 minutes
change: 5 # 5W change threshold
System Resource Optimization
Memory Management
# configuration.yaml
advanced:
log_level: info # Reduce from debug to save memory
log_rotation: true
log_max_files: 5
# Availability optimization
availability_timeout: 0 # Disable if not needed
availability_blocklist:
- "battery_*" # Disable for battery devices
# Cache optimization
cache_state: true
cache_state_persistent: true
Database Optimization
#!/bin/bash
# optimize_database.sh - SQLite optimization
# Vacuum database
sqlite3 /opt/zigbee2mqtt/data/database.db "VACUUM;"
# Analyze for optimization
sqlite3 /opt/zigbee2mqtt/data/database.db "ANALYZE;"
# Set pragmas for performance
sqlite3 /opt/zigbee2mqtt/data/database.db "PRAGMA journal_mode=WAL;"
sqlite3 /opt/zigbee2mqtt/data/database.db "PRAGMA synchronous=NORMAL;"
sqlite3 /opt/zigbee2mqtt/data/database.db "PRAGMA cache_size=10000;"
High Availability Setup
Multi-Coordinator Configuration
Primary-Secondary Setup
# primary-coordinator.yaml
serial:
port: /dev/ttyUSB0
adapter: zstack
advanced:
network_key: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13]
pan_id: 0x1A62
channel: 20
mqtt:
base_topic: zigbee2mqtt/primary
# secondary-coordinator.yaml (backup)
serial:
port: /dev/ttyUSB1
adapter: zstack
advanced:
network_key: [1, 3, 5, 7, 9, 11, 13, 15, 0, 2, 4, 6, 8, 10, 12, 13]
pan_id: 0x1A63 # Different PAN ID
channel: 25 # Different channel
mqtt:
base_topic: zigbee2mqtt/secondary
Failover Script
#!/bin/bash
# failover.sh - Automatic failover management
PRIMARY_STATUS=$(mosquitto_sub -h localhost -t "zigbee2mqtt/primary/bridge/state" -C 1 -W 5)
SECONDARY_STATUS=$(mosquitto_sub -h localhost -t "zigbee2mqtt/secondary/bridge/state" -C 1 -W 5)
if [ "$PRIMARY_STATUS" != "online" ]; then
echo "Primary coordinator offline, activating secondary"
# Stop primary if running
sudo systemctl stop zigbee2mqtt-primary
# Start secondary
sudo systemctl start zigbee2mqtt-secondary
# Update Home Assistant configuration
mosquitto_pub -t "homeassistant/switch/coordinator_failover/config" \
-m '{"name": "Coordinator Active", "state_topic": "zigbee2mqtt/secondary/bridge/state"}'
# Send alert
curl -X POST "https://alerts.example.com/webhook" \
-d '{"message": "Zigbee coordinator failover activated"}'
fi
Load Balancing
Device Distribution
# coordinator-1.yaml (Lighting devices)
advanced:
channel: 11
pan_id: 0x1A61
device_options:
include_pattern: "light_*|dimmer_*|switch_*"
# coordinator-2.yaml (Sensors)
advanced:
channel: 20
pan_id: 0x1A62
device_options:
include_pattern: "sensor_*|motion_*|door_*"
# coordinator-3.yaml (Climate control)
advanced:
channel: 25
pan_id: 0x1A63
device_options:
include_pattern: "thermostat_*|hvac_*|climate_*"
Custom Device Support
External Converters
Custom Device Definition
// custom_devices.js
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const definition = {
zigbeeModel: ['CUSTOM_DEVICE_V1'],
model: 'CUSTOM_DEVICE_V1',
vendor: 'Custom Vendor',
description: 'Custom sensor device',
fromZigbee: [fz.temperature, fz.humidity, fz.battery],
toZigbee: [tz.factory_reset],
exposes: [
exposes.temperature(),
exposes.humidity(),
exposes.battery(),
exposes.numeric('custom_value', exposes.access.STATE)
],
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement']);
await reporting.temperature(endpoint);
},
};
module.exports = definition;
Converter Registration
# configuration.yaml
external_converters:
- custom_devices.js
# Enable experimental features
experimental:
new_api: true
Protocol Extensions
Custom Clusters
// custom_clusters.js
const {Zcl} = require('zigbee-herdsman');
// Define custom cluster
const customCluster = {
ID: 0xFC00,
attributes: {
customAttribute: {ID: 0x0000, type: Zcl.DataType.UINT16},
customConfig: {ID: 0x0001, type: Zcl.DataType.CHAR_STR},
},
commands: {
customCommand: {
ID: 0x00,
parameters: [
{name: 'param1', type: Zcl.DataType.UINT8},
{name: 'param2', type: Zcl.DataType.UINT16},
],
},
},
commandsResponse: {
customResponse: {
ID: 0x00,
parameters: [
{name: 'status', type: Zcl.DataType.UINT8},
],
},
},
};
module.exports = customCluster;
Enterprise Deployment
Container Orchestration
Kubernetes Deployment
# zigbee2mqtt-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: zigbee2mqtt
namespace: home-automation
spec:
replicas: 1
selector:
matchLabels:
app: zigbee2mqtt
template:
metadata:
labels:
app: zigbee2mqtt
spec:
securityContext:
fsGroup: 1000
containers:
- name: zigbee2mqtt
image: koenkk/zigbee2mqtt:1.35.0
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
env:
- name: TZ
value: "America/New_York"
volumeMounts:
- name: config
mountPath: /app/data
- name: usb-device
mountPath: /dev/ttyUSB0
securityContext:
privileged: true
volumes:
- name: config
persistentVolumeClaim:
claimName: zigbee2mqtt-config
- name: usb-device
hostPath:
path: /dev/ttyUSB0
nodeSelector:
zigbee-coordinator: "true"
Service and Ingress
# zigbee2mqtt-service.yaml
apiVersion: v1
kind: Service
metadata:
name: zigbee2mqtt-frontend
spec:
selector:
app: zigbee2mqtt
ports:
- port: 8080
targetPort: 8080
name: frontend
---
# zigbee2mqtt-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zigbee2mqtt-ingress
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: zigbee2mqtt-auth
spec:
rules:
- host: zigbee2mqtt.internal.domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: zigbee2mqtt-frontend
port:
number: 8080
Monitoring and Observability
Prometheus Metrics
# prometheus-config.yaml
scrape_configs:
- job_name: 'zigbee2mqtt'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/metrics'
scrape_interval: 30s
Custom Metrics Exporter
#!/usr/bin/env python3
# metrics_exporter.py
import json
import time
import paho.mqtt.client as mqtt
from prometheus_client import start_http_server, Gauge, Counter
# Prometheus metrics
device_count = Gauge('zigbee2mqtt_devices_total', 'Total number of devices')
message_rate = Counter('zigbee2mqtt_messages_total', 'Total MQTT messages', ['topic'])
coordinator_version = Gauge('zigbee2mqtt_coordinator_version', 'Coordinator version')
def on_message(client, userdata, msg):
topic = msg.topic
message_rate.labels(topic=topic).inc()
if topic == 'zigbee2mqtt/bridge/devices':
devices = json.loads(msg.payload)
device_count.set(len(devices))
elif topic == 'zigbee2mqtt/bridge/info':
info = json.loads(msg.payload)
coordinator_version.set(float(info['coordinator']['meta']['revision']))
if __name__ == '__main__':
client = mqtt.Client()
client.on_message = on_message
client.connect('localhost', 1883, 60)
client.subscribe('zigbee2mqtt/bridge/+')
start_http_server(9090)
client.loop_forever()
Grafana Dashboard
{
"dashboard": {
"title": "Zigbee2MQTT Advanced Monitoring",
"panels": [
{
"title": "Device Count",
"type": "stat",
"targets": [
{
"expr": "zigbee2mqtt_devices_total",
"legendFormat": "Devices"
}
]
},
{
"title": "Message Rate",
"type": "graph",
"targets": [
{
"expr": "rate(zigbee2mqtt_messages_total[5m])",
"legendFormat": "Messages/sec"
}
]
},
{
"title": "Network Health",
"type": "heatmap",
"targets": [
{
"expr": "zigbee2mqtt_device_lqi",
"legendFormat": "LQI"
}
]
}
]
}
}
Advanced Networking
Network Topology Optimization
Mesh Network Planning
#!/usr/bin/env python3
# network_analyzer.py
import json
import networkx as nx
import matplotlib.pyplot as plt
from mqtt_client import get_network_map
def analyze_network_topology():
"""Analyze Zigbee network topology for optimization opportunities"""
# Get network map from Zigbee2MQTT
network_data = get_network_map()
# Create network graph
G = nx.Graph()
for device in network_data['nodes']:
G.add_node(device['ieee_address'],
friendly_name=device.get('friendly_name', 'Unknown'),
type=device.get('type', 'Unknown'),
lqi=device.get('lqi', 0))
for link in network_data['links']:
G.add_edge(link['source'], link['target'],
lqi=link.get('lqi', 0),
distance=link.get('distance', 'Unknown'))
# Analyze topology
print("Network Analysis:")
print(f"Total devices: {G.number_of_nodes()}")
print(f"Total connections: {G.number_of_edges()}")
print(f"Network density: {nx.density(G):.2f}")
# Find weak links
weak_links = [(u, v, d) for u, v, d in G.edges(data=True) if d['lqi'] < 100]
print(f"Weak links (LQI < 100): {len(weak_links)}")
# Find isolated devices
isolated = [node for node in G.nodes() if G.degree(node) == 1]
print(f"Isolated devices: {len(isolated)}")
# Suggest improvements
suggest_improvements(G, weak_links, isolated)
def suggest_improvements(graph, weak_links, isolated):
"""Suggest network improvements"""
print("\nImprovement Suggestions:")
if weak_links:
print("- Consider adding routers near weak links:")
for source, target, data in weak_links:
print(f" Between {source} and {target} (LQI: {data['lqi']})")
if isolated:
print("- Consider relocating or adding routers for isolated devices:")
for device in isolated:
print(f" {device}")
# Calculate centrality to identify critical devices
centrality = nx.betweenness_centrality(graph)
critical_devices = sorted(centrality.items(), key=lambda x: x[1], reverse=True)[:5]
print("- Most critical devices (high centrality):")
for device, score in critical_devices:
print(f" {device}: {score:.2f}")
Channel Management
Interference Detection
#!/bin/bash
# channel_scanner.sh
echo "Scanning for wireless interference..."
# Scan 2.4GHz WiFi channels
echo "WiFi Channel Usage:"
iwlist scan | grep -E "(Frequency|ESSID)" | paste - - | \
awk '{print $2, $4}' | sort | uniq -c | sort -nr
# Zigbee channel recommendations
echo -e "\nZigbee Channel Recommendations:"
echo "Channel 11 (2405 MHz) - Usually best choice"
echo "Channel 15 (2425 MHz) - Alternative if 11 is congested"
echo "Channel 20 (2450 MHz) - Alternative if 15 is congested"
echo "Channel 25 (2475 MHz) - Last resort"
# Check current Zigbee channel
echo -e "\nCurrent Zigbee Configuration:"
mosquitto_sub -t "zigbee2mqtt/bridge/info" -C 1 | jq .coordinator.meta.channel
Backup and Disaster Recovery
Automated Backup Strategy
#!/bin/bash
# enterprise_backup.sh
BACKUP_DIR="/opt/backups/zigbee2mqtt"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# Create backup directory
mkdir -p "$BACKUP_DIR/$DATE"
# Backup configuration
cp /opt/zigbee2mqtt/data/configuration.yaml "$BACKUP_DIR/$DATE/"
# Backup coordinator
cp /opt/zigbee2mqtt/data/coordinator_backup.json "$BACKUP_DIR/$DATE/"
# Backup database
sqlite3 /opt/zigbee2mqtt/data/database.db ".backup '$BACKUP_DIR/$DATE/database.db'"
# Create archive
tar -czf "$BACKUP_DIR/zigbee2mqtt_backup_$DATE.tar.gz" -C "$BACKUP_DIR" "$DATE"
rm -rf "$BACKUP_DIR/$DATE"
# Upload to cloud storage
aws s3 cp "$BACKUP_DIR/zigbee2mqtt_backup_$DATE.tar.gz" s3://backups/zigbee2mqtt/
# Cleanup old backups
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: zigbee2mqtt_backup_$DATE.tar.gz"
Disaster Recovery Procedure
#!/bin/bash
# disaster_recovery.sh
BACKUP_FILE="$1"
RESTORE_DIR="/opt/zigbee2mqtt/data"
if [ -z "$BACKUP_FILE" ]; then
echo "Usage: $0 <backup_file.tar.gz>"
exit 1
fi
echo "Starting disaster recovery..."
# Stop service
sudo systemctl stop zigbee2mqtt
# Backup current state (just in case)
mv "$RESTORE_DIR" "${RESTORE_DIR}_pre_recovery_$(date +%Y%m%d_%H%M%S)"
# Create restore directory
mkdir -p "$RESTORE_DIR"
# Extract backup
tar -xzf "$BACKUP_FILE" -C /tmp/
cp -r /tmp/*/. "$RESTORE_DIR/"
# Fix permissions
chown -R zigbee2mqtt:zigbee2mqtt "$RESTORE_DIR"
chmod 644 "$RESTORE_DIR"/*.yaml
chmod 644 "$RESTORE_DIR"/*.json
chmod 644 "$RESTORE_DIR"/*.db
# Start service
sudo systemctl start zigbee2mqtt
# Verify recovery
sleep 10
if systemctl is-active --quiet zigbee2mqtt; then
echo "Disaster recovery completed successfully"
# Verify network state
timeout 30 mosquitto_sub -t "zigbee2mqtt/bridge/state" -C 1
else
echo "Recovery failed - service not running"
exit 1
fi
Best Practices Summary
Security
- Always use TLS for MQTT connections
- Implement proper access control
- Regular security audits
- Keep firmware updated
Performance
- Choose appropriate coordinator for network size
- Optimize reporting intervals
- Regular database maintenance
- Monitor resource usage
Reliability
- Implement backup strategies
- Plan for high availability
- Monitor network health
- Document procedures
Scalability
- Plan network topology
- Use multiple coordinators for large deployments
- Implement proper monitoring
- Regular capacity planning
Enterprise Note: These advanced configurations require careful planning and testing. Always implement changes in a staging environment first, and maintain comprehensive documentation for your specific deployment requirements.