The Problem
The Stack
- 7 Tuya devices (smart plugs + 1 MCB circuit breaker) on the local LAN
- tinytuya (v1.17.6) — Python library for local Tuya device communication
- InfluxDB — time-series database for power metrics
- Grafana — dashboard with 1-second auto-refresh
- Mini PC running the tuyamon Python service as a systemd unit
Why Polling Was Broken

The Road to Real-Time

Attempt 1: UPDATEDPS → status()
Attempt 2: Reversed — status() → UPDATEDPS
Attempt 3: UPDATEDPS on a Separate Thread
Attempt 4: The Monitor Pattern ✅
Python
d = tinytuya.OutletDevice(DEVICE_ID, IP, KEY)
d.set_version(3.5)
d.set_socketPersistent(True)
# Send UPDATEDPS to trigger push stream
d.updatedps(nowait=True)
# Listen for push data
for i in range(20):
data = d.receive()
if data and "dps" in data:
power = int(data["dps"]["19"]) * 0.1
print(f"PUSH: {power}W")
PUSH: 190.1W
PUSH: 190.0W
PUSH: 189.3W
PUSH: 189.9W
PUSH: 190.5W
PUSH: 191.2W
The device was pushing real-time data on its own! Every 1-2 seconds, the MCB sent fresh DPS updates over the persistent TCP socket — no polling needed. I just had to listen.
This is exactly what the Tuya app does. It doesn't poll. It opens a persistent connection, sends occasional UPDATEDPS commands to keep the push stream alive, and captures whatever the device sends via receive().
The Final Architecture

Python
while not shutdown_event.is_set():
now = time.time()
if now >= status_time:
# Every 30s: full status() refresh as fallback
conn.updatedps(nowait=True)
data = conn.status()
elif now >= updatedps_time:
# Every 2s: trigger device to keep pushing
conn.updatedps(nowait=True)
data = conn.receive()
elif now >= heartbeat_time:
# Every 12s: keep TCP connection alive
data = conn.heartbeat(nowait=False)
else:
# Primary path: listen for push data
data = conn.receive()
if data and "dps" in data:
write_dps_to_influx(device, data["dps"], dt)
Results
Metric | Before | After |
|---|---|---|
| Data Freshness | ~60s lag vs Tuya app | ~1-2s (hardware limit) |
| Update Rate | 1/sec (but stale cache) | ~1-2/sec (real-time push) |
| Loop Overruns | Frequent (>1s iterations) | Zero (event-driven) |
| Connection Errors | Sporadic 905/914 storms | Zero in steady state |
| Tuya App Match | ❌ 20W+ gap | ✅ Exact match |
Key Takeaways
This optimization is part of my ongoing Solar Home System project, where I monitor and manage residential power consumption using a custom-built IoT stack running on an inexpensive Mini PC.