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)
|
||||
EV_PRESENCE_POLL_S = 300
|
||||
#: presence poll pacing (sekundy) a geofence poloměr (m).
|
||||
#: 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
|
||||
#: anti-spam "píchni auto": min. rozestup notifikací per vozidlo (s)
|
||||
EV_PLUG_NUDGE_COOLDOWN_S = 2 * 3600
|
||||
_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] = {}
|
||||
|
||||
|
||||
@@ -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:
|
||||
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
|
||||
|
||||
try:
|
||||
@@ -552,11 +572,20 @@ async def poll_tesla_presence(site_id: int, db: asyncpg.Connection) -> None:
|
||||
if api_state is None:
|
||||
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
|
||||
distance_m = None
|
||||
charging_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:
|
||||
st = await get_charge_state(db, veh["vin"])
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user