Przeglądaj źródła

Integrazione mappa per supporto dispositivi mobili

master
root 1 miesiąc temu
rodzic
commit
6bd9d920e4
77 zmienionych plików z 13938 dodań i 9097 usunięć
  1. +13
    -18
      Dockerfile
  2. +1
    -1
      README.md
  3. +0
    -58
      app/leaflet_bridge.js
  4. +209
    -41
      app/map_manager.py
  5. +0
    -145
      app/map_manager.py_v1
  6. +0
    -49
      app/map_manager.py_v2
  7. +83
    -81
      app/web_inference.py
  8. +4
    -1
      app/web_suite.py
  9. +4
    -4
      config/config.yaml
  10. +9
    -9
      data/infer/infer.csv
  11. BIN
      data/maps.bck/floor_0.png
  12. BIN
      data/maps.bck/floor_1.png
  13. +1
    -0
      data/maps.bck/meta_0.json
  14. +1
    -0
      data/maps.bck/meta_1.json
  15. BIN
      data/maps.old/floor_0.png
  16. BIN
      data/maps.old/floor_1.png
  17. +9
    -0
      data/maps.old/meta_0.json
  18. +1
    -0
      data/maps.old/meta_1.json
  19. BIN
      data/maps/floor_-1.png
  20. +9
    -0
      data/maps/meta_-1.json
  21. +9
    -1
      data/maps/meta_0.json
  22. +9
    -1
      data/maps/meta_1.json
  23. +0
    -0
      data/train/jobs/done/1_1600_450.csv
  24. +2
    -0
      data/train/jobs/done/BC-21_-1_1050_250.csv
  25. +2
    -0
      data/train/jobs/done/BC-21_0_195_1425.csv
  26. +2
    -0
      data/train/jobs/done/BC-21_0_2114_796.csv
  27. +2
    -0
      data/train/jobs/done/BC-21_0_2115_697.csv
  28. +2
    -0
      data/train/jobs/done/BC-21_0_2568_946.csv
  29. +2
    -0
      data/train/jobs/done/BC-21_0_400_100.csv
  30. +2
    -0
      data/train/jobs/done/BC-21_0_619_122.csv
  31. +2
    -0
      data/train/jobs/done/BC-21_1_1050_500.csv
  32. +2
    -0
      data/train/jobs/done/BC-21_1_950_750.csv
  33. +2
    -0
      data/train/jobs/done/BC-22_-1_1650_1100.csv
  34. +2
    -0
      data/train/jobs/done/BC-22_-1_170_1418.csv
  35. +2
    -0
      data/train/jobs/done/BC-22_0_534_999.csv
  36. +2
    -0
      data/train/jobs/done/BC-23_0_1580_180.csv
  37. +2
    -0
      data/train/jobs/done/BC-23_1_130_1386.csv
  38. +2
    -0
      data/train/jobs/done/BC-23_1_1800_600.csv
  39. +2
    -0
      data/train/jobs/done/BC-24_1_1900_1400.csv
  40. +2
    -0
      data/train/jobs/done/BC-24_1_2200_1000.csv
  41. +2
    -0
      data/train/jobs/done/BC-25_0_562_239.csv
  42. +2
    -0
      data/train/jobs/done/BC-25_1_1450_600.csv
  43. +2
    -0
      data/train/jobs/done/BC-25_1_2400_300.csv
  44. +2
    -0
      data/train/jobs/done/BC-25_1_2500_1300.csv
  45. +2
    -0
      data/train/jobs/done/P_1356_1256.csv
  46. +2
    -0
      data/train/jobs/done/P_2142_616.csv
  47. +2
    -0
      data/train/jobs/done/P_2491_543.csv
  48. +2
    -0
      data/train/samples/-1_1050_250.csv
  49. +2
    -0
      data/train/samples/-1_1650_1100.csv
  50. +2
    -0
      data/train/samples/-1_170_1418.csv
  51. +2
    -0
      data/train/samples/0_1356_1256.csv
  52. +2
    -0
      data/train/samples/0_1580_180.csv
  53. +2
    -0
      data/train/samples/0_1600_450.csv
  54. +2
    -0
      data/train/samples/0_195_1425.csv
  55. +2
    -0
      data/train/samples/0_2114_796.csv
  56. +2
    -0
      data/train/samples/0_2115_697.csv
  57. +2
    -0
      data/train/samples/0_2142_616.csv
  58. +2
    -0
      data/train/samples/0_2491_543.csv
  59. +2
    -0
      data/train/samples/0_2568_946.csv
  60. +2
    -0
      data/train/samples/0_400_100.csv
  61. +2
    -0
      data/train/samples/0_534_999.csv
  62. +2
    -0
      data/train/samples/0_562_239.csv
  63. +2
    -0
      data/train/samples/0_619_122.csv
  64. +2
    -0
      data/train/samples/1_1050_400.csv
  65. +2
    -0
      data/train/samples/1_1050_500.csv
  66. +2
    -0
      data/train/samples/1_130_1386.csv
  67. +2
    -0
      data/train/samples/1_1450_600.csv
  68. +2
    -0
      data/train/samples/1_1800_600.csv
  69. +2
    -0
      data/train/samples/1_1900_1400.csv
  70. +2
    -0
      data/train/samples/1_2200_1000.csv
  71. +2
    -0
      data/train/samples/1_2400_300.csv
  72. +2
    -0
      data/train/samples/1_2500_1300.csv
  73. +2
    -0
      data/train/samples/1_2750_200.csv
  74. +2
    -0
      data/train/samples/1_950_750.csv
  75. +1
    -0
      docker-compose.yml
  76. +12
    -1
      requirements.txt
  77. +13461
    -8687
      tmp/main_process.log

+ 13
- 18
Dockerfile Wyświetl plik

@@ -1,33 +1,28 @@
FROM python:3.10-slim
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

# dipendenze native utili a numpy/scikit (safe choice)
# Installiamo solo libgomp1 (necessaria per scikit-learn)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential gcc g++ \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt

# Correzione nome pacchetto e upgrade pip
RUN pip install --no-cache-dir --upgrade pip
RUN pip install streamlit==1.29.0 streamlit-drawable-canvas==0.9.3 PyYAML Pillow pandas
RUN pip install --no-cache-dir folium streamlit-folium
RUN pip install --no-cache-dir psutil
# Copia e installazione in un unico step per ridurre i layer
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt

# Copia del resto dell'applicazione
COPY app/ /app/app/
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh

# utente non-root
RUN useradd -m appuser
USER appuser

# cartelle dati/modelli (volumi)
RUN mkdir -p /home/appuser/data /home/appuser/models
ENV DATA_DIR=/home/appuser/data
ENV MODELS_DIR=/home/appuser/models
# Setup utente e permessi
RUN useradd -m appuser && \
mkdir -p /home/appuser/data /home/appuser/models && \
chown -R appuser:appuser /home/appuser /app

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

+ 1
- 1
README.md Wyświetl plik

@@ -411,7 +411,7 @@ curl -k -X 'GET' \
docker compose -p ble-ai-localizer build
docker compose -p ble-ai-localizer up -d --build
docker system prune
docker rmi ble-ai-localizer:0.1.0

