Browse Source

Gestione MQTT con memoria e rilevamento ultimato

master
root 1 month ago
parent
commit
b6d6a75c8d
100 changed files with 1151 additions and 173 deletions
  1. +2
    -5
      Dockerfile
  2. +36
    -45
      app/infer_mode.py
  3. +48
    -33
      app/train_executor.py
  4. +80
    -15
      app/web_inference.py
  5. +61
    -46
      app/web_suite.py
  6. +30
    -14
      app/web_test_inference.py
  7. +3
    -3
      config/config.yaml
  8. +0
    -0
      data/config/core.enabled
  9. +12
    -12
      data/infer/infer.csv
  10. BIN
      data/maps/floor_0.png
  11. BIN
      data/maps/floor_1.png
  12. +9
    -0
      data/maps/meta_0.json
  13. +9
    -0
      data/maps/meta_1.json
  14. +1
    -0
      data/model/model.joblib
  15. BIN
      data/model/model_camp_00_20260218_114109.joblib
  16. BIN
      data/model/model_camp_04_20260218_114229.joblib
  17. BIN
      data/model/model_camp_08_20260218_114319.joblib
  18. BIN
      data/model/model_camp_12_20260218_114340.joblib
  19. +370
    -0
      data/mqtt_raw/mqtt_raw_20260218_173135.log
  20. +90
    -0
      data/mqtt_raw/mqtt_raw_20260218_173234.log
  21. +5
    -0
      data/train/jobs/done/GBC-01_0_1096_1145.csv
  22. +5
    -0
      data/train/jobs/done/GBC-01_0_1229_709.csv
  23. +5
    -0
      data/train/jobs/done/GBC-01_0_1438_496.csv
  24. +5
    -0
      data/train/jobs/done/GBC-01_0_1438_981.csv
  25. +5
    -0
      data/train/jobs/done/GBC-01_0_1641_1401.csv
  26. +5
    -0
      data/train/jobs/done/GBC-01_0_1671_101.csv
  27. +5
    -0
      data/train/jobs/done/GBC-01_0_1675_918.csv
  28. +5
    -0
      data/train/jobs/done/GBC-01_0_2022_700.csv
  29. +5
    -0
      data/train/jobs/done/GBC-01_0_2041_477.csv
  30. +5
    -0
      data/train/jobs/done/GBC-01_0_2096_680.csv
  31. +5
    -0
      data/train/jobs/done/GBC-01_0_2102_676.csv
  32. +5
    -0
      data/train/jobs/done/GBC-01_0_2107_792.csv
  33. +5
    -0
      data/train/jobs/done/GBC-01_0_218_120.csv
  34. +5
    -0
      data/train/jobs/done/GBC-01_0_2244_735.csv
  35. +5
    -0
      data/train/jobs/done/GBC-01_0_2377_671.csv
  36. +5
    -0
      data/train/jobs/done/GBC-01_0_2503_523.csv
  37. +5
    -0
      data/train/jobs/done/GBC-01_0_2702_660.csv
  38. +5
    -0
      data/train/jobs/done/GBC-01_0_2816_375.csv
  39. +5
    -0
      data/train/jobs/done/GBC-01_0_2818_931.csv
  40. +5
    -0
      data/train/jobs/done/GBC-01_0_631_93.csv
  41. +5
    -0
      data/train/jobs/done/GBC-01_0_848_1113.csv
  42. +5
    -0
      data/train/jobs/done/GBC-01_0_849_102.csv
  43. +5
    -0
      data/train/jobs/done/GBC-01_0_849_1408.csv
  44. +5
    -0
      data/train/jobs/done/GBC-01_1_1050_1197.csv
  45. +5
    -0
      data/train/jobs/done/GBC-01_1_1129_114.csv
  46. +5
    -0
      data/train/jobs/done/GBC-01_1_1290_1423.csv
  47. +5
    -0
      data/train/jobs/done/GBC-01_1_1302_1344.csv
  48. +5
    -0
      data/train/jobs/done/GBC-01_1_1363_749.csv
  49. +5
    -0
      data/train/jobs/done/GBC-01_1_1467_373.csv
  50. +5
    -0
      data/train/jobs/done/GBC-01_1_1547_1421.csv
  51. +5
    -0
      data/train/jobs/done/GBC-01_1_2211_1431.csv
  52. +5
    -0
      data/train/jobs/done/GBC-01_1_2219_440.csv
  53. +5
    -0
      data/train/jobs/done/GBC-01_1_2248_980.csv
  54. +5
    -0
      data/train/jobs/done/GBC-01_1_2250_742.csv
  55. +5
    -0
      data/train/jobs/done/GBC-01_1_2628_1116.csv
  56. +5
    -0
      data/train/jobs/done/GBC-01_1_2629_652.csv
  57. +5
    -0
      data/train/jobs/done/GBC-01_1_2811_921.csv
  58. +5
    -0
      data/train/jobs/done/GBC-01_1_2880_519.csv
  59. +5
    -0
      data/train/jobs/done/GBC-01_1_852_1106.csv
  60. +5
    -0
      data/train/jobs/done/GBC-01_1_854_1111.csv
  61. +5
    -0
      data/train/jobs/done/GBC-01_1_855_745.csv
  62. +5
    -0
      data/train/jobs/done/GBC-01_1_988_802.csv
  63. +5
    -0
      data/train/jobs/done/GBC-02_0_1421_1424.csv
  64. +5
    -0
      data/train/jobs/done/GBC-02_0_1438_829.csv
  65. +5
    -0
      data/train/jobs/done/GBC-02_0_1493_797.csv
  66. +5
    -0
      data/train/jobs/done/GBC-02_0_1557_299.csv
  67. +5
    -0
      data/train/jobs/done/GBC-02_0_1673_498.csv
  68. +5
    -0
      data/train/jobs/done/GBC-02_0_1859_51.csv
  69. +5
    -0
      data/train/jobs/done/GBC-02_0_1861_1118.csv
  70. +5
    -0
      data/train/jobs/done/GBC-02_0_1958_250.csv
  71. +5
    -0
      data/train/jobs/done/GBC-02_0_2004_1404.csv
  72. +5
    -0
      data/train/jobs/done/GBC-02_0_2025_791.csv
  73. +5
    -0
      data/train/jobs/done/GBC-02_0_2106_789.csv
  74. +5
    -0
      data/train/jobs/done/GBC-02_0_2114_688.csv
  75. +5
    -0
      data/train/jobs/done/GBC-02_0_2192_100.csv
  76. +5
    -0
      data/train/jobs/done/GBC-02_0_2193_371.csv
  77. +5
    -0
      data/train/jobs/done/GBC-02_0_2230_927.csv
  78. +5
    -0
      data/train/jobs/done/GBC-02_0_2242_740.csv
  79. +5
    -0
      data/train/jobs/done/GBC-02_0_2373_789.csv
  80. +5
    -0
      data/train/jobs/done/GBC-02_0_2412_679.csv
  81. +5
    -0
      data/train/jobs/done/GBC-02_0_2414_796.csv
  82. +5
    -0
      data/train/jobs/done/GBC-02_0_2489_1157.csv
  83. +5
    -0
      data/train/jobs/done/GBC-02_0_2505_220.csv
  84. +5
    -0
      data/train/jobs/done/GBC-02_0_2812_1418.csv
  85. +5
    -0
      data/train/jobs/done/GBC-02_0_2894_522.csv
  86. +5
    -0
      data/train/jobs/done/GBC-02_0_2894_776.csv
  87. +5
    -0
      data/train/jobs/done/GBC-02_0_528_1457.csv
  88. +5
    -0
      data/train/jobs/done/GBC-02_0_848_842.csv
  89. +5
    -0
      data/train/jobs/done/GBC-02_0_852_707.csv
  90. +5
    -0
      data/train/jobs/done/GBC-02_0_993_456.csv
  91. +5
    -0
      data/train/jobs/done/GBC-02_1_1150_518.csv
  92. +5
    -0
      data/train/jobs/done/GBC-02_1_1150_743.csv
  93. +5
    -0
      data/train/jobs/done/GBC-02_1_1298_1107.csv
  94. +5
    -0
      data/train/jobs/done/GBC-02_1_1491_115.csv
  95. +5
    -0
      data/train/jobs/done/GBC-02_1_1735_1415.csv
  96. +5
    -0
      data/train/jobs/done/GBC-02_1_1979_582.csv
  97. +5
    -0
      data/train/jobs/done/GBC-02_1_2084_1179.csv
  98. +5
    -0
      data/train/jobs/done/GBC-02_1_2413_793.csv
  99. +5
    -0
      data/train/jobs/done/GBC-02_1_2415_672.csv
  100. +5
    -0
      data/train/jobs/done/GBC-02_1_2433_931.csv

+ 2
- 5
Dockerfile View File

@@ -21,10 +21,7 @@ COPY app/ /app/app/
COPY entrypoint.sh /app/entrypoint.sh COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh


# Setup utente e permessi
RUN useradd -m appuser && \
mkdir -p /home/appuser/data /home/appuser/models && \
chown -R appuser:appuser /home/appuser /app
# Setup permessi (manteniamo root per l'esecuzione dello script di boot e accesso a /tmp)
RUN mkdir -p /data/config /data/mqtt_raw /data/model


USER appuser
ENTRYPOINT ["/app/entrypoint.sh"] ENTRYPOINT ["/app/entrypoint.sh"]

+ 36
- 45
app/infer_mode.py View File

