Self-Healing Local Key
When a KKT Kolbe device gets re-paired in the SmartLife app (factory reset, network change, app re-login), Tuya rotates the device's local_key. Until now the integration kept caching the old key and silently demoted the device to SmartLife cloud after three failed local connection attempts — until a manual reload triggered the existing sync.
This release makes that recovery automatic.
What changed
tuya_device.py:auto_detectnow raisesKKTAuthenticationError(not a genericKKTConnectionError) when Error 914 persists across all protocol versions 3.1–3.5, or when every key variant for an explicit version returns 914.hybrid_coordinator.py: catchesKKTAuthenticationErrorin the local update branch, calls_async_try_resync_local_key(), retries the local update once on success.- Resync flow:
smartlife_client.async_refresh_device(device_id)→ compare against stored key → write fresh key + private IP into config entry → re-keylocal_devicein place → force clean reconnect. - Throttle: max one resync per 10 minutes per coordinator (so flapping Wi-Fi doesn't hammer the SmartLife API).
async_update_localre-raisesKKTAuthenticationErrorbefore the generic wrap so the coordinator sees the original type.
- Resync flow:
How to spot it in the log
| Log line | Meaning |
|---|---|
Local auth failed for device ... (likely stale local_key) |
Self-heal entry point fired |
local_key resync: applying rotated key |
Cloud had a newer key |
Self-heal succeeded: local_key resynced from SmartLife |
Retry won, back to local |
SmartLife key matches stored key ... not a key-rotation issue |
Error 914 is something else (firmware, Wi-Fi, device reset) — investigate manually |
Tests
5 new regression tests in tests/test_hybrid_coordinator_key_resync.py. Full suite: 244 passed.
Affected models
All hood and cooktop models that use the SmartLife setup path (HERMES & STYLE, HERMES, FLAT, SOLO HCM, ECCO HCM, EASY/PLOOM, IND7705HC, IND8000, EB8313HC). Manual-setup devices are unaffected because they have no SmartLife client to fall back on.
🤖 Generated with Claude Code