Gestione Sart/Stop Container
cd /data/service/ble-ai-localizer


+ 0
- 58
app/leaflet_bridge.js Wyświetl plik

@@ -1,58 +0,0 @@
// leaflet_bridge.js
function initMap(config) {
const { imgUrl, width, height, meta, grid_size, dots } = config;

// Setup Coordinate XY (0,0 in alto a sinistra)
const map = L.map('map', {
crs: L.CRS.Simple,
minZoom: -2,
maxZoom: 4,
attributionControl: false
});

const bounds = [[-height, 0], [0, width]];
L.imageOverlay(imgUrl, bounds).addTo(map);
map.fitBounds(bounds);

// Gestione Griglia
let gridLayer = L.layerGroup();
if (meta.show_grid) {
const step = meta.grid_size || 100;
const S = meta.pixel_ratio || 1;
for (let x = 0; x <= width; x += (step * S)) {
L.polyline([[0, x], [-height, x]], {color: '#ccc', weight: 1, opacity: 0.5}).addTo(gridLayer);
}
for (let y = 0; y >= -height; y -= (step * S)) {
L.polyline([[y, 0], [y, width]], {color: '#ccc', weight: 1, opacity: 0.5}).addTo(gridLayer);
}
gridLayer.addTo(map);
}

// Visualizzazione punti esistenti (Verdi e Blu)
dots.forEach(dot => {
const color = dot.status === 'completed' ? '#228B22' : '#0000FF';
L.circleMarker([dot.y, dot.x], {
radius: config.dot_size / 5,
fillColor: color,
color: 'white',
weight: 2,
fillOpacity: 0.8
}).addTo(map).bindPopup(`X: ${dot.relX}, Y: ${dot.relY}`);
});

// Evento Click per rilievo
map.on('click', function(e) {
const raw_x = e.latlng.lng;
const raw_y = e.latlng.lat; // In Leaflet Simple, Y è negativa sotto l'origine

// Invio dati a Streamlit
window.parent.postMessage({
type: 'streamlit:setComponentValue',
value: {
x: raw_x,
y: raw_y,
timestamp: new Date().getTime()
}
}, '*');
});
}

+ 209
- 41
app/map_manager.py Wyświetl plik

@@ -1,49 +1,217 @@
import os
import json
import streamlit as st
import pandas as pd
from PIL import Image
from pathlib import Path
import time
import folium
from streamlit_folium import st_folium
import math
import base64
from io import BytesIO

def get_image_base64(img):
# --- CACHE IMMAGINE ---
@st.cache_data
def get_image_base64(img_path):
img = Image.open(img_path).convert("RGBA")
w, h = img.size
buffered = BytesIO()
img.save(buffered, format="PNG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return f"data:image/png;base64,{img_str}"
img_str = base64.b64encode(buffered.getvalue()).decode("ascii")
return f"data:image/png;base64,{img_str}", w, h

def show_mapper_v2(cfg):
# ... (caricamento meta e percorsi come nel tuo file originale) ...
img_path = MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}.png"
img = Image.open(img_path).convert("RGBA")
img_width, img_height = img.size
img_b64 = get_image_base64(img)
# --- FUNZIONE SALVATAGGIO FISICO ---
def force_save_json(path, data):
try:
with open(path, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4)
return True
except Exception as e:
st.error(f"Errore scrittura disco: {e}")
return False

# Prepariamo la lista dei punti esistenti (Punto 6 delle specifiche)
dots_data = []
# Qui cicla sui tuoi file CSV e popola dots_data con {x, y, relX, relY, status}
# Integrazione del componente HTML
# Carichiamo il JS dal file esterno
with open("leaflet_bridge.js", "r") as f:
js_code = f.read()

html_content = f"""
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<div id="map" style="height: 600px; width: 100%;"></div>
<script>
{js_code}
initMap({{
imgUrl: "{img_b64}",
width: {img_width},
height: {img_height},
meta: {json.dumps(meta)},
dots: {json.dumps(dots_data)},
dot_size: {dot_size}
}});
</script>
"""
# Il componente restituisce il valore di window.parent.postMessage
result = components.html(html_content, height=650)
def show_mapper(cfg):
MAPS_DIR = Path(cfg['maps']['map_dir'])
SAMPLES_DIR = Path("/data/train/samples")
JOBS_BASE = Path(cfg['collect_train']['jobs_dir'])
PENDING_DIR = JOBS_BASE / "pending"
ERROR_DIR = JOBS_BASE / "error"
BEACONS_FILE = "/data/config/beacons.csv"
[p.mkdir(parents=True, exist_ok=True) for p in [MAPS_DIR, SAMPLES_DIR, PENDING_DIR, ERROR_DIR]]

# --- 1. GESTIONE UPLOAD ---
# La logica ora gestisce stringhe per floor_id permettendo il carattere "-"
maps = sorted([f.replace(cfg['maps']['floor_prefix'], "").split('.')[0]
for f in os.listdir(MAPS_DIR) if f.startswith(cfg['maps']['floor_prefix'])])
if result:
st.write(f"Posizione catturata: {result}")
# Qui inserisci la tua logica di salvataggio CSV che avevi nel punto 7
with st.expander("📂 Carica Nuova Planimetria", expanded=not maps):
c_up1, c_up2 = st.columns([1, 2])
new_f_id = c_up1.text_input("ID Piano (es. 0, -1):", key="new_f_id_v21")
up_file = c_up2.file_uploader("Immagine (PNG/JPG):", type=['png', 'jpg', 'jpeg'], key="up_v21")
if st.button("🚀 SALVA PIANO", use_container_width=True):
if new_f_id and up_file:
ext = Path(up_file.name).suffix
# Il nome file includerà il "-" se presente in new_f_id
img_save_path = MAPS_DIR / f"{cfg['maps']['floor_prefix']}{new_f_id}{ext}"
with open(img_save_path, "wb") as f:
f.write(up_file.getbuffer())
m_path = MAPS_DIR / f"{cfg['maps']['meta_prefix']}{new_f_id}.json"
force_save_json(m_path, {"pixel_ratio": 1.0, "calibrated": False, "origin": [0, 0], "grid_size": 50})
st.session_state.current_floor = new_f_id
st.rerun()

if not maps: return

# --- 2. RIGA STATO ---
c_p, c_s, c_o = st.columns([2.5, 2, 2])
with c_p:
s1, s2 = st.columns([1, 1.2])
s1.markdown("<p style='padding-top:35px; font-weight:bold;'>Piano Attivo:</p>", unsafe_allow_html=True)
def_idx = maps.index(st.session_state.current_floor) if st.session_state.get("current_floor") in maps else 0
floor_id = s2.selectbox("", maps, index=def_idx, key="f_v21", label_visibility="collapsed")
if st.session_state.get("prev_floor") != floor_id:
st.session_state.cal_points = []
st.session_state.temp_lat, st.session_state.temp_lng = None, None
st.session_state.prev_floor = floor_id

meta_path = MAPS_DIR / f"{cfg['maps']['meta_prefix']}{floor_id}.json"
if meta_path.exists():
with open(meta_path, "r") as f: meta = json.load(f)
else:
meta = {"pixel_ratio": 1.0, "calibrated": False, "origin": [0, 0]}

