diff --git a/app.py b/app.py index c922fd3..9667ecf 100644 --- a/app.py +++ b/app.py @@ -153,6 +153,7 @@ async def stop_mqtt_monitor(): async def local_then_core(request: Request, call_next): internal_core_proxy_paths = { "/reslevis/updateAlarm", + "/reslevis/updateCoreSettings", } # only proxy CRUD for Reslevis (change prefix or methods if needed) if ( diff --git a/logica_reslevis/tracker_mode.py b/logica_reslevis/tracker_mode.py index 221e128..f94452f 100644 --- a/logica_reslevis/tracker_mode.py +++ b/logica_reslevis/tracker_mode.py @@ -7,6 +7,12 @@ import httpx log = logging.getLogger(__name__) +def _norm_mac(v: Any) -> str: + if v is None: + return "" + return "".join(ch for ch in str(v).strip().lower() if ch.isalnum()) + + def _none_if_empty(v: Any) -> Any: return None if v in ("", None, 0, "0") else v @@ -68,7 +74,7 @@ def _read_infer_positions(infer_csv_path: str) -> Dict[str, Dict[str, Optional[f with open(infer_csv_path, newline="") as f: reader = csv.DictReader(f, delimiter=";") for row in reader: - mac = (row.get("mac") or "").strip().lower() + mac = _norm_mac(row.get("mac")) if not mac: continue try: @@ -93,7 +99,7 @@ def _ai_mode_trackers( result = [] for tracker in trackers: t = dict(tracker) - mac = (t.get("mac") or "").strip().lower() + mac = _norm_mac(t.get("mac")) if mac and mac in positions: t["x"] = positions[mac]["x"] t["y"] = positions[mac]["y"] diff --git a/routes/reslevis.py b/routes/reslevis.py index bcbc8f2..638637e 100644 --- a/routes/reslevis.py +++ b/routes/reslevis.py @@ -24,6 +24,8 @@ from schemas.reslevis import ( TrackerZoneItem, SettingItem, GuiConfigItem, + CoreSettingsItem, + CoreSettingsUpdateItem, ) from logica_reslevis.gateway import GatewayJsonRepository @@ -39,6 +41,7 @@ from logica_reslevis.subject import SubjectJsonRepository from logica_reslevis.alarm import AlarmJsonRepository from logica_reslevis.track import TrackJsonRepository from logica_reslevis.tracker_zone import TrackerZoneJsonRepository +from logica_reslevis.tracker_mode import get_mode_aware_trackers from security import get_current_user @@ -46,6 +49,7 @@ from security import get_current_user CORE_BASE_URL = config_env.CORE_API_URL.rstrip("/") ALERTS_CORE_BASE_URL = "http://localhost:1902" TRACKS_CORE_BASE_URL = "http://localhost:1902" +SETTINGS_CORE_BASE_URL = "http://127.0.0.1:1902" CORE_TIMEOUT = 2.0 # secondi async def sync_core_get(request: Request) -> None: @@ -123,16 +127,6 @@ def _normalize_gateway(row: dict) -> dict: row["building"] = _none_if_empty(row.get("building")) return row -def _normalize_tracker(row: dict) -> dict: - row = dict(row) - row["floor"] = _none_if_empty(row.get("floor")) - row["building"] = _none_if_empty(row.get("building")) - row["battery"] = _str_or_none(row.get("battery")) - row["temperature"] = _str_or_none(row.get("temperature")) - row["acceleration"] = _str_or_none(row.get("acceleration")) - row["heartRate"] = _str_or_none(row.get("heartRate")) - return row - def _normalize_track(row: dict) -> dict: row = dict(row) row["ID"] = row.get("ID") @@ -164,7 +158,6 @@ def _normalize_zone(row: dict) -> dict: CORE_GET_SYNC = { "/reslevis/getGateways": (gateway_repo, _normalize_gateway), "/reslevis/getZones": (zone_repo, _normalize_zone), - "/reslevis/getTrackers": (tracker_repo, _normalize_tracker), } @@ -349,8 +342,13 @@ def removeZoneAreaDefinition(zone_area_definition_uuid: str): tags=["Reslevis"], dependencies=[Depends(get_current_user)], ) -def getTrackers(): - return tracker_repo.list() +async def getTrackers(): + return await get_mode_aware_trackers( + tracker_repo, + SETTINGS_CORE_BASE_URL, + config_env.BLE_AI_INFER_CSV, + CORE_TIMEOUT, + ) @router.post("/postTracker", tags=["Reslevis"], dependencies=[Depends(get_current_user)]) @@ -622,3 +620,53 @@ def updateGuiConfig(item: GuiConfigItem): def removeGuiConfig(gui_config_id: str): gui_config_repo.remove(gui_config_id) return {"message": "OK"} + + +@router.get( + "/getCoreSettings", + response_model=List[CoreSettingsItem], + tags=["Reslevis"], + dependencies=[Depends(get_current_user)], +) +async def getCoreSettings(): + async with httpx.AsyncClient(timeout=CORE_TIMEOUT) as client: + resp = await client.get(f"{SETTINGS_CORE_BASE_URL}/reslevis/settings") + + if resp.status_code >= 400: + detail = resp.text.strip() or "CORE settings request failed" + raise HTTPException(status_code=resp.status_code, detail=detail) + + try: + payload = resp.json() + except ValueError as exc: + raise HTTPException(status_code=502, detail="Invalid CORE response") from exc + + if not isinstance(payload, list): + raise HTTPException(status_code=502, detail="Unexpected CORE response type") + + return payload + + +@router.put( + "/updateCoreSettings", + tags=["Reslevis"], + dependencies=[Depends(get_current_user)], +) +async def updateCoreSettings(item: CoreSettingsUpdateItem): + async with httpx.AsyncClient(timeout=CORE_TIMEOUT) as client: + resp = await client.patch( + f"{SETTINGS_CORE_BASE_URL}/reslevis/settings", + json=item.model_dump(exclude_none=True), + ) + + if resp.status_code >= 400: + detail = resp.text.strip() or "CORE settings update failed" + raise HTTPException(status_code=resp.status_code, detail=detail) + + if not resp.content: + return {"message": "OK"} + + try: + return resp.json() + except ValueError: + return {"message": "OK"}