Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

119 linhas
3.7 KiB

  1. import csv
  2. import logging
  3. from typing import Any, Dict, List, Optional
  4. import httpx
  5. log = logging.getLogger(__name__)
  6. def _none_if_empty(v: Any) -> Any:
  7. return None if v in ("", None, 0, "0") else v
  8. def _str_or_none(v: Any) -> Optional[str]:
  9. if v in ("", None):
  10. return None
  11. if isinstance(v, (int, float, bool)):
  12. return str(v)
  13. return v
  14. def _normalize_tracker(row: dict) -> dict:
  15. row = dict(row)
  16. row["floor"] = _none_if_empty(row.get("floor"))
  17. row["building"] = _none_if_empty(row.get("building"))
  18. row["battery"] = _str_or_none(row.get("battery"))
  19. row["temperature"] = _str_or_none(row.get("temperature"))
  20. row["acceleration"] = _str_or_none(row.get("acceleration"))
  21. row["heartRate"] = _str_or_none(row.get("heartRate"))
  22. return row
  23. async def _fetch_algorithm(core_base_url: str, timeout: float) -> Optional[str]:
  24. try:
  25. async with httpx.AsyncClient(timeout=timeout) as client:
  26. resp = await client.get(f"{core_base_url}/reslevis/settings")
  27. if 200 <= resp.status_code < 300:
  28. payload = resp.json()
  29. if isinstance(payload, list) and payload:
  30. value = payload[0].get("current_algorithm")
  31. if value is not None:
  32. return str(value).lower()
  33. except (httpx.RequestError, ValueError):
  34. pass
  35. return None
  36. async def _filter_mode_trackers(
  37. tracker_repo, core_base_url: str, timeout: float
  38. ) -> List[Dict[str, Any]]:
  39. try:
  40. async with httpx.AsyncClient(timeout=timeout) as client:
  41. resp = await client.get(f"{core_base_url}/reslevis/getTrackers")
  42. if 200 <= resp.status_code < 300:
  43. data = resp.json()
  44. if isinstance(data, list):
  45. normalized = [_normalize_tracker(r) for r in data if isinstance(r, dict)]
  46. tracker_repo._write_all(normalized)
  47. return normalized
  48. except (httpx.RequestError, ValueError):
  49. pass
  50. return tracker_repo.list()
  51. def _read_infer_positions(infer_csv_path: str) -> Dict[str, Dict[str, Optional[float]]]:
  52. positions: Dict[str, Dict[str, Optional[float]]] = {}
  53. try:
  54. with open(infer_csv_path, newline="") as f:
  55. reader = csv.DictReader(f, delimiter=";")
  56. for row in reader:
  57. mac = (row.get("mac") or "").strip().lower()
  58. if not mac:
  59. continue
  60. try:
  61. positions[mac] = {
  62. "x": int(row["x"]) if row.get("x") not in (None, "") else None,
  63. "y": int(row["y"]) if row.get("y") not in (None, "") else None,
  64. }
  65. except (KeyError, ValueError):
  66. continue
  67. except OSError:
  68. log.warning("BLE-AI infer CSV not found: %s", infer_csv_path)
  69. return positions
  70. def _ai_mode_trackers(
  71. tracker_repo, infer_csv_path: str
  72. ) -> List[Dict[str, Any]]:
  73. trackers = tracker_repo.list()
  74. positions = _read_infer_positions(infer_csv_path)
  75. if not positions:
  76. return trackers
  77. result = []
  78. for tracker in trackers:
  79. t = dict(tracker)
  80. mac = (t.get("mac") or "").strip().lower()
  81. if mac and mac in positions:
  82. t["x"] = positions[mac]["x"]
  83. t["y"] = positions[mac]["y"]
  84. result.append(t)
  85. return result
  86. async def get_mode_aware_trackers(
  87. tracker_repo,
  88. core_base_url: str,
  89. infer_csv_path: str,
  90. timeout: float,
  91. ) -> List[Dict[str, Any]]:
  92. algorithm = await _fetch_algorithm(core_base_url, timeout)
  93. if algorithm == "filter":
  94. return await _filter_mode_trackers(tracker_repo, core_base_url, timeout)
  95. if algorithm == "ai":
  96. return _ai_mode_trackers(tracker_repo, infer_csv_path)
  97. return tracker_repo.list()