with c_s: st.info(f"📏 Scala: {'✅' if meta['calibrated'] else '❌'}\n({meta['pixel_ratio']:.4f} px/cm)")
with c_o: st.info(f"🎯 Origine: {'✅' if meta['origin'] != [0,0] else '❌'}\n(X:{meta['origin'][0]}, Y:{meta['origin'][1]})")

if not meta["calibrated"] or meta["origin"] == [0, 0]:
st.warning(f"💡 **Piano {floor_id} da configurare**: Esegui **Calibra** e imposta l'**Origine**.")

# --- 3. IMPOSTAZIONI GLOBALI (Default disabilitati) ---
st.markdown("---")
g1, g2, g3, g4 = st.columns([1.2, 1.5, 1.2, 2])
with g1:
# Griglia disattivata di default per evitare interferenze iniziali
show_grid = st.toggle("Griglia", value=False, key="grid_v21")
with g2:
grid_cm = st.select_slider("Passo (cm):", options=[25, 50, 100, 200], value=50, key="step_v21")
with g3:
# Stay Grid disattivato di default
snap_on = st.toggle("Stay Grid", value=False, key="snap_v21")
with g4:
m_size = st.slider("Dimensione Marker:", 5, 20, 8, key="msize_v21")
st.markdown("---")

# --- 4. TOOLSET ---
t1, t2, t3 = st.columns(3)
if t1.button("📏 CALIBRA", use_container_width=True): st.session_state.map_tool = "Calibra"; st.session_state.cal_points = []
if t2.button("🎯 SET ORIGINE", use_container_width=True): st.session_state.map_tool = "Origine"
if t3.button("📡 RILEVA", use_container_width=True): st.session_state.map_tool = "Rileva"
tool = st.session_state.get('map_tool', 'Rileva')

# --- 5. MAPPA ---
col_map, col_ui = st.columns([3, 1])
with col_map:
img_p = next((MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}{e}" for e in ['.png','.jpg','.jpeg'] if (MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}{e}").exists()))
img_data, w, h = get_image_base64(img_p)
bounds = [[0, 0], [h, w]]
m = folium.Map(location=[h/2, w/2], crs="Simple", tiles=None, attribution_control=False)
m.fit_bounds(bounds)
m.options.update({"minZoom": -6, "maxZoom": 6, "zoomSnap": 0.25, "maxBounds": bounds, "maxBoundsViscosity": 1.0})
folium.raster_layers.ImageOverlay(image=img_data, bounds=bounds, interactive=True).add_to(m)

# ORIGINE (Sempre visibile se impostata)
if meta["origin"] != [0, 0]:
ox, oy = meta["origin"]
folium.CircleMarker(location=[oy, ox], radius=6, color="black", fill=True, zindex=1000, tooltip="Origine (0,0)").add_to(m)

# GRIGLIA
if show_grid and meta["calibrated"] and meta["origin"] != [0, 0]:
px_step = grid_cm * meta["pixel_ratio"]
ox, oy = meta["origin"]
for x in sorted(list(range(int(ox), w, int(px_step))) + list(range(int(ox), 0, -int(px_step)))):
folium.PolyLine([[0, x], [h, x]], color="blue", weight=1, opacity=0.1).add_to(m)
for y in sorted(list(range(int(oy), h, int(px_step))) + list(range(int(oy), 0, -int(px_step)))):
folium.PolyLine([[y, 0], [y, w]], color="blue", weight=1, opacity=0.1).add_to(m)

# Disegno Punti Storici
def draw_points(directory, color, shape="circle"):
if not meta["calibrated"] or meta["origin"] == [0,0]: return
for f in Path(directory).glob("*.csv"):
try:
df = pd.read_csv(f, sep=";")
df.columns = [c.lower() for c in df.columns]
# Confronto tra stringhe per gestire piani negativi e ID complessi
if str(df.iloc[0].get('z', df.iloc[0].get('floor'))) == str(floor_id):
px_x = (df.iloc[0]['x'] * meta["pixel_ratio"]) + meta["origin"][0]
px_y = meta["origin"][1] - (df.iloc[0]['y'] * meta["pixel_ratio"])
if shape == "circle": folium.CircleMarker(location=[px_y, px_x], radius=m_size, color=color, fill=True, fill_opacity=0.8).add_to(m)
elif shape == "square": folium.RegularPolygonMarker(location=[px_y, px_x], number_of_sides=4, radius=m_size, color="black", weight=2, fill=True, fill_color=color).add_to(m)
elif shape == "diamond": folium.RegularPolygonMarker(location=[px_y, px_x], number_of_sides=4, rotation=45, radius=m_size, color="black", weight=1, fill=True, fill_color=color).add_to(m)
except: continue

draw_points(SAMPLES_DIR, "green", "circle")
draw_points(PENDING_DIR, "yellow", "diamond")
draw_points(ERROR_DIR, "red", "square")

# Feedback Visivo Click
if tool == "Calibra" and st.session_state.get("cal_points"):
for p in st.session_state.cal_points: folium.CircleMarker(location=p, radius=6, color="red", fill=True).add_to(m)
if len(st.session_state.cal_points) == 2: folium.PolyLine(st.session_state.cal_points, color="red", weight=3).add_to(m)
elif st.session_state.get("temp_lat") is not None:
folium.CircleMarker(location=[st.session_state.temp_lat, st.session_state.temp_lng], radius=m_size+2, color="blue", fill=True, zindex=500).add_to(m)

out = st_folium(m, height=600, width=None, key=f"map_v21_{floor_id}_{tool}")
click = out.get("last_clicked")
if click:
clat, clng = click["lat"], click["lng"]
if tool == "Calibra":
if len(st.session_state.get("cal_points", [])) < 2:
st.session_state.cal_points.append([clat, clng]); st.rerun()
else:
if tool == "Rileva" and snap_on and meta["calibrated"]:
px_step = grid_cm * meta["pixel_ratio"]
st.session_state.temp_lng = meta["origin"][0] + round((clng - meta["origin"][0]) / px_step) * px_step
st.session_state.temp_lat = meta["origin"][1] + round((clat - meta["origin"][1]) / px_step) * px_step
else:
st.session_state.temp_lat, st.session_state.temp_lng = clat, clng
st.rerun()

