From ad31e2289f3b38b1d2349a9577fd1f44d1bf8c14 Mon Sep 17 00:00:00 2001 From: Eric FELIXINE Date: Tue, 5 May 2026 21:24:29 -0400 Subject: [PATCH] fix: replace random coords with fixed Martinique locations (no more sea sensors) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace random.uniform(±0.02°) with FIXED_LOCATIONS dict keyed by type+name - All 30 named sensor locations mapped to real Martinique coordinates on land - Coordonnées Martinique: 14.4°N–14.88°N, -61.25°W–-60.85°W - OpenRemote DB: UPDATE all IOTSensor assets with wrong coords (PostgreSQL jsonb_set) - All 34 sensor instances now validated as TERRE (100% on land) Fixed sensors: traffic, airquality, parking, noise, weather, light --- simulator.py | 91 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/simulator.py b/simulator.py index 96854eac..87ba419e 100644 --- a/simulator.py +++ b/simulator.py @@ -117,41 +117,82 @@ if "SENSOR_COUNT" in os.environ: SENSOR_COUNTS[k] = max(1, int(SENSOR_COUNTS[k] * ratio)) # ============================================================================= -# Localisation des capteurs Martinique +# Localisation des capteurs Martinique — Coordonnées FIXES sur terre ferme +# IMPORTANT : ±0.02° autour de Fort-de-France donne ~2km, or Martinique fait +# ~60km de long — certains points tombent en mer. Solution : coordonnées fixes. # ============================================================================= -SENSOR_LOCATIONS: dict[str, list[dict]] = {} -SENSOR_NAMES: dict[str, list[str]] = { - "traffic": ["Carrefour Central", "Avenue des Caraïbes", "Boulevard Pasteur", - "Rue des Flamboyants", "Place de la République"], - "airquality": ["Quartier Bonde", "Port de Fort-de-France", "Château Denis", - "Lamentin Aéroport", "Schoelcher Village"], - "parking": ["Parking Rivière-Saleé", "Parking Cluny", "Parking Média", - "Parking Grand-Camp", "Parking Dillon"], - "noise": ["Rue des Arts", "Marché Central", "Université Fort-de-France", - "Stade de Dillon", "Place du Champs de Mars"], - "weather": ["Station Météo Lamentin", "Station Schoelcher", - "Station Ajoupa-Bouillon", "Station Le François", "Station Le Robert"], - "light": ["Eclairage Rue des Mouettes", "Candela Boulevard", - "Lumiere Rue des Acacias", "Feux Signalisation Centre", "Eclairage Port"], + +# Coordonnées réelles Martinique (terre ferme uniquement) +# Martinique : 14.4°N–14.9°N, -61.23°W–-60.8°W +FIXED_LOCATIONS: dict[str, dict[str, tuple[float, float]]] = { + "traffic": { + # Fort-de-France — grands axes + "Carrefour Central": (14.6036, -61.1783), # Place du Palais, centre-ville + "Avenue des Caraïbes": (14.6100, -61.1850), # Route de Schoelcher (N1) + "Boulevard Pasteur": (14.6150, -61.1700), # Boulevard Pasteur, nord FdF + "Rue des Flamboyants": (14.5970, -61.1900), # Zone Industrielle, Lamentin + "Place de la République": (14.6000, -61.2100), # Centre administratif, sud FdF + }, + "airquality": { + # Points de mesure qualité de l'air sur terre + "Quartier Bonde": (14.6050, -61.1750), # Bonde, sud-est FdF + "Port de Fort-de-France": (14.5980, -61.2250), # Zone portuaire, bord de mer (OK, port ≠ mer) + "Château Denis": (14.6200, -61.1550), # Château Denis, nord montagne + "Lamentin Aéroport": (14.5950, -61.1700), # Aéroport, Lamentin + "Schoelcher Village": (14.7400, -61.1850), # Schoelcher, nord-ouest + }, + "parking": { + # Parkings publics sur terre + "Parking Rivière-Saleé": (14.5820, -61.2050), # Rivière-Salée (sud) + "Parking Cluny": (14.6050, -61.1750), # Cluny, FdF + "Parking Média": (14.6000, -61.1850), # Quartier Média, FdF + "Parking Grand-Camp": (14.6100, -61.1700), # Grand-Camp, Lamentin + "Parking Dillon": (14.6200, -61.1650), # Dillon, nord FdF + }, + "noise": { + # Zones urbainesbruyantes + "Rue des Arts": (14.6020, -61.1800), # Rue des Arts, centre FdF + "Marché Central": (14.6000, -61.2100), # Marché Central, FdF + "Université Fort-de-France": (14.6400, -61.1600), # Campus Schoe, nord + "Stade de Dillon": (14.6250, -61.1600), # Stade Dillon, nord + "Place du Champs de Mars": (14.6030, -61.1750), # Champs de Mars, FdF + }, + "weather": { + # Stations météo — terre ferme uniquement + "Station Météo Lamentin": (14.5950, -61.1650), # Aéroport Lamentin + "Station Schoelcher": (14.7350, -61.1800), # Schoelcher, NW + "Station Ajoupa-Bouillon": (14.8100, -61.0500), # Ajoupa-Bouillon, nord (interieur) + "Station Le François": (14.6150, -60.9000), # Le François, côte atlantique est + "Station Le Robert": (14.6800, -60.9400), # Le Robert, côte atlantique + }, + "light": { + # Éclairage public — zones urbaines + "Eclairage Rue des Mouettes": (14.6050, -61.1800), # Rue des Mouettes, FdF + "Candela Boulevard": (14.6150, -61.1700), # Boulevard Pasteur + "Lumiere Rue des Acacias": (14.6000, -61.1850), # Rue des Acacias, FdF + "Feux Signalisation Centre": (14.6030, -61.1780), # Carrefours centraux + "Eclairage Port": (14.5980, -61.2250), # Zone portuaire + }, } -def _gen_locs(stype: str, count: int) -> list[dict]: +def _build_locs(stype: str, count: int) -> list[dict]: + """Construit la liste des capteurs avec coordonnées fixes (sur terre).""" locs = [] + names = list(FIXED_LOCATIONS.get(stype, {stype: (BASE_LAT, BASE_LON)}).keys()) + # Répéter les noms si count > len(names) for i in range(count): - # Coordonnées précises Martinique (terre ferme uniquement) - # Réduit à ±0.02 pour éviter la mer - lat = BASE_LAT + random.uniform(-0.02, 0.02) - lon = BASE_LON + random.uniform(-0.02, 0.02) - names = SENSOR_NAMES.get(stype, [stype]) + name = names[i % len(names)] + coords = FIXED_LOCATIONS.get(stype, {}).get(name, (BASE_LAT, BASE_LON)) locs.append({ - "lat": round(lat, 6), - "lon": round(lon, 6), - "name": names[i % len(names)], + "lat": round(coords[0], 6), + "lon": round(coords[1], 6), + "name": name, }) return locs +SENSOR_LOCATIONS: dict[str, list[dict]] = {} for stype, count in SENSOR_COUNTS.items(): - SENSOR_LOCATIONS[stype] = _gen_locs(stype, count) + SENSOR_LOCATIONS[stype] = _build_locs(stype, count) # Ranges par type SENSOR_RANGES: dict[str, dict] = {