68 lines
2.4 KiB
Python
68 lines
2.4 KiB
Python
import logging
|
|
import threading
|
|
from datetime import datetime
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class HaPoller:
|
|
"""Background daemon thread that periodically polls Home Assistant
|
|
for battery percentages and updates installed batteries in the DB.
|
|
|
|
Lifecycle:
|
|
poller = HaPoller(ha_client, session_factory, interval_seconds)
|
|
poller.start() # called once from create_app
|
|
poller.stop() # not normally needed; daemon thread exits with the process
|
|
"""
|
|
|
|
def __init__(self, ha_client, session_factory, interval: int):
|
|
self._client = ha_client
|
|
self._Session = session_factory
|
|
self._interval = interval
|
|
self._stop = threading.Event()
|
|
self._thread = threading.Thread(
|
|
target=self._run, name="ha-poller", daemon=True
|
|
)
|
|
|
|
def start(self):
|
|
self._thread.start()
|
|
logger.info("HA poller started (interval=%ds)", self._interval)
|
|
|
|
def stop(self):
|
|
self._stop.set()
|
|
|
|
def _run(self):
|
|
# Wait first so startup DB activity settles before the first poll
|
|
while not self._stop.wait(self._interval):
|
|
self._poll_once()
|
|
|
|
def _poll_once(self):
|
|
from models import Battery, BatteryPctLog, Device # local import avoids circular-import risk
|
|
|
|
session = self._Session()
|
|
try:
|
|
devices = (
|
|
session.query(Device)
|
|
.filter(Device.ha_entity_id.isnot(None))
|
|
.all()
|
|
)
|
|
for device in devices:
|
|
pct = self._client.get_state(device.ha_entity_id)
|
|
if pct is not None:
|
|
for battery in device.batteries:
|
|
if battery.status == "installed" and battery.battery_percentage != pct:
|
|
battery.battery_percentage = pct
|
|
session.add(BatteryPctLog(
|
|
battery_id=battery.id,
|
|
percentage=pct,
|
|
recorded_at=datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
|
|
source="poll",
|
|
))
|
|
session.commit()
|
|
logger.debug("HA poll complete (%d devices checked)", len(devices))
|
|
except Exception as exc:
|
|
session.rollback()
|
|
logger.warning("HA poll failed: %s", exc)
|
|
finally:
|
|
session.close()
|