-
Notifications
You must be signed in to change notification settings - Fork 366
Feature: per-device/per-model option to ignore leave events #1648
Description
Summary
Request for a per-device or per-model option to ignore device_leave events in zigbee-herdsman, preventing removeFromDatabase() from being called for configured devices.
Problem
Tuya TS0505B (Moes ZB-TDD6-RCW-4) ceiling spots send spurious leave events when power is restored via a mains relay (wall switch). This is a firmware quirk — the devices never actually leave the Zigbee network. They continue to be physically present and communicating.
When herdsman processes the leave event, it calls removeFromDatabase(), which:
- Removes the device from shepherd.db
- Removes the device from herdsman's in-memory device list
- All subsequent messages from the device are silently dropped (
controller.js:775:"Data is from unknown device, skipping...") - Commands to the device fail because herdsman doesn't know it anymore
The device is still on the Zigbee network. If we manually restore the device entry in shepherd.db and restart, the device is immediately controllable without re-pairing (first command takes ~11s for route discovery, then normal 50ms latency).
Use case
Smart ceiling spots (37 Tuya TS0505B) installed behind HomeMatic mains relays (wall switches). Toggling the wall switch turns all spots on/off — this is the normal, intended operation. Every power cycle risks triggering phantom leave events that permanently remove devices from the database.
This is a common installation scenario for smart bulbs. The Zigbee specification's leave mechanism is intended for devices voluntarily leaving the network, not for firmware bugs during power-on.
Proposed solution
A per-device or per-model callback/option that allows the consuming application (e.g., ioBroker.zigbee adapter) to tell herdsman to ignore leave events for specific devices.
Working implementation
We have a working patch in controller.js that has been running in production since 2026-02-22 with 37 devices and zero issues:
// In Controller class:
_shouldIgnoreLeave(device) {
try {
const fs = require('fs');
const path = require('path');
const overridesPath = path.join(this.options.databasePath, 'LocalOverrides.json');
if (!fs.existsSync(overridesPath)) return false;
const overrides = JSON.parse(fs.readFileSync(overridesPath, 'utf8'));
const ieeeShort = device.ieeeAddr.replace('0x', '');
// Check by device ID
const byId = overrides.by_id?.[ieeeShort];
if (byId?.disable_leave_delete || byId?.options?.disable_leave_delete) return true;
// Check by model
const modelId = device.modelID;
if (modelId) {
const byModel = overrides.by_model?.[modelId];
if (byModel?.disable_leave_delete || byModel?.options?.disable_leave_delete) return true;
}
return false;
} catch (e) {
return false;
}
}Applied in the onDeviceLeave handler (around line 541):
async onDeviceLeave(payload) {
const device = model_1.Device.byIeeeAddr(payload.ieeeAddr);
if (device && this._shouldIgnoreLeave(device)) {
logger_1.logger.info(`Ignoring leave event for ${device.ieeeAddr} (${device.modelID}) — ignore_leave is configured`);
return; // Skip removeFromDatabase()
}
// ... existing leave handling ...
}Cleaner API approach
Instead of reading config files directly, herdsman could expose a hook:
// Option 1: Callback
const controller = new Controller({
shouldIgnoreLeave: (device) => {
// Application decides per device
return configuredModels.includes(device.modelID);
}
});
// Option 2: Configuration list
const controller = new Controller({
ignoreLeaveModels: ['TS0505B'],
ignoreLeaveDevices: ['0xa4c138...']
});Evidence
- 37 Tuya TS0505B devices monitored for 5+ days
- 30+ leave events observed from normal wall switch operation (single relay toggles)
- Devices send
commandActiveStatusReport(LQI 91-156) seconds before the leave — proving they are healthy - After manual shepherd.db restore: immediately controllable, no re-pairing needed
- With our herdsman-level patch: zero device losses since Feb 22, all communication uninterrupted
- Full debug logs and test results documented in ioBroker/ioBroker.zigbee#2748
About security
The ioBroker.zigbee adapter maintainer (@asgothian) raised concerns about "breaking Zigbee network security." We believe this is not applicable here because:
- This is an opt-in option, not a default behavior change
- It targets hardwired ceiling fixtures that cannot be physically removed
- The leave events are not legitimate — the devices are not voluntarily leaving
- The option would be configured per device or per model, not globally
- A device that genuinely needs to leave (e.g., factory reset for re-pairing to a different network) would still work via the normal pairing process
Environment
- zigbee-herdsman 9.0.4
- Coordinator: ZStack3x0, Firmware 20250321 (CC2652P)
- 37x Tuya TS0505B (_TZ3210_b8jdosxo) / Moes ZB-TDD6-RCW-4
- All devices are Routers (mains-powered ceiling spots)