# --- 6. LOGICA UI ---
with col_ui:
st.write(f"### Tool: **{tool}**")
err_files = list(ERROR_DIR.glob("*.csv"))
if err_files and st.button(f"🗑️ PULISCI ERRORI", use_container_width=True):
for f in err_files: os.remove(f); st.rerun()
if tool == "Calibra":
pts = st.session_state.get("cal_points", [])
if len(pts) == 2:
dist_cm = st.number_input("Distanza reale (cm):", value=100.0)
if st.button("📏 SALVA SCALA", use_container_width=True, type="primary"):
px_d = math.sqrt((pts[1][1]-pts[0][1])**2 + (pts[1][0]-pts[0][0])**2)
meta.update({"pixel_ratio": px_d / dist_cm, "calibrated": True})
if force_save_json(meta_path, meta): st.session_state.cal_points = []; st.rerun()
elif st.session_state.get("temp_lat") is not None:
px_x, px_y = st.session_state.temp_lng, st.session_state.temp_lat
if tool == "Origine":
st.metric("X (px)", int(px_x)); st.metric("Y (px)", int(px_y))
if st.button("💾 SALVA ORIGINE", use_container_width=True, type="primary"):
meta["origin"] = [int(px_x), int(px_y)]
if force_save_json(meta_path, meta): st.rerun()
elif tool == "Rileva" and meta["calibrated"]:
rx = (px_x - meta["origin"][0]) / meta["pixel_ratio"]
ry = (meta["origin"][1] - px_y) / meta["pixel_ratio"]
sx, sy = int(round(rx)), int(round(ry))
st.metric("X (cm)", sx); st.metric("Y (cm)", sy)
if os.path.exists(BEACONS_FILE):
b_df = pd.read_csv(BEACONS_FILE, sep=";")
sel_b = st.selectbox("Beacon:", b_df.apply(lambda x: f"{x['BeaconName']} | {x['MAC']}", axis=1))
if st.button("🚀 REGISTRA", use_container_width=True, type="primary"):
b_name, b_mac = sel_b.split(" | ")
id_str = f"{b_name}_{floor_id}_{sx}_{sy}"
# Salvataggio Z come stringa per mantenere il "-"
data = {"Position": id_str, "Floor": floor_id, "RoomName": b_name, "X": sx, "Y": sy, "Z": floor_id, "BeaconName": b_name, "MAC": b_mac}
pd.DataFrame([data]).to_csv(PENDING_DIR / f"{id_str}.csv", sep=";", index=False); st.rerun()

+ 0
- 145
app/map_manager.py_v1 Wyświetl plik

@@ -1,145 +0,0 @@
import os
import json
import streamlit as st
import pandas as pd
from PIL import Image, ImageDraw
from pathlib import Path
from streamlit_drawable_canvas import st_canvas
import time

def show_mapper(cfg):
# --- 1. CONFIGURAZIONE PERCORSI ---
MAPS_DIR = Path(cfg['maps']['map_dir'])
SAMPLES_DIR = Path(cfg['train']['samples_dir'])
PENDING_DIR = Path(cfg['collect_train']['jobs_dir']) / "pending"
BEACONS_FILE = "/data/config/beacons.csv"

[p.mkdir(parents=True, exist_ok=True) for p in [MAPS_DIR, SAMPLES_DIR, PENDING_DIR]]

def load_map_metadata(f_id):
meta_path = MAPS_DIR / f"{cfg['maps']['meta_prefix']}{f_id}.json"
defaults = {"pixel_ratio": 1.0, "calibrated": False, "origin": [0, 0], "grid_size": 50}
if meta_path.exists():
with open(meta_path, "r") as f: return {**defaults, **json.load(f)}
return defaults

st.subheader("🗺️ Gestione Mappatura e Rilevamento")

# Selezione Piano
maps = sorted([f.replace(cfg['maps']['floor_prefix'], "").split('.')[0] for f in os.listdir(MAPS_DIR) if f.startswith(cfg['maps']['floor_prefix'])])
if not maps: st.error("Nessuna mappa trovata."); return
floor_id = st.selectbox("Seleziona Piano (Z):", maps)
meta = load_map_metadata(floor_id)

# --- 2. STATO SISTEMA ---
c_s1, c_s2 = st.columns(2)
with c_s1:
st.info(f"📏 Scala: {'✅' if meta['calibrated'] else '❌'} ({meta['pixel_ratio']:.4f} px/cm)")
with c_s2:
st.info(f"🎯 Origine: {'✅' if meta['origin'] != [0,0] else '❌'} (X:{meta['origin'][0]}, Y:{meta['origin'][1]})")

# --- 3. CONTROLLI VISUALIZZAZIONE ---
with st.expander("🎨 Opzioni Visualizzazione", expanded=True):
c_v1, c_v2, c_v3 = st.columns(3)
zoom = c_v1.slider("🔍 Zoom Mappa", 0.1, 4.0, 1.0, 0.1)
dot_size = c_v2.slider("🔵/🟢 Dimensione Punti", 10, 100, 40)
mode = c_v3.radio("Modalità Interazione:", ["🖐️ NAVIGA", "🎯 AZIONE"], horizontal=True)

# --- 4. SELEZIONE STRUMENTO ---
t1, t2, t3 = st.columns(3)
if t1.button("📏 IMPOSTA SCALA", use_container_width=True): st.session_state.map_tool = "Calibra"
if t2.button("🎯 SET ORIGINE", use_container_width=True): st.session_state.map_tool = "Origine"
is_ready = meta.get("calibrated", False) and meta["origin"] != [0, 0]
if t3.button("📡 RILEVA", use_container_width=True, disabled=not is_ready): st.session_state.map_tool = "Rileva"

tool = st.session_state.get('map_tool', 'Rileva')
st.write(f"Strumento attivo: **{tool}**")

# --- 5. PREPARAZIONE IMMAGINE E STORICO ---
img_path = MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}.png"
if not img_path.exists(): img_path = MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}.jpg"
img = Image.open(img_path).convert("RGBA")
draw = ImageDraw.Draw(img)

if is_ready:
samples_files = list(SAMPLES_DIR.glob(f"{floor_id}_*.csv"))
pending_files = list(PENDING_DIR.glob(f"{floor_id}_*.csv"))
def draw_points(files, color):
for f in files:
try:
p = f.stem.split("_")
px = (int(p[1]) * meta["pixel_ratio"]) + meta["origin"][0]
py = (int(p[2]) * meta["pixel_ratio"]) + meta["origin"][1]
r = dot_size // 2
draw.ellipse([px-r, py-r, px+r, py+r], fill=color, outline="white", width=2)
except: continue

draw_points(samples_files, "#228B22") # Verde: Completati
draw_points(pending_files, "#0000FF") # Blu: In corso

# --- 6. CANVAS ---
d_mode = "transform" if mode == "🖐️ NAVIGA" else ("line" if tool == "Calibra" else "point")
canvas_result = st_canvas(
background_image=img,
height=int(img.size[1] * zoom),
width=int(img.size[0] * zoom),
drawing_mode=d_mode,
display_toolbar=True,
update_streamlit=True,
key=f"canvas_v10_{floor_id}_{zoom}_{mode}_{tool}",
)

# --- 7. LOGICA AZIONI E SALVATAGGIO CSV ---
if mode == "🎯 AZIONE" and canvas_result.json_data and canvas_result.json_data["objects"]:
last = canvas_result.json_data["objects"][-1]
raw_x, raw_y = last["left"] / zoom, last["top"] / zoom

if tool == "Calibra" and last["type"] == "line":
px_dist = ((last["x2"] - last["x1"])**2 + (last["y2"] - last["y1"])**2)**0.5 / zoom
dist_cm = st.number_input("Distanza reale (cm):", value=100.0)
if st.button("APPLICA SCALA"):
meta.update({"pixel_ratio": px_dist / dist_cm, "calibrated": True})
with open(MAPS_DIR / f"{cfg['maps']['meta_prefix']}{floor_id}.json", "w") as f:
json.dump(meta, f)
st.rerun()