@@ -9,28 +9,26 @@ import yaml
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Tuple
from .logger_utils import log_msg as log from .logger_utils import log_msg as log


# Importiamo la funzione per caricare i gateway per mantenere l'ordine delle feature
from .csv_config import load_gateway_features_csv

BUILD_TAG = "infer-debug-v20-autoreload"
BUILD_TAG = "infer-mac-fix-v21"


# ------------------------- # -------------------------
# UTILITIES # UTILITIES
# ------------------------- # -------------------------


def _norm_mac(s: str) -> str: def _norm_mac(s: str) -> str:
s = (s or "").strip().replace("-", "").replace(":", "").replace(".", "").upper()
"""
Forza il formato standard xx:xx:xx:xx:xx:xx in MINUSCOLO per matchare il modello.
Esempio MQTT: 'AC233FC1DD4E' -> 'ac:23:3f:c1:dd:4e'
"""
s = (s or "").strip().replace("-", "").replace(":", "").replace(".", "").lower()
if len(s) != 12: return s if len(s) != 12: return s
return ":".join([s[i:i+2] for i in range(0, 12, 2)]) return ":".join([s[i:i+2] for i in range(0, 12, 2)])


def _predict_xyz(model_pkg: Dict[str, Any], X: np.ndarray) -> Tuple[int, float, float]: def _predict_xyz(model_pkg: Dict[str, Any], X: np.ndarray) -> Tuple[int, float, float]:
floor_clf = model_pkg.get("floor_clf") floor_clf = model_pkg.get("floor_clf")
if floor_clf is None:
raise ValueError("Il pacchetto modello non contiene 'floor_clf'")
z_pred = floor_clf.predict(X) z_pred = floor_clf.predict(X)
z = int(z_pred[0]) z = int(z_pred[0])
@@ -42,7 +40,6 @@ def _predict_xyz(model_pkg: Dict[str, Any], X: np.ndarray) -> Tuple[int, float,
xy_pred = regressor.predict(X) xy_pred = regressor.predict(X)
x, y = xy_pred[0] x, y = xy_pred[0]
return z, float(x), float(y) return z, float(x), float(y)


@dataclass @dataclass
@@ -56,6 +53,7 @@ class RollingRSSI:
self.data: Dict[str, Dict[str, List[_Point]]] = {} self.data: Dict[str, Dict[str, List[_Point]]] = {}


def add(self, bm: str, gm: str, rssi: float): def add(self, bm: str, gm: str, rssi: float):
# bm e gm arrivano già normalizzati da on_message
self.data.setdefault(bm, {}).setdefault(gm, []).append(_Point(time.time(), rssi)) self.data.setdefault(bm, {}).setdefault(gm, []).append(_Point(time.time(), rssi))


def prune(self): def prune(self):
@@ -71,6 +69,7 @@ class RollingRSSI:
feats = [] feats = []
found_count = 0 found_count = 0
for gm in gws: for gm in gws:
# gm è già minuscolo con : perché preso da gateways_ordered (dal modello)
vals = [p.v for p in per_gw.get(gm, [])] vals = [p.v for p in per_gw.get(gm, [])]
if vals: if vals:
val = np.median(vals) if agg == "median" else np.mean(vals) val = np.median(vals) if agg == "median" else np.mean(vals)
@@ -93,10 +92,9 @@ def run_infer(settings: Dict[str, Any]):
log(f"INFER_MODE build tag={BUILD_TAG}") log(f"INFER_MODE build tag={BUILD_TAG}")


# Variabili di stato per il caricamento dinamico
model_pkg = None model_pkg = None
last_model_mtime = 0 last_model_mtime = 0
gateways_ordered = []
gateways_ordered = [] # Saranno in formato aa:bb:cc...
gateways_set = set() gateways_set = set()
nan_fill = -110.0 nan_fill = -110.0


@@ -105,34 +103,24 @@ def run_infer(settings: Dict[str, Any]):
try: try:
current_mtime = os.path.getmtime(model_path) current_mtime = os.path.getmtime(model_path)
if current_mtime != last_model_mtime: if current_mtime != last_model_mtime:
log(f"🧠 Caricamento/Aggiornamento modello: {model_path}")
log(f"🧠 Aggiornamento modello: {model_path}")
model_pkg = joblib.load(model_path) model_pkg = joblib.load(model_path)
last_model_mtime = current_mtime last_model_mtime = current_mtime
# METADATI PER DEBUG
gateways_ordered = model_pkg.get("gateways_order", [])
# Il modello ha i gateway salvati come caricati nell'addestramento
gateways_ordered = [gw.lower() for gw in model_pkg.get("gateways_order", [])]
gateways_set = set(gateways_ordered) gateways_set = set(gateways_ordered)
nan_fill = float(model_pkg.get("nan_fill", -110.0)) nan_fill = float(model_pkg.get("nan_fill", -110.0))
floors = list(model_pkg.get("xy_by_floor", {}).keys())
log(f"✅ MODELLO PRONTO: {len(gateways_ordered)} GW allenati.")
log(f"🏢 Piani mappati: {floors}")
log(f"🧪 Valore Fill (NaN): {nan_fill}")
if len(gateways_ordered) > 0:
log(f"📡 Primi 3 GW di riferimento: {gateways_ordered[:3]}")
log(f"✅ MODELLO PRONTO: {len(gateways_ordered)} GW. Fill: {nan_fill}")
return True return True
except Exception as e:
if model_pkg is None:
log(f"⚠️ In attesa di un modello valido in {model_path}...")
return False
except: return False
return True return True


# Primo caricamento
load_model_dynamic() load_model_dynamic()

rolling = RollingRSSI(float(inf_c.get("window_seconds", 5.0))) rolling = RollingRSSI(float(inf_c.get("window_seconds", 5.0)))
# --- Gestione Token e Beacons ---
# Cache Beacons
token_cache = {"token": None, "expires_at": 0} token_cache = {"token": None, "expires_at": 0}
def get_token(): def get_token():
if time.time() < token_cache["expires_at"]: return token_cache["token"] if time.time() < token_cache["expires_at"]: return token_cache["token"]
@@ -159,18 +147,25 @@ def run_infer(settings: Dict[str, Any]):
try: try:
headers = {"Authorization": f"Bearer {token}", "accept": "application/json"} headers = {"Authorization": f"Bearer {token}", "accept": "application/json"}
resp = requests.get(api_c["get_beacons_url"], headers=headers, verify=False, timeout=10) resp = requests.get(api_c["get_beacons_url"], headers=headers, verify=False, timeout=10)
return [it["mac"] for it in resp.json() if "mac" in it] if resp.status_code == 200 else []
# Normalizziamo anche i beacon cercati per il confronto
return [_norm_mac(it["mac"]) for it in resp.json() if "mac" in it] if resp.status_code == 200 else []
except: return [] except: return []


def on_message(client, userdata, msg): def on_message(client, userdata, msg):
if not gateways_set: return
gw = _norm_mac(msg.topic.split("/")[-1])
if gw not in gateways_set: return
# msg.topic es: publish_out/ac233fc1dd4e
raw_gw = msg.topic.split("/")[-1]
gw_norm = _norm_mac(raw_gw)
if gw_norm not in gateways_set: return
try: try:
items = json.loads(msg.payload.decode()) items = json.loads(msg.payload.decode())
for it in items: for it in items:
bm, rssi = _norm_mac(it.get("mac")), it.get("rssi")
if bm and rssi is not None: rolling.add(bm, gw, float(rssi))
raw_bm = it.get("mac")
rssi = it.get("rssi")
if raw_bm and rssi is not None:
bm_norm = _norm_mac(raw_bm)
rolling.add(bm_norm, gw_norm, float(rssi))
except: pass except: pass


mqtt_client = mqtt.Client() mqtt_client = mqtt.Client()
@@ -180,28 +175,25 @@ def run_infer(settings: Dict[str, Any]):
mqtt_client.subscribe(mqtt_c["topic"]) mqtt_client.subscribe(mqtt_c["topic"])
mqtt_client.loop_start() mqtt_client.loop_start()
except Exception as e: except Exception as e:
log(f"MQTT Connect Error: {e}")
log(f"MQTT Error: {e}")


last_predict, last_api_refresh = 0.0, 0.0 last_predict, last_api_refresh = 0.0, 0.0
beacons = []
beacons_to_track = []


while True: while True:
now = time.time() now = time.time()
rolling.prune() rolling.prune()
# Verifica se il link simbolico model.joblib è cambiato
load_model_dynamic() load_model_dynamic()


if now - last_api_refresh >= float(api_c.get("refresh_seconds", 30)): if now - last_api_refresh >= float(api_c.get("refresh_seconds", 30)):
beacons = fetch_beacons()
beacons_to_track = fetch_beacons()
last_api_refresh = now last_api_refresh = now


if now - last_predict >= float(inf_c.get("refresh_seconds", 10.0)): if now - last_predict >= float(inf_c.get("refresh_seconds", 10.0)):
rows, count_ok = [], 0 rows, count_ok = [], 0
if model_pkg:
for bm in beacons:
bm_n = _norm_mac(bm)
if model_pkg and beacons_to_track:
for bm_n in beacons_to_track:
X, n_found = rolling.aggregate_features(bm_n, gateways_ordered, inf_c.get("aggregate", "median"), nan_fill) X, n_found = rolling.aggregate_features(bm_n, gateways_ordered, inf_c.get("aggregate", "median"), nan_fill)
z, x, y = -1, -1.0, -1.0 z, x, y = -1, -1.0, -1.0
@@ -209,8 +201,7 @@ def run_infer(settings: Dict[str, Any]):
try: try:
z, x, y = _predict_xyz(model_pkg, X) z, x, y = _predict_xyz(model_pkg, X)
if z != -1: count_ok += 1 if z != -1: count_ok += 1
except Exception as e:
pass
except: pass
rows.append(f"{bm_n};{int(z)};{int(round(x))};{int(round(y))}") rows.append(f"{bm_n};{int(z)};{int(round(x))};{int(round(y))}")


@@ -221,7 +212,7 @@ def run_infer(settings: Dict[str, Any]):
f.write("mac;z;x;y\n") f.write("mac;z;x;y\n")
for r in rows: f.write(r + "\n") for r in rows: f.write(r + "\n")
os.replace(str(out_p) + ".tmp", out_p) os.replace(str(out_p) + ".tmp", out_p)
log(f"CYCLE: {count_ok}/{len(rows)} localized")
log(f"CYCLE: {count_ok}/{len(beacons_to_track)} localized (Input GW match: {len(gateways_set)})")
except Exception as e: log(f"File Error: {e}") except Exception as e: log(f"File Error: {e}")
last_predict = now last_predict = now


+ 48
- 33
app/train_executor.py View File

@@ -33,80 +33,95 @@ def process_train_jobs():
nan_fill = job["nan_fill"] nan_fill = job["nan_fill"]
gw_csv = job["gateways_csv"] gw_csv = job["gateways_csv"]
# --- GENERAZIONE NOME FILE CON TIMESTAMP (BACKUP) ---
# --- GENERAZIONE NOME FILE CON TIMESTAMP ---
now_str = datetime.now().strftime("%Y%m%d_%H%M%S") now_str = datetime.now().strftime("%Y%m%d_%H%M%S")
model_filename = f"model_camp_{campagna}_{now_str}.joblib" model_filename = f"model_camp_{campagna}_{now_str}.joblib"
model_path = Path("/data/model") / model_filename model_path = Path("/data/model") / model_filename
# Caricamento Gateway
# Caricamento Gateway con normalizzazione MAC
gws = load_gateway_features_csv(gw_csv) gws = load_gateway_features_csv(gw_csv)
gateways_order = [g.mac for g in gws]
gateways_order = [g.mac.lower().strip() for g in gws]
log(f"[TRAIN-CORE] Feature vector: {len(gateways_order)} gateway caricati da {gw_csv}")


# Analisi file campioni # Analisi file campioni
samples_dir = Path("/data/train/samples") samples_dir = Path("/data/train/samples")
sample_files = list(samples_dir.glob(f"{campagna}_*.csv")) sample_files = list(samples_dir.glob(f"{campagna}_*.csv"))
log(f"[TRAIN-CORE] Analisi di {len(sample_files)} file per campagna '{campagna}'")
X_list, y_z, y_xy = [], [], [] X_list, y_z, y_xy = [], [], []
for fp in sample_files: for fp in sample_files:
try: try:
df = pd.read_csv(fp, sep=";") df = pd.read_csv(fp, sep=";")
if df.empty: continue if df.empty: continue
# Normalizziamo le colonne del DF in minuscolo
df.columns = [c.lower().strip() for c in df.columns]
row = df.iloc[0] row = df.iloc[0]
# Mapping RSSI basato su gateway.csv (risolve errore 'mac')
X_list.append([float(row.get(gw, nan_fill)) for gw in gateways_order])
features = []
for gw in gateways_order:
val = row.get(gw)
# Gestione esplicita di 'nan' stringa o NaN numerico
if val is not None and str(val).lower() != 'nan' and not pd.isna(val):
features.append(float(val))
else:
features.append(float(nan_fill))
X_list.append(features)
y_z.append(int(round(float(row.get("z"))))) y_z.append(int(round(float(row.get("z")))))
y_xy.append([float(row.get("x")), float(row.get("y"))]) y_xy.append([float(row.get("x")), float(row.get("y"))])
except: continue
except Exception as e:
log(f"[TRAIN-CORE] Errore nel file {fp.name}: {e}")
continue


if not X_list: if not X_list:
log(f"[TRAIN-CORE] ERRORE: Dati non validi per campagna {campagna}")
log(f"[TRAIN-CORE] ❌ ABORTO: Nessun dato matchato tra gateway.csv e fingerprint!")
job_path.unlink() job_path.unlink()
continue continue


X, Y_z, Y_xy = np.array(X_list), np.array(y_z), np.array(y_xy)
X = np.array(X_list)
# Calcolo copertura reale
matches_per_point = [np.sum(np.array(vec) > nan_fill) for vec in X_list]
avg_match = np.mean(matches_per_point)
log(f"[TRAIN-CORE] Dataset pronto. Punti: {len(X_list)}. Media match Gateway: {avg_match:.2f}/{len(gateways_order)}")


# Fitting KNN
log(f"[TRAIN-CORE] Fitting modello per {model_filename}...")
# --- LOG PARAMETRI ADDESTRAMENTO ---
k_val = int(knn_cfg.get('k', 5))
w_val = knn_cfg.get('weights', 'distance')
m_val = knn_cfg.get('metric', 'euclidean')
log(f"[TRAIN-CORE] Fitting KNN -> k: {k_val}, weights: {w_val}, metric: {m_val}, nan_fill: {nan_fill}")

# Fitting
floor_clf = KNeighborsClassifier( floor_clf = KNeighborsClassifier(
n_neighbors=int(knn_cfg.get('k', 5)),
weights=knn_cfg.get('weights', 'distance'),
metric=knn_cfg.get('metric', 'euclidean')
).fit(X, Y_z)
n_neighbors=k_val, weights=w_val, metric=m_val
).fit(X, np.array(y_z))
models_xy = {} models_xy = {}
for z in np.unique(Y_z):
idx = np.where(Y_z == z)[0]
for z in np.unique(y_z):
idx = np.where(np.array(y_z) == z)[0]
# k_xy non può essere superiore al numero di campioni per piano
current_k_xy = min(k_val, len(idx))
models_xy[int(z)] = KNeighborsRegressor( models_xy[int(z)] = KNeighborsRegressor(
n_neighbors=min(int(knn_cfg.get('k', 5)), len(idx)),
weights=knn_cfg.get('weights', 'distance'),
metric=knn_cfg.get('metric', 'euclidean')
).fit(X[idx], Y_xy[idx])
n_neighbors=current_k_xy, weights=w_val, metric=m_val
).fit(X[idx], np.array(y_xy)[idx])


# Salvataggio Pacchetto
# Salvataggio
model_pkg = { model_pkg = {
"floor_clf": floor_clf,
"xy_by_floor": models_xy,
"gateways_order": gateways_order,
"nan_fill": nan_fill,
"created_at": datetime.now().isoformat(),
"campaign": campagna,
"filename": model_filename
"floor_clf": floor_clf, "xy_by_floor": models_xy,
"gateways_order": gateways_order, "nan_fill": nan_fill,
"knn_params": {"k": k_val, "weights": w_val, "metric": m_val},
"created_at": datetime.now().isoformat(), "campaign": campagna
} }
Path("/data/model").mkdir(parents=True, exist_ok=True) Path("/data/model").mkdir(parents=True, exist_ok=True)
joblib.dump(model_pkg, model_path) joblib.dump(model_pkg, model_path)
log(f"[TRAIN-CORE] ✅ Addestramento COMPLETATO: {model_filename}") log(f"[TRAIN-CORE] ✅ Addestramento COMPLETATO: {model_filename}")


except Exception as e: except Exception as e:
log(f"[TRAIN-CORE] ❌ ERRORE CRITICO: {str(e)}") log(f"[TRAIN-CORE] ❌ ERRORE CRITICO: {str(e)}")
finally: finally:
if job_path.exists():
job_path.unlink()
if job_path.exists(): job_path.unlink()


def run_train_monitor(): def run_train_monitor():
"""Loop di monitoraggio per il Core Orchestrator."""
while True: while True:
process_train_jobs() process_train_jobs()
time.sleep(5) time.sleep(5)

+ 80
- 15
app/web_inference.py View File

@@ -3,6 +3,8 @@ import pandas as pd
import os import os
import json import json
import folium import folium
import requests
import yaml
from streamlit_folium import st_folium from streamlit_folium import st_folium
from pathlib import Path from pathlib import Path
from PIL import Image from PIL import Image
@@ -19,6 +21,48 @@ def get_image_base64(img_path):
img_str = base64.b64encode(buffered.getvalue()).decode("ascii") img_str = base64.b64encode(buffered.getvalue()).decode("ascii")
return f"data:image/png;base64,{img_str}", w, h return f"data:image/png;base64,{img_str}", w, h


def _norm_mac_internal(s: str) -> str:
"""Standardizza il MAC in formato xx:xx:xx:xx:xx:xx minuscolo per il matching."""
s = (s or "").strip().replace("-", "").replace(":", "").replace(".", "").lower()
if len(s) != 12: return s
return ":".join([s[i:i+2] for i in range(0, 12, 2)])

def fetch_beacons_metadata(cfg):
"""Recupera l'elenco dei beacon dalle API e normalizza i MAC per il lookup."""
api_c = cfg.get("api", {})
token_url = api_c.get("token_url")
beacons_url = api_c.get("get_beacons_url")
try:
secrets_path = os.environ.get("SECRETS_FILE") or "/config/secrets.yaml"
with open(secrets_path, "r") as f:
sec = yaml.safe_load(f).get("oidc", {})
# 1. Autenticazione OIDC
payload = {
"grant_type": "password",
"client_id": api_c.get("client_id", "Fastapi"),
"client_secret": sec.get("client_secret", ""),
"username": sec.get("username", "core"),
"password": sec.get("password", "")
}
resp_t = requests.post(token_url, data=payload, verify=False, timeout=5)
if resp_t.status_code != 200: return {}
token = resp_t.json().get("access_token")

# 2. Download Beacon List e Normalizzazione
headers = {"Authorization": f"Bearer {token}", "accept": "application/json"}
resp_b = requests.get(beacons_url, headers=headers, verify=False, timeout=5)
if resp_b.status_code == 200:
# Dizionario {mac_normalizzato: nome_amichevole}
return {
_norm_mac_internal(it["mac"]): it.get("name", "N/A")
for it in resp_b.json() if "mac" in it
}
except Exception as e:
st.error(f"Errore recupero nomi beacon: {e}")
return {}

def show_inference_page(cfg): def show_inference_page(cfg):
st.subheader("📡 Monitoraggio Beacon Real-Time") st.subheader("📡 Monitoraggio Beacon Real-Time")
@@ -26,7 +70,7 @@ def show_inference_page(cfg):
MAPS_DIR = Path(cfg['maps']['map_dir']) MAPS_DIR = Path(cfg['maps']['map_dir'])
INFER_FILE = Path("/data/infer/infer.csv") INFER_FILE = Path("/data/infer/infer.csv")
# --- 1. SELEZIONE E STATO (RIGA COMPATTA) ---
# --- 1. SELEZIONE E STATO ---
maps = sorted([f.replace(cfg['maps']['floor_prefix'], "").split('.')[0] maps = sorted([f.replace(cfg['maps']['floor_prefix'], "").split('.')[0]
for f in os.listdir(MAPS_DIR) if f.startswith(cfg['maps']['floor_prefix'])]) for f in os.listdir(MAPS_DIR) if f.startswith(cfg['maps']['floor_prefix'])])
@@ -34,30 +78,24 @@ def show_inference_page(cfg):
st.warning("Nessuna mappa configurata.") st.warning("Nessuna mappa configurata.")
return return


# Lettura dati per conteggio
df_infer = pd.DataFrame() df_infer = pd.DataFrame()
if INFER_FILE.exists(): if INFER_FILE.exists():
df_infer = pd.read_csv(INFER_FILE, sep=";") df_infer = pd.read_csv(INFER_FILE, sep=";")


# Layout riga 1
c_piano, c_count, c_size = st.columns([3, 2, 2]) c_piano, c_count, c_size = st.columns([3, 2, 2])
with c_piano: with c_piano:
sub1, sub2 = st.columns([1, 1.2]) sub1, sub2 = st.columns([1, 1.2])
sub1.markdown("<p style='padding-top:35px; font-weight:bold; font-size:15px;'>Piano Visualizzato:</p>", unsafe_allow_html=True) sub1.markdown("<p style='padding-top:35px; font-weight:bold; font-size:15px;'>Piano Visualizzato:</p>", unsafe_allow_html=True)
floor_id = sub2.selectbox("", maps, key="inf_floor_v24", label_visibility="collapsed") floor_id = sub2.selectbox("", maps, key="inf_floor_v24", label_visibility="collapsed")
# Filtro dati per il piano scelto
df_active = df_infer[(df_infer['z'].astype(str) == str(floor_id)) & (df_infer['x'] != -1)] if not df_infer.empty else pd.DataFrame() df_active = df_infer[(df_infer['z'].astype(str) == str(floor_id)) & (df_infer['x'] != -1)] if not df_infer.empty else pd.DataFrame()


with c_count: with c_count:
st.info(f"📡 Beacon Attivi: **{len(df_active)}**\n(Totali nel file: {len(df_infer)})") st.info(f"📡 Beacon Attivi: **{len(df_active)}**\n(Totali nel file: {len(df_infer)})")


with c_size: with c_size:
# Slider per dimensione pallini (come nel mapper)
m_size = st.slider("Dimensione Beacon:", 5, 20, 8, key="inf_msize_v24") m_size = st.slider("Dimensione Beacon:", 5, 20, 8, key="inf_msize_v24")


# Caricamento Metadati
meta_path = MAPS_DIR / f"{cfg['maps']['meta_prefix']}{floor_id}.json" meta_path = MAPS_DIR / f"{cfg['maps']['meta_prefix']}{floor_id}.json"
if not meta_path.exists(): return if not meta_path.exists(): return
with open(meta_path, "r") as f: meta = json.load(f) with open(meta_path, "r") as f: meta = json.load(f)
@@ -73,30 +111,57 @@ def show_inference_page(cfg):
m.options.update({"minZoom": -6, "maxZoom": 6, "zoomSnap": 0.25, "maxBounds": bounds, "maxBoundsViscosity": 1.0}) m.options.update({"minZoom": -6, "maxZoom": 6, "zoomSnap": 0.25, "maxBounds": bounds, "maxBoundsViscosity": 1.0})
folium.raster_layers.ImageOverlay(image=img_data, bounds=bounds).add_to(m) folium.raster_layers.ImageOverlay(image=img_data, bounds=bounds).add_to(m)


# Disegno Beacon
# Recupero nomi per etichette mappa
names_map = fetch_beacons_metadata(cfg)

if meta["calibrated"] and meta["origin"] != [0,0]: if meta["calibrated"] and meta["origin"] != [0,0]:
# Origine
# Origine (Punto di riferimento)
folium.CircleMarker(location=[meta["origin"][1], meta["origin"][0]], radius=4, color="black", fill=True).add_to(m) folium.CircleMarker(location=[meta["origin"][1], meta["origin"][0]], radius=4, color="black", fill=True).add_to(m)


for _, row in df_active.iterrows(): for _, row in df_active.iterrows():
px_x = (row['x'] * meta["pixel_ratio"]) + meta["origin"][0] px_x = (row['x'] * meta["pixel_ratio"]) + meta["origin"][0]
px_y = meta["origin"][1] - (row['y'] * meta["pixel_ratio"]) px_y = meta["origin"][1] - (row['y'] * meta["pixel_ratio"])
mac_label = str(row['mac'])[-5:]
# --- UMANIZZAZIONE ETICHETTA MAPPA ---
norm_mac = _norm_mac_internal(row['mac'])
# Se disponibile usa il nome da API, altrimenti le ultime cifre del MAC
label_text = names_map.get(norm_mac, str(row['mac'])[-5:])


# Pallino Beacon
folium.CircleMarker( folium.CircleMarker(
location=[px_y, px_x], radius=m_size, color="blue", location=[px_y, px_x], radius=m_size, color="blue",
fill=True, fill_color="cyan", fill_opacity=0.8
fill=True, fill_color="cyan", fill_opacity=0.8,
tooltip=f"Device: {label_text} | MAC: {row['mac']}"
).add_to(m) ).add_to(m)


# Etichetta Nome (accanto al punto)
folium.Marker( folium.Marker(
location=[px_y, px_x], location=[px_y, px_x],
icon=folium.DivIcon(html=f"""<div style="font-family: sans-serif; color: black; font-weight: bold; font-size: {int(m_size*1.2)}pt; width: 80px; transform: translate({m_size+2}px, -{m_size+2}px);">{mac_label}</div>""")
icon=folium.DivIcon(html=f"""
<div style="
font-family: sans-serif;
color: #0d47a1;
font-weight: bold;
white-space: nowrap;
font-size: {int(m_size*1.1)}pt;
transform: translate({m_size+2}px, -{m_size+2}px);
text-shadow: 1px 1px 2px white;
">
{label_text}
</div>
""")
).add_to(m) ).add_to(m)


st_folium(m, height=700, width=None, key=f"inf_map_v24_{floor_id}", use_container_width=True) st_folium(m, height=700, width=None, key=f"inf_map_v24_{floor_id}", use_container_width=True)


# --- 3. TABELLA RIEPILOGO COMPLETA ---
# --- 3. TABELLA RIEPILOGO COMPLETA (Arricchita con Nome API) ---
if not df_infer.empty: if not df_infer.empty:
st.subheader("Dettaglio Dispositivi (Tutti i Piani)") st.subheader("Dettaglio Dispositivi (Tutti i Piani)")
# Aggiunta colonna Z per chiarezza
st.dataframe(df_infer[['mac', 'z', 'x', 'y']], use_container_width=True)
df_display = df_infer.copy()
df_display['mac_norm'] = df_display['mac'].apply(_norm_mac_internal)
df_display['name'] = df_display['mac_norm'].map(names_map).fillna("Sconosciuto")
# Selezione e riordino colonne finali
cols_to_show = ['mac', 'name', 'z', 'x', 'y']
st.dataframe(df_display[cols_to_show], use_container_width=True)

+ 61
- 46
app/web_suite.py View File

@@ -6,6 +6,7 @@ import time
import signal import signal
import web_status import web_status
import psutil import psutil
from pathlib import Path


# --- 1. CONFIGURAZIONE PAGINA --- # --- 1. CONFIGURAZIONE PAGINA ---
st.set_page_config( st.set_page_config(
@@ -14,13 +15,14 @@ st.set_page_config(
initial_sidebar_state="auto" initial_sidebar_state="auto"
) )


# --- 2. CONFIGURAZIONE PERCORSI ---
REAL_CONFIG_PATH = "/config/config.yaml"
if not os.path.exists(REAL_CONFIG_PATH):
REAL_CONFIG_PATH = "/app/config/config.yaml"

# --- 2. CONFIGURAZIONE PERCORSI E STATI PERSISTENTI ---
REAL_CONFIG_PATH = "/config/config.yaml" if os.path.exists("/config/config.yaml") else "/app/config/config.yaml"
LOG_FILE = "/tmp/main_process.log" LOG_FILE = "/tmp/main_process.log"


# File di stato su disco per la persistenza
CORE_STATE_FILE = "/data/config/core.enabled"
LOG_PID_FILE = "/tmp/mqtt_logging.pid"

def load_yaml(path): def load_yaml(path):
if not os.path.exists(path): return {} if not os.path.exists(path): return {}
with open(path, 'r', encoding='utf-8') as f: return yaml.safe_load(f) or {} with open(path, 'r', encoding='utf-8') as f: return yaml.safe_load(f) or {}
@@ -30,7 +32,12 @@ def save_yaml(path, data):


cfg = load_yaml(REAL_CONFIG_PATH) cfg = load_yaml(REAL_CONFIG_PATH)


# --- 3. LOGICA PERSISTENZA CORE ---
def stop_core_engine(): def stop_core_engine():
"""Arresta il core e rimuove il flag di persistenza."""
if os.path.exists(CORE_STATE_FILE):
os.remove(CORE_STATE_FILE)
for proc in psutil.process_iter(['cmdline']): for proc in psutil.process_iter(['cmdline']):
try: try:
cmd = proc.info['cmdline'] cmd = proc.info['cmdline']
@@ -42,9 +49,12 @@ def stop_core_engine():
except: pass except: pass


def start_core_engine(): def start_core_engine():
"""Avvia il core e crea il flag di persistenza su disco."""
Path(CORE_STATE_FILE).touch()
env = os.environ.copy() env = os.environ.copy()
env["CONFIG"] = REAL_CONFIG_PATH env["CONFIG"] = REAL_CONFIG_PATH
env["PYTHONPATH"] = "/app" env["PYTHONPATH"] = "/app"
# Reindirizzamento append log per non perdere lo storico dell'entrypoint
with open(LOG_FILE, "a") as log_f: with open(LOG_FILE, "a") as log_f:
subprocess.Popen( subprocess.Popen(
["python3", "-m", "app.main"], ["python3", "-m", "app.main"],
@@ -55,10 +65,18 @@ def start_core_engine():
start_new_session=True start_new_session=True
) )


# --- 3. TITOLO FISSO ---
# --- 4. MONITORAGGIO ATTIVO (SENZA AUTO-START BLOCCANTE) ---
# La logica di avvio al boot è ora gestita da entrypoint.sh.
# Qui segnaliamo solo se lo stato desiderato (file esistente) non coincide con quello reale.
if os.path.exists(CORE_STATE_FILE) and not web_status.is_main_running():
st.sidebar.warning("⚠️ Core abilitato ma non in esecuzione.")
if st.sidebar.button("RIPRISTINA ORA"):
start_core_engine()
st.rerun()

# --- 5. TITOLO E LOGIN ---
st.title("🛰️ BLE AI Localizer - Suite") st.title("🛰️ BLE AI Localizer - Suite")


# --- 4. LOGICA LOGIN ---
if "password_correct" not in st.session_state: if "password_correct" not in st.session_state:
st.session_state["password_correct"] = False st.session_state["password_correct"] = False


@@ -73,63 +91,60 @@ if not st.session_state["password_correct"]:
st.error("Credenziali errate") st.error("Credenziali errate")
st.stop() st.stop()


# --- 5. AUTO-START ---
if not web_status.is_main_running():
if "core_auto_launched" not in st.session_state:
start_core_engine()
st.session_state["core_auto_launched"] = True
time.sleep(1)
st.rerun()

# --- 6. SIDEBAR: CONTROLLI SISTEMA --- # --- 6. SIDEBAR: CONTROLLI SISTEMA ---
with st.sidebar: with st.sidebar:
st.header("🛠️ Core Control") st.header("🛠️ Core Control")
is_running = web_status.is_main_running() is_running = web_status.is_main_running()
if is_running:
st.markdown("STATO: :green[**CORE ATTIVO**]")
else:
st.markdown("STATO: :red[**CORE FERMO**]")
st.markdown(f"STATO: {':green[**CORE ATTIVO**]' if is_running else ':red[**CORE FERMO**]'}")
if st.button("🚀 RIAVVIA CORE" if is_running else "▶️ AVVIA CORE", use_container_width=True): if st.button("🚀 RIAVVIA CORE" if is_running else "▶️ AVVIA CORE", use_container_width=True):
with st.spinner("Gestione Core..."):
stop_core_engine()
time.sleep(1)
start_core_engine()
time.sleep(2)
st.rerun()
stop_core_engine()
time.sleep(1)
start_core_engine()
st.rerun()


st.divider() st.divider()
# --- GESTIONE MQTT RAW (DINAMICA DA CONFIG) ---
m_cfg = cfg.get('mqtt', {})
m_host = m_cfg.get('host', '127.0.0.1')
m_port = m_cfg.get('port', 1883)
m_proto = m_cfg.get('protocol', 'mqttv311')
# Estraiamo la parola chiave dal topic (es: 'publish_out' da 'publish_out/#')
m_filter = m_cfg.get('topic', 'publish_out').split('/')[0]

RAW_LOG_DIR = cfg.get('paths', {}).get('mqtt_raw_dir', '/data/mqtt_raw/')
os.makedirs(RAW_LOG_DIR, exist_ok=True)
raw_active = st.toggle("🔴 MQTT RAW RECORDING", value=st.session_state.get("mqtt_logging", False))
if raw_active and not st.session_state.get("mqtt_logging"):
# --- GESTIONE MQTT RAW PERSISTENTE ---
is_logging_active = False
if os.path.exists(LOG_PID_FILE):
try:
with open(LOG_PID_FILE, "r") as f:
saved_pid = int(f.read().strip())
if psutil.pid_exists(saved_pid):
is_logging_active = True
else:
os.remove(LOG_PID_FILE)
except:
pass

raw_active = st.toggle("🔴 MQTT RAW RECORDING", value=is_logging_active)
if raw_active and not is_logging_active:
RAW_LOG_DIR = cfg.get('paths', {}).get('mqtt_raw_dir', '/data/mqtt_raw/')
os.makedirs(RAW_LOG_DIR, exist_ok=True)
dt = time.strftime("%Y%m%d_%H%M%S") dt = time.strftime("%Y%m%d_%H%M%S")
filepath = os.path.join(RAW_LOG_DIR, f"mqtt_raw_{dt}.log") filepath = os.path.join(RAW_LOG_DIR, f"mqtt_raw_{dt}.log")
m_cfg = cfg.get('mqtt', {})
m_filter = m_cfg.get('topic', 'publish_out').split('/')[0]
# Comando generato dinamicamente dai parametri YAML
cmd = f"stdbuf -oL mosquitto_sub -v -h {m_host} -p {m_port} -t '#' -V {m_proto} | stdbuf -oL grep '{m_filter}' > {filepath}"
cmd = f"stdbuf -oL mosquitto_sub -v -h {m_cfg.get('host')} -p {m_cfg.get('port')} -t '#' | stdbuf -oL grep '{m_filter}' > {filepath}"
proc = subprocess.Popen(cmd, shell=True, preexec_fn=os.setsid) proc = subprocess.Popen(cmd, shell=True, preexec_fn=os.setsid)
st.session_state["mqtt_logging"] = True
st.session_state["mqtt_proc_pid"] = proc.pid
st.success(f"Log avviato: {m_host}")
with open(LOG_PID_FILE, "w") as f:
f.write(str(proc.pid))
st.rerun()
if not raw_active and st.session_state.get("mqtt_logging"):
elif not raw_active and is_logging_active:
try: try:
os.killpg(os.getpgid(st.session_state["mqtt_proc_pid"]), signal.SIGTERM)
with open(LOG_PID_FILE, "r") as f:
pid_to_kill = int(f.read().strip())
os.killpg(os.getpgid(pid_to_kill), signal.SIGTERM)
if os.path.exists(LOG_PID_FILE): os.remove(LOG_PID_FILE)
st.rerun()
except: except:
pass pass
st.session_state["mqtt_logging"] = False


# --- 7. IMPORT MODULI E TABS --- # --- 7. IMPORT MODULI E TABS ---
from map_manager import show_mapper from map_manager import show_mapper


+ 30
- 14
app/web_test_inference.py View File

@@ -53,14 +53,34 @@ def show_test_inference(cfg):
m_pkg = joblib.load(MODEL_DIR / selected_model) m_pkg = joblib.load(MODEL_DIR / selected_model)
delim = cfg.get('paths', {}).get('csv_delimiter', ';') delim = cfg.get('paths', {}).get('csv_delimiter', ';')
df_test = pd.read_csv(TEST_SAMPLES_DIR / selected_test, sep=delim) df_test = pd.read_csv(TEST_SAMPLES_DIR / selected_test, sep=delim)
row = df_test.iloc[0] row = df_test.iloc[0]
z_real, x_real, y_real = int(round(float(row['z']))), float(row['x']), float(row['y'])
z_real, x_real, y_real = int(round(float(row['z']))), float(row['x']), float(row['y'])
gws = m_pkg['gateways_order'] gws = m_pkg['gateways_order']
fill = m_pkg.get('nan_fill', -110.0) fill = m_pkg.get('nan_fill', -110.0)
X_in = np.array([[float(row.get(gw, fill)) for gw in gws]])

# --- DEBUG VETTORE INPUT ---
raw_vals = []
for gw in gws:
val = row.get(gw)
raw_vals.append(float(val) if val is not None and not pd.isna(val) else fill)
X_in = np.array([raw_vals])
# Visualizzazione Debug in UI per l'operatore
with st.expander("🔍 Analisi Vettore di Input (Fingerprint vs Modello)"):
debug_df = pd.DataFrame({
"Gateway MAC": gws,
"RSSI Letto": [row.get(gw, "NON TROVATO") for gw in gws],
"RSSI Finale (Input AI)": raw_vals
})
st.dataframe(debug_df)
match_count = np.sum(X_in[0] > fill)
st.write(f"**Gateway Corrispondenti:** {match_count} su {len(gws)}")
if match_count == 0:
st.error("ERRORE: Il file di test non contiene nessuno dei Gateway usati per l'addestramento!")

# Predizione
z_pred = int(m_pkg['floor_clf'].predict(X_in)[0]) z_pred = int(m_pkg['floor_clf'].predict(X_in)[0])
x_pred, y_pred = -1.0, -1.0 x_pred, y_pred = -1.0, -1.0
if z_pred in m_pkg['xy_by_floor']: if z_pred in m_pkg['xy_by_floor']:
@@ -68,27 +88,24 @@ def show_test_inference(cfg):
x_pred, y_pred = float(xy[0]), float(xy[1]) x_pred, y_pred = float(xy[0]), float(xy[1])


z_err, dist_err = calculate_error(z_real, x_real, y_real, z_pred, x_pred, y_pred) z_err, dist_err = calculate_error(z_real, x_real, y_real, z_pred, x_pred, y_pred)
st.session_state.test_results = { st.session_state.test_results = {
"z_real": z_real, "x_real": x_real, "y_real": y_real, "z_real": z_real, "x_real": x_real, "y_real": y_real,
"z_pred": z_pred, "x_pred": x_pred, "y_pred": y_pred, "z_pred": z_pred, "x_pred": x_pred, "y_pred": y_pred,
"z_err": z_err, "dist_err": dist_err,
"model_used": selected_model
"z_err": z_err, "dist_err": dist_err, "model_used": selected_model
} }
except Exception as e: except Exception as e:
st.error(f"Errore: {e}")
st.error(f"Errore durante l'inferenza: {e}")


# --- VISUALIZZAZIONE GRAFICA DEI RISULTATI ---
if st.session_state.test_results: if st.session_state.test_results:
res = st.session_state.test_results res = st.session_state.test_results
# --- RIPRISTINO INFORMAZIONI COORDINATE ---
c_info1, c_info2 = st.columns(2) c_info1, c_info2 = st.columns(2)
with c_info1: with c_info1:
st.info(f"📍 **Test Reale** | Piano: {res['z_real']} | X: **{res['x_real']}** | Y: **{res['y_real']}**") st.info(f"📍 **Test Reale** | Piano: {res['z_real']} | X: **{res['x_real']}** | Y: **{res['y_real']}**")
with c_info2: with c_info2:
st.success(f"🔮 **Predizione** | Piano: {res['z_pred']} | X: **{round(res['x_pred'],1)}** | Y: **{round(res['y_pred'],1)}**") st.success(f"🔮 **Predizione** | Piano: {res['z_pred']} | X: **{round(res['x_pred'],1)}** | Y: **{round(res['y_pred'],1)}**")


# --- LEGENDA AGGIORNATA CON NUOVI COLORI ---
st.markdown(f""" st.markdown(f"""
<div style="background-color: #f8f9fa; padding: 12px; border-radius: 8px; border-left: 5px solid #00bcd4; margin: 10px 0;"> <div style="background-color: #f8f9fa; padding: 12px; border-radius: 8px; border-left: 5px solid #00bcd4; margin: 10px 0;">
<h5 style="margin:0 0 8px 0;">📍 Legenda Mappa</h5> <h5 style="margin:0 0 8px 0;">📍 Legenda Mappa</h5>
@@ -122,14 +139,13 @@ def show_test_inference(cfg):
p_real = to_px(res['x_real'], res['y_real']) p_real = to_px(res['x_real'], res['y_real'])
p_pred = to_px(res['x_pred'], res['y_pred']) p_pred = to_px(res['x_pred'], res['y_pred'])


# 🔵 PUNTO DI TEST (Celeste)
# Marker Posizione Reale
folium.CircleMarker( folium.CircleMarker(
location=p_real, radius=11, color="#00838f", fill=True, location=p_real, radius=11, color="#00838f", fill=True,
fill_color="#00bcd4", fill_opacity=0.85,
tooltip="PUNTO DI TEST (REALE)"
fill_color="#00bcd4", fill_opacity=0.85, tooltip="PUNTO DI TEST (REALE)"
).add_to(m) ).add_to(m)
# 🟠 PUNTO PREDETTO (Arancio)
# Marker Predizione
if res['x_pred'] != -1.0: if res['x_pred'] != -1.0:
folium.CircleMarker( folium.CircleMarker(
location=p_pred, radius=11, color="#e65100", fill=True, location=p_pred, radius=11, color="#e65100", fill=True,
@@ -137,7 +153,7 @@ def show_test_inference(cfg):
tooltip=f"PREDIZIONE (Modello: {res['model_used']})" tooltip=f"PREDIZIONE (Modello: {res['model_used']})"
).add_to(m) ).add_to(m)
# Linea Errore
# Linea di errore (Gialla tratteggiata)
folium.PolyLine( folium.PolyLine(
locations=[p_real, p_pred], color="#ffeb3b", locations=[p_real, p_pred], color="#ffeb3b",
weight=4, opacity=0.7, dash_array='8' weight=4, opacity=0.7, dash_array='8'


+ 3
- 3
config/config.yaml View File

@@ -60,7 +60,7 @@ infer:
refresh_seconds: 10 refresh_seconds: 10
rssi_max: -25 rssi_max: -25
rssi_min: -110 rssi_min: -110
window_seconds: 7
window_seconds: 30
xy_round: 0 xy_round: 0
maps: maps:
default_dot_size: 20 default_dot_size: 20
@@ -70,7 +70,7 @@ maps:
meta_prefix: meta_ meta_prefix: meta_
show_grid_default: true show_grid_default: true
ml: ml:
k: 5
k: 3
method: knn method: knn
metric: euclidean metric: euclidean
weights: distance weights: distance
@@ -103,7 +103,7 @@ train:
folds: 5 folds: 5
k_max: 15 k_max: 15
k_min: 3 k_min: 3
k: 5
k: 3
metric: euclidean metric: euclidean
weights: distance weights: distance
model_path: /data/model/model.joblib model_path: /data/model/model.joblib


+ 0
- 0
data/config/core.enabled View File


+ 12
- 12
data/infer/infer.csv View File

@@ -1,13 +1,13 @@
mac;z;x;y mac;z;x;y
C8:3F:8F:17:DB:35;-1;-1;-1
C3:00:00:39:47:DF;-1;-1;-1
C3:00:00:39:47:C4;-1;1917;650
C3:00:00:39:47:E2;-1;-1;-1
C7:AE:56:1E:38:B7;-1;1917;650
E0:1F:9A:7A:47:D2;-1;-1;-1
C3:00:00:57:B9:D9;-1;1917;650
C3:00:00:57:B9:DB;-1;1917;650
C3:00:00:57:B9:F4;-1;1917;650
C3:00:00:57:B9:DC;-1;1917;650
C3:00:00:57:B9:DD;-1;1917;650
C3:00:00:57:B9:DF;-1;1917;650
c8:3f:8f:17:db:35;-1;-1;-1
c3:00:00:39:47:df;1;2082;1337
c3:00:00:39:47:c4;1;883;1263
c3:00:00:39:47:e2;1;1506;778
c7:ae:56:1e:38:b7;1;2254;672
e0:1f:9a:7a:47:d2;-1;-1;-1
c3:00:00:57:b9:d9;1;2084;1344
c3:00:00:57:b9:db;1;2066;1345
c3:00:00:57:b9:f4;1;1790;989
c3:00:00:57:b9:dc;1;875;1177
c3:00:00:57:b9:dd;1;918;1037
c3:00:00:57:b9:df;1;919;971

BIN
data/maps/floor_0.png View File

Before After
Width: 8337  |  Height: 4803  |  Size: 528 KiB

BIN
data/maps/floor_1.png View File

Before After
Width: 8238  |  Height: 4672  |  Size: 556 KiB

+ 9
- 0
data/maps/meta_0.json View File

@@ -0,0 +1,9 @@
{
"pixel_ratio": 1.5838698443273016,
"calibrated": true,
"origin": [
1299,
3742
],
"grid_size": 50
}

+ 9
- 0
data/maps/meta_1.json View File

@@ -0,0 +1,9 @@
{
"pixel_ratio": 1.5923301441291737,
"calibrated": true,
"origin": [
1348,
3537
],
"grid_size": 50
}

+ 1
- 0
data/model/model.joblib View File

@@ -0,0 +1 @@
model_camp_00_20260218_114109.joblib

BIN
data/model/model_camp_00_20260218_114109.joblib View File


BIN
data/model/model_camp_04_20260218_114229.joblib View File


BIN
data/model/model_camp_08_20260218_114319.joblib View File


BIN
data/model/model_camp_12_20260218_114340.joblib View File


+ 370
- 0
data/mqtt_raw/mqtt_raw_20260218_173135.log
File diff suppressed because it is too large
View File


+ 90
- 0
data/mqtt_raw/mqtt_raw_20260218_173234.log
File diff suppressed because it is too large
View File


+ 5
- 0
data/train/jobs/done/GBC-01_0_1096_1145.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1096_1145;0;BC-00-21;1096;1145;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1096_1145;0;BC-04-22;1096;1145;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1096_1145;0;BC-08-23;1096;1145;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1096_1145;0;BC-12-24;1096;1145;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_1229_709.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1229_709;0;BC-00-21;1229;709;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1229_709;0;BC-04-22;1229;709;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1229_709;0;BC-08-23;1229;709;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1229_709;0;BC-12-24;1229;709;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_1438_496.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1438_496;0;BC-00-21;1438;496;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1438_496;0;BC-04-22;1438;496;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1438_496;0;BC-08-23;1438;496;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1438_496;0;BC-12-24;1438;496;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_1438_981.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1438_981;0;BC-00-21;1438;981;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1438_981;0;BC-04-22;1438;981;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1438_981;0;BC-08-23;1438;981;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1438_981;0;BC-12-24;1438;981;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_1641_1401.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1641_1401;0;BC-00-21;1641;1401;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1641_1401;0;BC-04-22;1641;1401;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1641_1401;0;BC-08-23;1641;1401;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1641_1401;0;BC-12-24;1641;1401;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_1671_101.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1671_101;0;BC-00-21;1671;101;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1671_101;0;BC-04-22;1671;101;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1671_101;0;BC-08-23;1671;101;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1671_101;0;BC-12-24;1671;101;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_1675_918.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_1675_918;0;BC-00-21;1675;918;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_1675_918;0;BC-04-22;1675;918;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_1675_918;0;BC-08-23;1675;918;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_1675_918;0;BC-12-24;1675;918;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2022_700.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2022_700;0;BC-00-21;2022;700;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2022_700;0;BC-04-22;2022;700;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2022_700;0;BC-08-23;2022;700;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2022_700;0;BC-12-24;2022;700;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2041_477.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2041_477;0;BC-00-21;2041;477;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2041_477;0;BC-04-22;2041;477;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2041_477;0;BC-08-23;2041;477;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2041_477;0;BC-12-24;2041;477;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2096_680.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2096_680;0;BC-00-21;2096;680;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2096_680;0;BC-04-22;2096;680;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2096_680;0;BC-08-23;2096;680;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2096_680;0;BC-12-24;2096;680;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2102_676.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2102_676;0;BC-00-21;2102;676;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2102_676;0;BC-04-22;2102;676;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2102_676;0;BC-08-23;2102;676;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2102_676;0;BC-12-24;2102;676;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2107_792.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2107_792;0;BC-00-21;2107;792;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2107_792;0;BC-04-22;2107;792;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2107_792;0;BC-08-23;2107;792;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2107_792;0;BC-12-24;2107;792;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_218_120.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_218_120;0;BC-00-21;218;120;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_218_120;0;BC-04-22;218;120;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_218_120;0;BC-08-23;218;120;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_218_120;0;BC-12-24;218;120;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2244_735.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2244_735;0;BC-00-21;2244;735;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2244_735;0;BC-04-22;2244;735;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2244_735;0;BC-08-23;2244;735;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2244_735;0;BC-12-24;2244;735;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2377_671.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2377_671;0;BC-00-21;2377;671;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2377_671;0;BC-04-22;2377;671;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2377_671;0;BC-08-23;2377;671;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2377_671;0;BC-12-24;2377;671;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2503_523.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2503_523;0;BC-00-21;2503;523;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2503_523;0;BC-04-22;2503;523;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2503_523;0;BC-08-23;2503;523;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2503_523;0;BC-12-24;2503;523;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2702_660.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2702_660;0;BC-00-21;2702;660;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2702_660;0;BC-04-22;2702;660;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2702_660;0;BC-08-23;2702;660;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2702_660;0;BC-12-24;2702;660;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2816_375.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2816_375;0;BC-00-21;2816;375;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2816_375;0;BC-04-22;2816;375;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2816_375;0;BC-08-23;2816;375;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2816_375;0;BC-12-24;2816;375;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_2818_931.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_2818_931;0;BC-00-21;2818;931;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_2818_931;0;BC-04-22;2818;931;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_2818_931;0;BC-08-23;2818;931;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_2818_931;0;BC-12-24;2818;931;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_631_93.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_631_93;0;BC-00-21;631;93;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_631_93;0;BC-04-22;631;93;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_631_93;0;BC-08-23;631;93;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_631_93;0;BC-12-24;631;93;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_848_1113.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_848_1113;0;BC-00-21;848;1113;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_848_1113;0;BC-04-22;848;1113;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_848_1113;0;BC-08-23;848;1113;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_848_1113;0;BC-12-24;848;1113;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_849_102.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_849_102;0;BC-00-21;849;102;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_849_102;0;BC-04-22;849;102;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_849_102;0;BC-08-23;849;102;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_849_102;0;BC-12-24;849;102;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_0_849_1408.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_0_849_1408;0;BC-00-21;849;1408;0;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_0_849_1408;0;BC-04-22;849;1408;0;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_0_849_1408;0;BC-08-23;849;1408;0;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_0_849_1408;0;BC-12-24;849;1408;0;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1050_1197.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1050_1197;1;BC-00-21;1050;1197;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1050_1197;1;BC-04-22;1050;1197;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1050_1197;1;BC-08-23;1050;1197;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1050_1197;1;BC-12-24;1050;1197;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1129_114.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1129_114;1;BC-00-21;1129;114;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1129_114;1;BC-04-22;1129;114;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1129_114;1;BC-08-23;1129;114;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1129_114;1;BC-12-24;1129;114;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1290_1423.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1290_1423;1;BC-00-21;1290;1423;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1290_1423;1;BC-04-22;1290;1423;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1290_1423;1;BC-08-23;1290;1423;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1290_1423;1;BC-12-24;1290;1423;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1302_1344.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1302_1344;1;BC-00-21;1302;1344;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1302_1344;1;BC-04-22;1302;1344;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1302_1344;1;BC-08-23;1302;1344;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1302_1344;1;BC-12-24;1302;1344;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1363_749.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1363_749;1;BC-00-21;1363;749;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1363_749;1;BC-04-22;1363;749;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1363_749;1;BC-08-23;1363;749;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1363_749;1;BC-12-24;1363;749;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1467_373.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1467_373;1;BC-00-21;1467;373;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1467_373;1;BC-04-22;1467;373;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1467_373;1;BC-08-23;1467;373;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1467_373;1;BC-12-24;1467;373;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_1547_1421.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_1547_1421;1;BC-00-21;1547;1421;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_1547_1421;1;BC-04-22;1547;1421;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_1547_1421;1;BC-08-23;1547;1421;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_1547_1421;1;BC-12-24;1547;1421;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2211_1431.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2211_1431;1;BC-00-21;2211;1431;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2211_1431;1;BC-04-22;2211;1431;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2211_1431;1;BC-08-23;2211;1431;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2211_1431;1;BC-12-24;2211;1431;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2219_440.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2219_440;1;BC-00-21;2219;440;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2219_440;1;BC-04-22;2219;440;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2219_440;1;BC-08-23;2219;440;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2219_440;1;BC-12-24;2219;440;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2248_980.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2248_980;1;BC-00-21;2248;980;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2248_980;1;BC-04-22;2248;980;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2248_980;1;BC-08-23;2248;980;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2248_980;1;BC-12-24;2248;980;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2250_742.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2250_742;1;BC-00-21;2250;742;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2250_742;1;BC-04-22;2250;742;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2250_742;1;BC-08-23;2250;742;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2250_742;1;BC-12-24;2250;742;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2628_1116.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2628_1116;1;BC-00-21;2628;1116;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2628_1116;1;BC-04-22;2628;1116;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2628_1116;1;BC-08-23;2628;1116;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2628_1116;1;BC-12-24;2628;1116;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2629_652.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2629_652;1;BC-00-21;2629;652;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2629_652;1;BC-04-22;2629;652;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2629_652;1;BC-08-23;2629;652;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2629_652;1;BC-12-24;2629;652;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2811_921.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2811_921;1;BC-00-21;2811;921;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2811_921;1;BC-04-22;2811;921;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2811_921;1;BC-08-23;2811;921;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2811_921;1;BC-12-24;2811;921;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_2880_519.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_2880_519;1;BC-00-21;2880;519;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_2880_519;1;BC-04-22;2880;519;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_2880_519;1;BC-08-23;2880;519;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_2880_519;1;BC-12-24;2880;519;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_852_1106.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_852_1106;1;BC-00-21;852;1106;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_852_1106;1;BC-04-22;852;1106;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_852_1106;1;BC-08-23;852;1106;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_852_1106;1;BC-12-24;852;1106;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_854_1111.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_854_1111;1;BC-00-21;854;1111;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_854_1111;1;BC-04-22;854;1111;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_854_1111;1;BC-08-23;854;1111;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_854_1111;1;BC-12-24;854;1111;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_855_745.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_855_745;1;BC-00-21;855;745;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_855_745;1;BC-04-22;855;745;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_855_745;1;BC-08-23;855;745;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_855_745;1;BC-12-24;855;745;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-01_1_988_802.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-21_1_988_802;1;BC-00-21;988;802;1;BC-00-21;C3:00:00:57:B9:E6
BC-04-22_1_988_802;1;BC-04-22;988;802;1;BC-04-22;C3:00:00:57:B9:D4
BC-08-23_1_988_802;1;BC-08-23;988;802;1;BC-08-23;C3:00:00:57:B9:E8
BC-12-24_1_988_802;1;BC-12-24;988;802;1;BC-12-24;C3:00:00:57:B9:F1

+ 5
- 0
data/train/jobs/done/GBC-02_0_1421_1424.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1421_1424;0;BC-00-25;1421;1424;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1421_1424;0;BC-04-26;1421;1424;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1421_1424;0;BC-08-27;1421;1424;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1421_1424;0;BC-12-28;1421;1424;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1438_829.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1438_829;0;BC-00-25;1438;829;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1438_829;0;BC-04-26;1438;829;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1438_829;0;BC-08-27;1438;829;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1438_829;0;BC-12-28;1438;829;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1493_797.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1493_797;0;BC-00-25;1493;797;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1493_797;0;BC-04-26;1493;797;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1493_797;0;BC-08-27;1493;797;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1493_797;0;BC-12-28;1493;797;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1557_299.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1557_299;0;BC-00-25;1557;299;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1557_299;0;BC-04-26;1557;299;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1557_299;0;BC-08-27;1557;299;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1557_299;0;BC-12-28;1557;299;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1673_498.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1673_498;0;BC-00-25;1673;498;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1673_498;0;BC-04-26;1673;498;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1673_498;0;BC-08-27;1673;498;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1673_498;0;BC-12-28;1673;498;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1859_51.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1859_51;0;BC-00-25;1859;51;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1859_51;0;BC-04-26;1859;51;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1859_51;0;BC-08-27;1859;51;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1859_51;0;BC-12-28;1859;51;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1861_1118.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1861_1118;0;BC-00-25;1861;1118;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1861_1118;0;BC-04-26;1861;1118;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1861_1118;0;BC-08-27;1861;1118;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1861_1118;0;BC-12-28;1861;1118;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_1958_250.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_1958_250;0;BC-00-25;1958;250;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_1958_250;0;BC-04-26;1958;250;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_1958_250;0;BC-08-27;1958;250;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_1958_250;0;BC-12-28;1958;250;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2004_1404.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2004_1404;0;BC-00-25;2004;1404;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2004_1404;0;BC-04-26;2004;1404;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2004_1404;0;BC-08-27;2004;1404;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2004_1404;0;BC-12-28;2004;1404;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2025_791.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2025_791;0;BC-00-25;2025;791;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2025_791;0;BC-04-26;2025;791;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2025_791;0;BC-08-27;2025;791;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2025_791;0;BC-12-28;2025;791;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2106_789.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2106_789;0;BC-00-25;2106;789;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2106_789;0;BC-04-26;2106;789;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2106_789;0;BC-08-27;2106;789;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2106_789;0;BC-12-28;2106;789;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2114_688.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2114_688;0;BC-00-25;2114;688;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2114_688;0;BC-04-26;2114;688;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2114_688;0;BC-08-27;2114;688;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2114_688;0;BC-12-28;2114;688;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2192_100.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2192_100;0;BC-00-25;2192;100;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2192_100;0;BC-04-26;2192;100;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2192_100;0;BC-08-27;2192;100;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2192_100;0;BC-12-28;2192;100;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2193_371.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2193_371;0;BC-00-25;2193;371;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2193_371;0;BC-04-26;2193;371;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2193_371;0;BC-08-27;2193;371;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2193_371;0;BC-12-28;2193;371;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2230_927.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2230_927;0;BC-00-25;2230;927;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2230_927;0;BC-04-26;2230;927;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2230_927;0;BC-08-27;2230;927;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2230_927;0;BC-12-28;2230;927;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2242_740.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2242_740;0;BC-00-25;2242;740;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2242_740;0;BC-04-26;2242;740;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2242_740;0;BC-08-27;2242;740;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2242_740;0;BC-12-28;2242;740;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2373_789.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2373_789;0;BC-00-25;2373;789;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2373_789;0;BC-04-26;2373;789;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2373_789;0;BC-08-27;2373;789;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2373_789;0;BC-12-28;2373;789;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2412_679.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2412_679;0;BC-00-25;2412;679;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2412_679;0;BC-04-26;2412;679;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2412_679;0;BC-08-27;2412;679;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2412_679;0;BC-12-28;2412;679;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2414_796.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2414_796;0;BC-00-25;2414;796;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2414_796;0;BC-04-26;2414;796;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2414_796;0;BC-08-27;2414;796;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2414_796;0;BC-12-28;2414;796;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2489_1157.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2489_1157;0;BC-00-25;2489;1157;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2489_1157;0;BC-04-26;2489;1157;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2489_1157;0;BC-08-27;2489;1157;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2489_1157;0;BC-12-28;2489;1157;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2505_220.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2505_220;0;BC-00-25;2505;220;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2505_220;0;BC-04-26;2505;220;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2505_220;0;BC-08-27;2505;220;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2505_220;0;BC-12-28;2505;220;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2812_1418.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2812_1418;0;BC-00-25;2812;1418;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2812_1418;0;BC-04-26;2812;1418;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2812_1418;0;BC-08-27;2812;1418;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2812_1418;0;BC-12-28;2812;1418;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2894_522.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2894_522;0;BC-00-25;2894;522;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2894_522;0;BC-04-26;2894;522;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2894_522;0;BC-08-27;2894;522;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2894_522;0;BC-12-28;2894;522;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_2894_776.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_2894_776;0;BC-00-25;2894;776;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_2894_776;0;BC-04-26;2894;776;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_2894_776;0;BC-08-27;2894;776;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_2894_776;0;BC-12-28;2894;776;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_528_1457.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_528_1457;0;BC-00-25;528;1457;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_528_1457;0;BC-04-26;528;1457;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_528_1457;0;BC-08-27;528;1457;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_528_1457;0;BC-12-28;528;1457;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_848_842.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_848_842;0;BC-00-25;848;842;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_848_842;0;BC-04-26;848;842;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_848_842;0;BC-08-27;848;842;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_848_842;0;BC-12-28;848;842;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_852_707.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_852_707;0;BC-00-25;852;707;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_852_707;0;BC-04-26;852;707;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_852_707;0;BC-08-27;852;707;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_852_707;0;BC-12-28;852;707;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_0_993_456.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_0_993_456;0;BC-00-25;993;456;0;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_0_993_456;0;BC-04-26;993;456;0;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_0_993_456;0;BC-08-27;993;456;0;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_0_993_456;0;BC-12-28;993;456;0;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_1150_518.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_1150_518;1;BC-00-25;1150;518;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_1150_518;1;BC-04-26;1150;518;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_1150_518;1;BC-08-27;1150;518;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_1150_518;1;BC-12-28;1150;518;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_1150_743.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_1150_743;1;BC-00-25;1150;743;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_1150_743;1;BC-04-26;1150;743;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_1150_743;1;BC-08-27;1150;743;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_1150_743;1;BC-12-28;1150;743;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_1298_1107.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_1298_1107;1;BC-00-25;1298;1107;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_1298_1107;1;BC-04-26;1298;1107;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_1298_1107;1;BC-08-27;1298;1107;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_1298_1107;1;BC-12-28;1298;1107;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_1491_115.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_1491_115;1;BC-00-25;1491;115;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_1491_115;1;BC-04-26;1491;115;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_1491_115;1;BC-08-27;1491;115;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_1491_115;1;BC-12-28;1491;115;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_1735_1415.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_1735_1415;1;BC-00-25;1735;1415;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_1735_1415;1;BC-04-26;1735;1415;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_1735_1415;1;BC-08-27;1735;1415;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_1735_1415;1;BC-12-28;1735;1415;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_1979_582.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_1979_582;1;BC-00-25;1979;582;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_1979_582;1;BC-04-26;1979;582;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_1979_582;1;BC-08-27;1979;582;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_1979_582;1;BC-12-28;1979;582;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_2084_1179.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_2084_1179;1;BC-00-25;2084;1179;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_2084_1179;1;BC-04-26;2084;1179;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_2084_1179;1;BC-08-27;2084;1179;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_2084_1179;1;BC-12-28;2084;1179;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_2413_793.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_2413_793;1;BC-00-25;2413;793;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_2413_793;1;BC-04-26;2413;793;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_2413_793;1;BC-08-27;2413;793;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_2413_793;1;BC-12-28;2413;793;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_2415_672.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_2415_672;1;BC-00-25;2415;672;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_2415_672;1;BC-04-26;2415;672;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_2415_672;1;BC-08-27;2415;672;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_2415_672;1;BC-12-28;2415;672;1;BC-12-28;C3:00:00:57:B9:F6

+ 5
- 0
data/train/jobs/done/GBC-02_1_2433_931.csv View File

@@ -0,0 +1,5 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-00-25_1_2433_931;1;BC-00-25;2433;931;1;BC-00-25;C3:00:00:57:B9:E7
BC-04-26_1_2433_931;1;BC-04-26;2433;931;1;BC-04-26;C3:00:00:57:B9:D6
BC-08-27_1_2433_931;1;BC-08-27;2433;931;1;BC-08-27;C3:00:00:57:B9:D7
BC-12-28_1_2433_931;1;BC-12-28;2433;931;1;BC-12-28;C3:00:00:57:B9:F6

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save