The Problem
The Stack (Quick Recap)
Three Fixes, One Session
Fix 1: Device Key Refresh (Error 914)
[Smart Outlet Dishwasher] Key/version error (914)
[Smart Outlet Dishwasher] Key/version error (914)
[Smart Outlet Dishwasher] Key/version error (914)
... (25,000+ times)
The fix was straightforward — regenerate devices.json from the Tuya Cloud API:
Bash
cd /opt/tuyamon
sudo python3 -m tinytuya wizard
# Downloads fresh device keys from Cloud API
Fix 2: Exponential Backoff

Python
# Backoff constants
BACKOFF_INITIAL = 2 # Starting delay (seconds)
BACKOFF_MAX = 60 # Cap
BACKOFF_FACTOR = 2 # Multiplier per failure
BACKOFF_QUIET_AFTER = 10 # Reduce log noise after N attempts
# In the reconnection handler:
reconnect_count += 1
if reconnect_count <= BACKOFF_QUIET_AFTER or reconnect_count % 10 == 0:
logger.warning(f"[{name}] Reconnecting in {delay:.0f}s (attempt #{reconnect_count})")
shutdown_event.wait(reconnect_delay)
reconnect_delay = min(reconnect_delay * BACKOFF_FACTOR, BACKOFF_MAX)
- Progression: 2s → 4s → 8s → 16s → 32s → 60s (capped)
- Quiet mode: After 10 attempts at max backoff, only logs every 10th attempt
- Reset: Instantly resets to 2s on successful data reception
- Same formula twice: Applied to both the outer reconnect loop and initial status failures
Fix 3: DHCP Lease Table Lookup (The Big One)
- Close all 8 persistent connections
- Send UDP broadcast
- Wait for responses (10-30 seconds)
- Reconnect all 8 devices (20-30 seconds)


Python
EDGEROUTER_HOST = "192.168.1.1"
EDGEROUTER_USER = "angga"
EDGEROUTER_KEY = "/root/.ssh/id_rsa"
EDGEROUTER_SSH_OPTS = [
"-o", "ConnectTimeout=5",
"-o", "PubkeyAcceptedAlgorithms=+ssh-rsa", # Old EdgeOS compatibility
"-o", "HostKeyAlgorithms=+ssh-rsa",
"-o", "StrictHostKeyChecking=no",
"-o", "BatchMode=yes",
]
def resolve_ips_from_dhcp():
cmd = [
"ssh", *EDGEROUTER_SSH_OPTS,
"-i", EDGEROUTER_KEY,
f"{EDGEROUTER_USER}@{EDGEROUTER_HOST}",
"/opt/vyatta/bin/vyatta-op-cmd-wrapper show dhcp leases",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
# Parse: "192.168.1.75 4c:a9:19:44:62:6d 2026/04/15 ..."
dhcp_by_mac = {}
for line in result.stdout.splitlines():
parts = line.split()
if len(parts) >= 2 and parts[0].startswith("192.168."):
dhcp_by_mac[parts[1].replace(":", "").lower()] = parts[0]
# Match monitored devices by MAC
for dev in devices:
mac_norm = dev.get("mac", "").replace(":", "").replace("-", "").lower()
dhcp_ip = dhcp_by_mac.get(mac_norm)
if dhcp_ip and dev.get("ip") != dhcp_ip:
dev["ip"] = dhcp_ip
close_persistent_connection(dev) # Only reconnect if IP changed
logger.info(f"[{dev['name']}] DHCP resolved IP: {dev['ip']} -> {dhcp_ip}")
Python
def device_data_scan_thread():
while not shutdown_event.is_set():
shutdown_event.wait(DHCP_SCAN_INTERVAL) # 5 minutes
if shutdown_event.is_set():
break
if not resolve_ips_from_dhcp():
# Fallback: disruptive UDP scan
logger.warning("DHCP lookup failed. Falling back to UDP scan.")
for dev in devices:
close_persistent_connection(dev)
update_device_data()
Results
Metric | Before | After |
|---|---|---|
| IP Resolution | UDP broadcast (disruptive) | DHCP lease table (non-disruptive) |
| Data Blackout | 30-60s every 5 min | Zero |
| Connections Dropped | All 8, every scan | Only if IP changed (rare) |
| Error Logs (24h outage) | 43,200 lines | ~1,400 lines (97% reduction) |
| Stale Key Recovery | Manual discovery | tinytuya wizard + restart |
| Scan Duration | 10-30s (UDP timeout) | <1s (SSH + parse) |
Key Takeaways
This is Part 2 of my home IoT monitoring series. Part 1: From Polling to Push: Achieving Real-Time Tuya Power Monitoring. Both optimizations are part of my ongoing Solar Home System project.