elif tool == "Origine":
if st.button(f"Fissa Origine qui: {int(raw_x)}, {int(raw_y)}"):
meta["origin"] = [int(raw_x), int(raw_y)]
with open(MAPS_DIR / f"{cfg['maps']['meta_prefix']}{floor_id}.json", "w") as f:
json.dump(meta, f)
st.rerun()

elif tool == "Rileva" and is_ready:
dx = (raw_x - meta["origin"][0]) / meta["pixel_ratio"]
dy = (raw_y - meta["origin"][1]) / meta["pixel_ratio"]
grid = meta.get("grid_size", 50)
sx, sy = int(round(dx/grid)*grid), int(round(dy/grid)*grid)
st.write(f"### 📍 Punto: {sx}cm, {sy}cm")
if os.path.exists(BEACONS_FILE):
b_df = pd.read_csv(BEACONS_FILE, sep=";")
sel_b = st.selectbox("Seleziona Beacon:", b_df.apply(lambda x: f"{x['BeaconName']} | {x['MAC']}", axis=1))
if st.button("🚀 REGISTRA LETTURA", type="primary", use_container_width=True):
b_name, b_mac = sel_b.split(" | ")
fname = f"{floor_id}_{sx}_{sy}.csv"
# --- FIX SINTASSI CSV ---
# Formato: Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
data_out = {
"Position": f"P_{sx}_{sy}",
"Floor": floor_id,
"RoomName": "Area_Rilevazione",
"X": sx,
"Y": sy,
"Z": 0,
"BeaconName": b_name,
"MAC": b_mac
}
pd.DataFrame([data_out]).to_csv(PENDING_DIR / fname, index=False, sep=";")
st.toast(f"Punto Blu registrato!")
time.sleep(1); st.rerun()

+ 0
- 49
app/map_manager.py_v2 Wyświetl plik

@@ -1,49 +0,0 @@
import base64
from io import BytesIO

def get_image_base64(img):
buffered = BytesIO()
img.save(buffered, format="PNG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return f"data:image/png;base64,{img_str}"

def show_mapper_v2(cfg):
# ... (caricamento meta e percorsi come nel tuo file originale) ...
img_path = MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}.png"
img = Image.open(img_path).convert("RGBA")
img_width, img_height = img.size
img_b64 = get_image_base64(img)

# Prepariamo la lista dei punti esistenti (Punto 6 delle specifiche)
dots_data = []
# Qui cicla sui tuoi file CSV e popola dots_data con {x, y, relX, relY, status}
# Integrazione del componente HTML
# Carichiamo il JS dal file esterno
with open("leaflet_bridge.js", "r") as f:
js_code = f.read()

html_content = f"""
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<div id="map" style="height: 600px; width: 100%;"></div>
<script>
{js_code}
initMap({{
imgUrl: "{img_b64}",
width: {img_width},
height: {img_height},
meta: {json.dumps(meta)},
dots: {json.dumps(dots_data)},
dot_size: {dot_size}
}});
</script>
"""
# Il componente restituisce il valore di window.parent.postMessage
result = components.html(html_content, height=650)
if result:
st.write(f"Posizione catturata: {result}")
# Qui inserisci la tua logica di salvataggio CSV che avevi nel punto 7

+ 83
- 81
app/web_inference.py Wyświetl plik

@@ -1,100 +1,102 @@
import streamlit as st
import pandas as pd
import os
import json
from PIL import Image, ImageDraw, ImageFont
import folium
from streamlit_folium import st_folium
from pathlib import Path
import time
import os
from PIL import Image
import base64
from io import BytesIO

# --- UTILS ---
@st.cache_data
def get_image_base64(img_path):
img = Image.open(img_path).convert("RGBA")
w, h = img.size
buffered = BytesIO()
img.save(buffered, format="PNG")
img_str = base64.b64encode(buffered.getvalue()).decode("ascii")
return f"data:image/png;base64,{img_str}", w, h

def show_inference_page(cfg):
# Definizione percorsi
# Assumendo che il file sia in /app/app/web_inference.py,
# cerchiamo il font nella stessa cartella 'app'
BASE_DIR = Path(__file__).parent
st.subheader("📡 Monitoraggio Beacon Real-Time")
# --- CONFIGURAZIONE PERCORSI ---
MAPS_DIR = Path(cfg['maps']['map_dir'])
INFER_FILE = Path(cfg['infer']['output_dir']) / cfg['infer']['out_file']
INFER_FILE = Path("/data/infer/infer.csv")
# Percorso del font locale
FONT_PATH = BASE_DIR / "DejaVuSans-Bold.ttf"

st.subheader("🤖 Monitoraggio Inferenza Live")
# --- 1. SELEZIONE E STATO (RIGA COMPATTA) ---
maps = sorted([f.replace(cfg['maps']['floor_prefix'], "").split('.')[0]
for f in os.listdir(MAPS_DIR) if f.startswith(cfg['maps']['floor_prefix'])])
if not maps:
st.warning("Nessuna mappa configurata.")
return

# --- CONTROLLI NEL TAB ---
with st.expander("🎨 Opzioni e Controllo", expanded=True):
col_ctrl1, col_ctrl2, col_ctrl3, col_ctrl4 = st.columns(4)
with col_ctrl1:
dot_size = st.slider("Dimensione Marker", 10, 100, 45, key="inf_dot")
with col_ctrl2:
refresh_rate = st.select_slider("Refresh (s)", options=[2, 5, 10, 30], value=5, key="inf_ref")
with col_ctrl3:
show_labels = st.checkbox("Mostra MAC", value=True, key="inf_show_mac")
with col_ctrl4:
# Monitoraggio disattivato di default per evitare login fantasma
auto_refresh = st.toggle("🔄 Monitoraggio Attivo", value=False, key="inf_auto")
# Lettura dati per conteggio
df_infer = pd.DataFrame()
if INFER_FILE.exists():
df_infer = pd.read_csv(INFER_FILE, sep=";")

floor_id = st.number_input("Piano (Z)", value=0, min_value=0, step=1, key="inf_z")
# Layout riga 1
c_piano, c_count, c_size = st.columns([3, 2, 2])
with c_piano:
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)
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()

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

with c_size:
# Slider per dimensione pallini (come nel mapper)
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 = {"pixel_ratio": 1.0, "origin": [0, 0]}
if meta_path.exists():
with open(meta_path, "r") as f:
meta.update(json.load(f))
if not meta_path.exists(): return
with open(meta_path, "r") as f: meta = json.load(f)

# --- 2. RENDERING MAPPA ---
st.markdown("---")
img_p = next((MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}{e}" for e in ['.png','.jpg'] if (MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}{e}").exists()))
img_data, w, h = get_image_base64(img_p)
bounds = [[0, 0], [h, w]]
m = folium.Map(location=[h/2, w/2], crs="Simple", tiles=None, attribution_control=False)
m.fit_bounds(bounds)
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)

