fix: replace random coords with fixed Martinique locations (no more sea sensors)

- 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
This commit is contained in:
Eric FELIXINE
2026-05-05 21:24:29 -04:00
parent 75ee75f036
commit ad31e2289f

View File

@@ -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°N14.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] = {