Presence watcher: cost-aware pacing (Fleet API je placené)
- list poll 5→10 min; vehicle_data JEN při přechodu asleep→online nebo max 1×/15 min (data /usr/bin/zsh.002/req); wake nikdy (gate na online) - otevřená ev_session = auto u wallboxu → ŽÁDNÉ API cally (při AC nabíjení auto nespí — bez gatu by data tekla celou noc nabíjení) Odhad: </měsíc (online okna mimo wallbox jsou krátká). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -499,12 +499,19 @@ async def poll_loxone_sensors(site_id: int, db: asyncpg.Connection) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
#: presence poll pacing (sekundy) a geofence poloměr (m)
|
#: presence poll pacing (sekundy) a geofence poloměr (m).
|
||||||
EV_PRESENCE_POLL_S = 300
|
#: Fleet API je placené (vehicle_data $0.002/req, wake $0.02 — wake NIKDY):
|
||||||
|
#: list 10 min; vehicle_data jen při přechodu asleep→online a pak max 1×/15 min;
|
||||||
|
#: při otevřené ev_session se nepolluje vůbec (auto je u wallboxu = doma,
|
||||||
|
#: a při AC nabíjení nespí — bez gatu by data cally tekly celou noc).
|
||||||
|
EV_PRESENCE_POLL_S = 600
|
||||||
|
EV_PRESENCE_DATA_MIN_S = 900
|
||||||
EV_PRESENCE_HOME_RADIUS_M = 150
|
EV_PRESENCE_HOME_RADIUS_M = 150
|
||||||
#: anti-spam "píchni auto": min. rozestup notifikací per vozidlo (s)
|
#: anti-spam "píchni auto": min. rozestup notifikací per vozidlo (s)
|
||||||
EV_PLUG_NUDGE_COOLDOWN_S = 2 * 3600
|
EV_PLUG_NUDGE_COOLDOWN_S = 2 * 3600
|
||||||
_EV_PRESENCE_LAST_POLL: dict[int, float] = {}
|
_EV_PRESENCE_LAST_POLL: dict[int, float] = {}
|
||||||
|
_EV_PRESENCE_LAST_DATA: dict[int, float] = {}
|
||||||
|
_EV_PRESENCE_LAST_STATE: dict[int, str] = {}
|
||||||
_EV_PLUG_NUDGE_LAST: dict[int, float] = {}
|
_EV_PLUG_NUDGE_LAST: dict[int, float] = {}
|
||||||
|
|
||||||
|
|
||||||
@@ -542,6 +549,19 @@ async def poll_tesla_presence(site_id: int, db: asyncpg.Connection) -> None:
|
|||||||
if veh is None or veh["latitude"] is None:
|
if veh is None or veh["latitude"] is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# auto na wallboxu (otevřená session) = doma; žádné API cally (šetří $)
|
||||||
|
plugged = await db.fetchval(
|
||||||
|
"""
|
||||||
|
select exists(
|
||||||
|
select 1 from ems.ev_session es
|
||||||
|
where es.vehicle_id = $1 and es.session_end is null
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
int(veh["id"]),
|
||||||
|
)
|
||||||
|
if plugged:
|
||||||
|
return
|
||||||
|
|
||||||
from services.tesla_client import get_charge_state, get_vehicle_api_state, haversine_m
|
from services.tesla_client import get_charge_state, get_vehicle_api_state, haversine_m
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -552,11 +572,20 @@ async def poll_tesla_presence(site_id: int, db: asyncpg.Connection) -> None:
|
|||||||
if api_state is None:
|
if api_state is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
prev_state = _EV_PRESENCE_LAST_STATE.get(int(veh["id"]))
|
||||||
|
_EV_PRESENCE_LAST_STATE[int(veh["id"])] = api_state
|
||||||
|
woke_up = api_state == "online" and prev_state != "online"
|
||||||
|
data_due = (
|
||||||
|
loop_now - _EV_PRESENCE_LAST_DATA.get(int(veh["id"]), 0.0)
|
||||||
|
>= EV_PRESENCE_DATA_MIN_S
|
||||||
|
)
|
||||||
|
|
||||||
at_home = None
|
at_home = None
|
||||||
distance_m = None
|
distance_m = None
|
||||||
charging_state = None
|
charging_state = None
|
||||||
shift_state = None
|
shift_state = None
|
||||||
if api_state == "online":
|
if api_state == "online" and (woke_up or data_due):
|
||||||
|
_EV_PRESENCE_LAST_DATA[int(veh["id"])] = loop_now
|
||||||
try:
|
try:
|
||||||
st = await get_charge_state(db, veh["vin"])
|
st = await get_charge_state(db, veh["vin"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user