try:
if INFER_FILE.exists():
df = pd.read_csv(INFER_FILE, sep=";")
df_active = df[(df['z'] == floor_id) & (df['x'] != -1) & (df['y'] != -1)]
img_path = MAPS_DIR / f"{cfg['maps']['floor_prefix']}{floor_id}.png"
if img_path.exists():
img = Image.open(img_path).convert("RGBA")
draw = ImageDraw.Draw(img)
# Disegno Beacon
if meta["calibrated"] and meta["origin"] != [0,0]:
# Origine
folium.CircleMarker(location=[meta["origin"][1], meta["origin"][0]], radius=4, color="black", fill=True).add_to(m)

# --- GESTIONE FONT XL ---
# Dimensione proporzionale al pallino (1.5x)
dynamic_font_size = int(dot_size * 1.5)
font = None
if FONT_PATH.exists():
try:
# Tenta il caricamento del file TTF locale
font = ImageFont.truetype(str(FONT_PATH), dynamic_font_size)
except Exception as e:
# Se il file è corrotto (unknown file format), mostra errore e usa fallback
st.error(f"Errore caricamento font: {e}. Controlla il file DejaVuSans-Bold.ttf")
if font is None:
font = ImageFont.load_default()
for _, row in df_active.iterrows():
px_x = (row['x'] * meta["pixel_ratio"]) + meta["origin"][0]
px_y = meta["origin"][1] - (row['y'] * meta["pixel_ratio"])
mac_label = str(row['mac'])[-5:]

for _, row in df_active.iterrows():
px_x = (row['x'] * meta["pixel_ratio"]) + meta["origin"][0]
px_y = (row['y'] * meta["pixel_ratio"]) + meta["origin"][1]
folium.CircleMarker(
location=[px_y, px_x], radius=m_size, color="blue",
fill=True, fill_color="cyan", fill_opacity=0.8
).add_to(m)

