fix(trigger): near() fired bei Auto-Vorbeifahrten verpasst — Loop schneller + event-getrieben
Stefan ist mehrmals an einem 300m-near()-Watcher (DRK Kreyenbrueck)
vorbeigefahren, kein Fire. Ursache: Background-Loop tickte alle 30s,
Auto-Durchfahrt durch 600m-Durchmesser-Radius dauert bei 50-120 km/h
nur 18-43 Sekunden — der Tick konnte komplett dazwischen liegen.
Drei Fixes (A + B aus Stefans Vorschlag):
A1. Background-Loop-Frequenz: TICK_SEC 30 → 8.
Garantiert mind. 2 Checks auch bei 120 km/h durch 300m. Loop ist
billig (paar Dateilesungen + AST-Eval), Brain merkt das nicht.
A2. near() bekommt Age-Schutz (watcher.py NEAR_MAX_AGE_SEC=300):
Wenn location_age_sec > 5 min, gilt die Position als unbekannt
und near() liefert False. Verhindert Phantom-Fires wenn Tracking
aus ist oder Mobilfunk weg war — vorher haette der letzte
bekannte Wert weiter ausgewertet werden koennen.
B. Event-getriebener Tick:
- background.py: tick_now()-Funktion + Module-Slot fuer
agent_factory damit man von ausserhalb des Lifespan-Pfads
einen Tick triggern kann
- main.py: POST /triggers/check-now Endpoint ruft tick_now()
- bridge: _persist_location feuert nach jedem Save ein fire-and-
forget POST /triggers/check-now (run_in_executor, timeout 8s,
blockt nichts wenn Brain stockt)
Damit fires near() sofort wenn die App ein location_update schickt —
Polling ist nur noch der Fallback fuer Watcher OHNE GPS-Bezug
(disk_free, hour_of_day etc.) und als Sicherheits-Tick falls
location_update mal ausfaellt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-1
@@ -91,6 +91,12 @@ def _cpu_load_1min() -> float:
|
||||
|
||||
_DAYS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
|
||||
|
||||
# Maximales GPS-Alter fuer near()-Auswertung. Wenn die App laenger nicht
|
||||
# gepushed hat (z.B. Tracking aus, Mobilfunk weg, App geschlossen), gilt
|
||||
# die Position als "unbekannt" und near() liefert False — verhindert
|
||||
# Phantom-Fires basierend auf einer wochen-alten Position.
|
||||
NEAR_MAX_AGE_SEC = 5 * 60
|
||||
|
||||
|
||||
def _gps_state() -> dict[str, Any]:
|
||||
"""Letzte bekannte Position aus /shared/state/location.json.
|
||||
@@ -177,11 +183,18 @@ def collect_variables() -> dict[str, Any]:
|
||||
# Funktion-Helper — wird vom Parser als ast.Call mit Name "near" erkannt.
|
||||
# Closure ueber die GPS-Werte, damit eval keine extra Variablen braucht.
|
||||
def _near(lat: float, lon: float, radius_m: float) -> bool:
|
||||
"""Haversine-Distanz: True wenn aktuelle Position < radius_m vom Punkt."""
|
||||
"""Haversine-Distanz: True wenn aktuelle Position < radius_m vom Punkt.
|
||||
Plus Age-Schutz: GPS-Daten aelter als NEAR_MAX_AGE_SEC werden als
|
||||
veraltet betrachtet → False. Sonst wuerde near() bei abgeschaltetem
|
||||
Tracking weiter die letzte bekannte Position nutzen und potentiell
|
||||
Phantom-Fires werfen wenn der User mal in der Naehe war."""
|
||||
cur_lat = vars_.get("current_lat")
|
||||
cur_lon = vars_.get("current_lon")
|
||||
if cur_lat is None or cur_lon is None:
|
||||
return False
|
||||
age = vars_.get("location_age_sec")
|
||||
if isinstance(age, (int, float)) and age >= 0 and age > NEAR_MAX_AGE_SEC:
|
||||
return False
|
||||
try:
|
||||
R = 6371000.0
|
||||
phi1 = math.radians(float(cur_lat))
|
||||
|
||||
Reference in New Issue
Block a user