Files
battery-tracker-app/ha_poller.py
T

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()