50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
"""Low-frequency read-only observation emits transitions, never frame writes."""
|
|||
|
|
|
||
|
|
import json
|
||
|
|
|
||
|
|
from pigway_frame_flow.storage.database import encode
|
||
|
|
|
||
|
|
|
||
|
|
class DeviceObserver:
|
||
|
|
def __init__(self, service):
|
||
|
|
self.service = service
|
||
|
|
|
||
|
|
def tick(self):
|
||
|
|
for id, driver in self.service.registry.drivers.items():
|
||
|
|
try:
|
||
|
|
device = driver.device()
|
||
|
|
except Exception:
|
||
|
|
# Cloud query failure is not evidence that the physical device is offline.
|
||
|
|
continue
|
||
|
|
low = (
|
||
|
|
device.power.battery_percent is not None
|
||
|
|
and device.power.battery_percent <= 20
|
||
|
|
)
|
||
|
|
state = {"status": device.status, "low_battery": low}
|
||
|
|
key = "device-observation:" + id
|
||
|
|
row = self.service.db.one(
|
||
|
|
"SELECT payload FROM app_config WHERE key=?", (key,)
|
||
|
|
)
|
||
|
|
previous = json.loads(row["payload"]) if row else None
|
||
|
|
if previous == state:
|
||
|
|
continue
|
||
|
|
if previous:
|
||
|
|
if previous["status"] != state["status"] and state["status"] in (
|
||
|
|
"online",
|
||
|
|
"offline",
|
||
|
|
):
|
||
|
|
self.service.db.event(
|
||
|
|
"device." + state["status"], {"device_id": id}
|
||
|
|
)
|
||
|
|
if low and not previous["low_battery"]:
|
||
|
|
self.service.db.event(
|
||
|
|
"device.low_battery",
|
||
|
|
{
|
||
|
|
"device_id": id,
|
||
|
|
"battery_percent": device.power.battery_percent,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self.service.db.execute(
|
||
|
|
"INSERT OR REPLACE INTO app_config VALUES(?,?)", (key, encode(state))
|
||
|
|
)
|