r = dot_size
# Disegno Marker
draw.ellipse([px_x-(r+5), px_y-(r+5), px_x+(r+5), px_y+(r+5)], fill="black")
draw.ellipse([px_x-r, px_y-r, px_x+r, px_y+r], fill="#00E5FF")
if show_labels:
label = f"{str(row['mac'])[-5:]}"
# Posizionamento dinamico a destra del pallino
text_x = px_x + r + 20
text_y = px_y - (dynamic_font_size / 2)
# Outline per leggibilità (bordo nero spesso 3px)
for dx, dy in [(-3,-3), (3,-3), (-3,3), (3,3), (0,-3), (0,3), (-3,0), (2,0)]:
draw.text((text_x + dx, text_y + dy), label, font=font, fill="black")
# Testo Giallo
draw.text((text_x, text_y), label, font=font, fill="#FFFF00")
folium.Marker(
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>""")
).add_to(m)

st.image(img, use_column_width=True)
st.metric("Dispositivi Online", len(df_active))
except Exception as e:
st.error(f"Errore generale: {e}")
st_folium(m, height=700, width=None, key=f"inf_map_v24_{floor_id}", use_container_width=True)

# --- REFRESH CONDIZIONALE ---
if auto_refresh:
time.sleep(refresh_rate)
st.rerun()
# --- 3. TABELLA RIEPILOGO COMPLETA ---
if not df_infer.empty:
st.subheader("Dettaglio Dispositivi (Tutti i Piani)")
# Aggiunta colonna Z per chiarezza
st.dataframe(df_infer[['mac', 'z', 'x', 'y']], use_container_width=True)

+ 4
- 1
app/web_suite.py Wyświetl plik

@@ -27,7 +27,7 @@ st.set_page_config(
menu_items={
'Get Help': None,
'Report a bug': None,
'About': "# ▒~_~[▒▒~O BLE AI Localizer - Suite\nSistema professionale di posizionamento BLE."
'About': "🛰️BLE AI Localizer - Suite\nSistema professionale di posizionamento BLE."
}
)

@@ -44,6 +44,9 @@ st.markdown("""
</style>
""", unsafe_allow_html=True)

if "main_login_user" not in st.session_state:
st.session_state["main_login_user"] = ""

# --- LOGIN (Tua versione originale) ---
if "password_correct" not in st.session_state:
st.session_state["password_correct"] = False


+ 4
- 4
config/config.yaml Wyświetl plik

@@ -63,18 +63,18 @@ infer:
window_seconds: 5
xy_round: 0
maps:
default_dot_size: 20
default_grid_size: 100
floor_prefix: floor_
map_dir: /data/maps
meta_prefix: meta_
default_grid_size: 100 # Dimensione griglia predefinita in cm
default_dot_size: 20 # Dimensione predefinita dei marker
show_grid_default: true # Stato iniziale della griglia
show_grid_default: true
ml:
k: 5
method: knn
metric: euclidean
weights: distance
mode: infer
mode: collect_train
mqtt:
ca_file: ''
client_id: ble-ai-localizer


+ 9
- 9
data/infer/infer.csv Wyświetl plik

@@ -1,13 +1,13 @@
mac;z;x;y
C8:3F:8F:17:DB:35;1;1061;1290
C8:3F:8F:17:DB:35;1;1058;1294
C3:00:00:39:47:DF;-1;-1;-1
C3:00:00:39:47:C4;1;1386;1501
C3:00:00:39:47:C4;1;1304;1478
C3:00:00:39:47:E2;-1;-1;-1
C7:AE:56:1E:38:B7;1;1311;1501
C7:AE:56:1E:38:B7;1;1323;1499
E0:1F:9A:7A:47:D2;-1;-1;-1
C3:00:00:57:B9:D9;1;1060;1380
C3:00:00:57:B9:DB;1;1056;1383
C3:00:00:57:B9:F4;1;1061;1292
C3:00:00:57:B9:DC;1;1060;1294
C3:00:00:57:B9:DD;1;1216;1444
C3:00:00:57:B9:DF;1;1059;1296
C3:00:00:57:B9:D9;1;1058;1382
C3:00:00:57:B9:DB;1;1060;1293
C3:00:00:57:B9:F4;1;1059;1296
C3:00:00:57:B9:DC;1;1060;1291
C3:00:00:57:B9:DD;1;1203;1452
C3:00:00:57:B9:DF;1;1061;1294

BIN
data/maps.bck/floor_0.png Wyświetl plik

Przed Po
Szerokość: 8337  |  Wysokość: 4803  |  Rozmiar: 528 KiB

BIN
data/maps.bck/floor_1.png Wyświetl plik

Przed Po
Szerokość: 8238  |  Wysokość: 4672  |  Rozmiar: 556 KiB

+ 1
- 0
data/maps.bck/meta_0.json Wyświetl plik

@@ -0,0 +1 @@
{"pixel_ratio": 1.5843674344166205, "calibrated": true, "origin": [1296, 3744], "grid_size": 50, "show_grid": true}

+ 1
- 0
data/maps.bck/meta_1.json Wyświetl plik

@@ -0,0 +1 @@
{"pixel_ratio": 1.5919341046277666, "calibrated": true, "origin": [1251, 1143], "grid_size": 50}

BIN
data/maps.old/floor_0.png Wyświetl plik

Przed Po
Szerokość: 8337  |  Wysokość: 4803  |  Rozmiar: 528 KiB

BIN
data/maps.old/floor_1.png Wyświetl plik

Przed Po
Szerokość: 8238  |  Wysokość: 4672  |  Rozmiar: 556 KiB

+ 9
- 0
data/maps.old/meta_0.json Wyświetl plik

@@ -0,0 +1,9 @@
{
"pixel_ratio": 1.584476207254857,
"calibrated": true,
"origin": [
1248,
3790
],
"grid_size": 50
}

+ 1
- 0
data/maps.old/meta_1.json Wyświetl plik

@@ -0,0 +1 @@
{"pixel_ratio": 1.5924732396126005, "calibrated": true, "origin": [1297, 3586], "grid_size": 50}

BIN
data/maps/floor_-1.png Wyświetl plik

Przed Po
Szerokość: 8238  |  Wysokość: 4672  |  Rozmiar: 556 KiB

+ 9
- 0
data/maps/meta_-1.json Wyświetl plik

@@ -0,0 +1,9 @@
{
"pixel_ratio": 1.5920551746472242,
"calibrated": true,
"origin": [
1297,
3587
],
"grid_size": 50
}

+ 9
- 1
data/maps/meta_0.json Wyświetl plik

@@ -1 +1,9 @@
{"pixel_ratio": 1.574668658056015, "calibrated": true, "origin": [1193, 1031], "grid_size": 50, "show_grid": true}
{
"pixel_ratio": 1.584773230620443,
"calibrated": true,
"origin": [
1247,
3791
],
"grid_size": 50
}

+ 9
- 1
data/maps/meta_1.json Wyświetl plik

@@ -1 +1,9 @@
{"pixel_ratio": 1.5919341046277666, "calibrated": true, "origin": [1251, 1143], "grid_size": 50}
{
"pixel_ratio": 1.5924129560451799,
"calibrated": true,
"origin": [
1297,
3587
],
"grid_size": 50
}

data/train/jobs/pending/1_1600_450.csv → data/train/jobs/done/1_1600_450.csv Wyświetl plik


+ 2
- 0
data/train/jobs/done/BC-21_-1_1050_250.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_-1_1050_250;-1;BC-21;1050;250;-1;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_0_195_1425.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_0_195_1425;0;BC-21;195;1425;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_0_2114_796.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_0_2114_796;0;BC-21;2114;796;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_0_2115_697.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
P_2115_697;0;BC-21;2115;697;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_0_2568_946.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_0_2568_946;0;BC-21;2568;946;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_0_400_100.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_0_400_100;0;BC-21;400;100;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_0_619_122.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_0_619_122;0;BC-21;619;122;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_1_1050_500.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_1_1050_500;1;BC-21;1050;500;1;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-21_1_950_750.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-21_1_950_750;1;BC-21;950;750;1;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/BC-22_-1_1650_1100.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-22_-1_1650_1100;-1;BC-22;1650;1100;-1;BC-22;C3:00:00:57:B9:D4

+ 2
- 0
data/train/jobs/done/BC-22_-1_170_1418.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-22_-1_170_1418;-1;BC-22;170;1418;-1;BC-22;C3:00:00:57:B9:D4

+ 2
- 0
data/train/jobs/done/BC-22_0_534_999.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-22_0_534_999;0;BC-22;534;999;0;BC-22;C3:00:00:57:B9:D4

+ 2
- 0
data/train/jobs/done/BC-23_0_1580_180.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-23_0_1580_180;0;BC-23;1580;180;0;BC-23;C3:00:00:57:B9:E8

+ 2
- 0
data/train/jobs/done/BC-23_1_130_1386.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-23_1_130_1386;1;BC-23;130;1386;1;BC-23;C3:00:00:57:B9:E8

+ 2
- 0
data/train/jobs/done/BC-23_1_1800_600.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-23_1_1800_600;1;BC-23;1800;600;1;BC-23;C3:00:00:57:B9:E8

+ 2
- 0
data/train/jobs/done/BC-24_1_1900_1400.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-24_1_1900_1400;1;BC-24;1900;1400;1;BC-24;C3:00:00:57:B9:F1

+ 2
- 0
data/train/jobs/done/BC-24_1_2200_1000.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-24_1_2200_1000;1;BC-24;2200;1000;1;BC-24;C3:00:00:57:B9:F1

+ 2
- 0
data/train/jobs/done/BC-25_0_562_239.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-25_0_562_239;0;BC-25;562;239;0;BC-25;C3:00:00:57:B9:E7

+ 2
- 0
data/train/jobs/done/BC-25_1_1450_600.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-25_1_1450_600;1;BC-25;1450;600;1;BC-25;C3:00:00:57:B9:E7

+ 2
- 0
data/train/jobs/done/BC-25_1_2400_300.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-25_1_2400_300;1;BC-25;2400;300;1;BC-25;C3:00:00:57:B9:E7

+ 2
- 0
data/train/jobs/done/BC-25_1_2500_1300.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
BC-25_1_2500_1300;1;BC-25;2500;1300;1;BC-25;C3:00:00:57:B9:E7

+ 2
- 0
data/train/jobs/done/P_1356_1256.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
P_1356_1256;0;BC-21;1356;1256;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/P_2142_616.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
P_2142_616;0;BC-21;2142;616;0;BC-21;C3:00:00:57:B9:E6

+ 2
- 0
data/train/jobs/done/P_2491_543.csv Wyświetl plik

@@ -0,0 +1,2 @@
Position;Floor;RoomName;X;Y;Z;BeaconName;MAC
P_2491_543;0;BC-22;2491;543;0;BC-22;C3:00:00:57:B9:D4

+ 2
- 0
data/train/samples/-1_1050_250.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;1050;250;-1;-72.000;-82.000;-75.000;nan;nan;nan;nan;nan;-80.000;-51.500;-74.000;-64.000;-73.000;-77.000;nan;-76.000

+ 2
- 0
data/train/samples/-1_1650_1100.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:D4;1650;1100;-1;-77.000;nan;-78.000;nan;nan;nan;nan;nan;-76.000;nan;-75.000;-67.000;-76.000;-78.000;-83.000;-73.500

+ 2
- 0
data/train/samples/-1_170_1418.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:D4;170;1418;-1;-77.000;nan;-79.000;nan;-85.000;nan;nan;nan;-74.000;nan;-73.000;-67.000;-76.000;-78.000;-83.000;-74.000

+ 2
- 0
data/train/samples/0_1356_1256.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;1356;1256;0;-72.000;-82.000;-75.500;nan;nan;nan;nan;nan;-80.000;-51.000;-74.000;-64.500;-70.000;-79.000;nan;-75.500

+ 2
- 0
data/train/samples/0_1580_180.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E8;1580;180;0;-80.000;-82.000;-83.500;nan;-85.500;nan;nan;nan;-76.000;-59.000;-71.000;-64.000;-77.000;-78.000;-85.000;-74.000

+ 2
- 0
data/train/samples/0_1600_450.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;1600;450;0;-72.000;-82.000;-75.000;nan;nan;nan;nan;nan;-81.000;-51.500;-75.000;-64.000;-73.000;-77.500;nan;-76.000

+ 2
- 0
data/train/samples/0_195_1425.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;195;1425;0;-76.000;-82.000;-75.000;nan;nan;nan;nan;nan;-80.000;-52.000;-74.000;-64.000;-70.000;-78.000;nan;-76.000

+ 2
- 0
data/train/samples/0_2114_796.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;2114;796;0;-72.000;-82.000;-76.000;nan;nan;nan;nan;nan;-80.000;-52.000;-75.000;-64.000;-70.500;-78.000;nan;-75.000

+ 2
- 0
data/train/samples/0_2115_697.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;2115;697;0;-76.000;-82.000;-76.000;nan;nan;nan;nan;nan;-80.000;-52.000;-75.000;-64.000;-71.000;-77.000;nan;-76.000

+ 2
- 0
data/train/samples/0_2142_616.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;2142;616;0;-77.000;-82.000;-76.000;nan;nan;nan;nan;nan;-80.000;-52.000;-75.000;-64.000;-72.000;-78.000;nan;-76.000

+ 2
- 0
data/train/samples/0_2491_543.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:D4;2491;543;0;-77.000;nan;-79.000;nan;-84.000;nan;nan;nan;-74.000;nan;-75.000;-67.000;-77.000;-78.000;-83.000;-73.000

+ 2
- 0
data/train/samples/0_2568_946.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;2568;946;0;-76.000;-83.000;-76.000;nan;nan;nan;nan;nan;-80.000;-51.000;-74.500;-64.000;-73.000;-77.000;nan;-76.000

+ 2
- 0
data/train/samples/0_400_100.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;400;100;0;-77.000;-83.000;-75.000;nan;nan;nan;nan;nan;-80.000;-51.000;-76.000;-64.000;-73.000;-78.000;nan;-76.000

+ 2
- 0
data/train/samples/0_534_999.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:D4;534;999;0;-77.000;nan;-79.000;nan;-84.000;nan;nan;nan;-76.000;nan;-73.500;-66.000;-76.000;-78.000;-83.000;-73.000

+ 2
- 0
data/train/samples/0_562_239.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E7;562;239;0;-83.500;nan;-83.000;nan;nan;nan;nan;nan;-78.000;-48.000;-71.000;-75.000;-74.000;-78.500;-83.000;-80.000

+ 2
- 0
data/train/samples/0_619_122.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;619;122;0;-72.000;-82.000;-75.000;nan;nan;nan;nan;nan;-80.000;-52.000;-75.500;-64.000;-73.000;-78.000;nan;-76.000

+ 2
- 0
data/train/samples/1_1050_400.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:F1;1050;400;1;nan;nan;nan;nan;nan;nan;nan;nan;-77.000;nan;-69.000;-65.000;-71.000;-77.000;-82.000;-81.000

+ 2
- 0
data/train/samples/1_1050_500.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;1050;500;1;-76.000;-82.000;-75.000;nan;nan;nan;nan;nan;-80.000;-51.000;-75.000;-64.000;-73.000;-77.000;nan;-76.000

+ 2
- 0
data/train/samples/1_130_1386.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E8;130;1386;1;-80.000;-82.000;-84.000;nan;-85.000;nan;nan;nan;-76.000;-59.000;-71.000;-64.000;-77.000;-78.000;-85.000;-74.000

+ 2
- 0
data/train/samples/1_1450_600.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E7;1450;600;1;-83.500;nan;-83.000;nan;nan;nan;nan;nan;-79.000;-48.000;-71.000;-75.000;-77.000;-77.000;-83.000;-80.000

+ 2
- 0
data/train/samples/1_1800_600.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E8;1800;600;1;-80.000;-82.000;-83.000;nan;nan;nan;nan;nan;-76.000;-59.000;-71.000;-64.000;-76.500;-79.000;-84.500;-72.000

+ 2
- 0
data/train/samples/1_1900_1400.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:F1;1900;1400;1;nan;nan;nan;nan;nan;nan;nan;nan;-77.000;nan;-69.000;-65.000;-71.000;-77.000;-82.000;-81.000

+ 2
- 0
data/train/samples/1_2200_1000.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:F1;2200;1000;1;nan;nan;nan;nan;nan;nan;nan;nan;-77.000;nan;-69.000;-65.000;-71.000;-78.000;-82.000;-81.000

+ 2
- 0
data/train/samples/1_2400_300.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E7;2400;300;1;-83.000;nan;-83.000;nan;nan;nan;nan;nan;-78.000;-48.000;-71.000;-76.500;-77.000;-77.000;-83.000;-80.000

+ 2
- 0
data/train/samples/1_2500_1300.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E7;2500;1300;1;-84.000;nan;-83.000;nan;nan;nan;nan;nan;-79.000;-48.000;-71.000;-77.000;-77.000;-77.500;-83.000;-80.000

+ 2
- 0
data/train/samples/1_2750_200.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;2750;200;1;-72.000;-83.000;-76.000;nan;nan;nan;nan;nan;-80.000;-51.000;-74.500;-64.000;-70.000;-78.000;nan;-76.000

+ 2
- 0
data/train/samples/1_950_750.csv Wyświetl plik

@@ -0,0 +1,2 @@
mac;x;y;z;AC:23:3F:C1:DD:3C;AC:23:3F:C1:DD:49;AC:23:3F:C1:DC:EE;AC:23:3F:C1:DD:40;AC:23:3F:C1:DD:51;AC:23:3F:C1:DD:48;AC:23:3F:C1:DD:50;AC:23:3F:C1:DC:D3;AC:23:3F:C1:DD:55;AC:23:3F:C1:DC:D1;AC:23:3F:C1:DC:CB;AC:23:3F:C1:DC:D2;AC:23:3F:C1:DD:31;AC:23:3F:C1:DD:4B;AC:23:3F:C1:DD:4E;AC:23:3F:C1:DC:CD
C3:00:00:57:B9:E6;950;750;1;-72.000;-82.000;-75.500;nan;nan;nan;nan;nan;-80.000;-52.000;-74.000;-64.000;-71.500;-77.000;nan;-76.000

+ 1
- 0
docker-compose.yml Wyświetl plik

@@ -3,6 +3,7 @@ services:
build: .
image: ble-ai-localizer:0.1.0
environment:
PYTHONWARNINGS: "ignore:Unverified HTTPS request"
CONFIG: "/config/config.yaml" # Nome usato da main.py
SECRETS_FILE: "/config/secrets.yaml"
UI_USER: "Admin"


+ 12
- 1
requirements.txt Wyświetl plik

@@ -1,14 +1,25 @@
pandas==2.2.2
# --- CORE AI & DATA ---
numpy==1.26.4
scikit-learn==1.5.1
joblib==1.4.2
pandas==2.2.2
pyarrow==15.0.0

# --- COMUNICAZIONE & SISTEMA ---
paho-mqtt==2.1.0
requests==2.32.3
PyYAML==6.0.2
psutil==5.9.8
pathlib==1.0.1

# --- WEB & MAPPE ---
streamlit==1.49.1
pillow==10.2.0
fastapi==0.115.0
uvicorn[standard]==0.30.6
folium==0.15.1
streamlit-folium==0.26.1

# --- VISUALIZZAZIONE ---
matplotlib==3.9.2
seaborn==0.13.2

+ 13461
- 8687
tmp/main_process.log
Plik diff jest za duży
Wyświetl plik


Ładowanie…
Anuluj
Zapisz