diff --git a/simulator.py b/simulator.py index d035cb8c..aa0ea754 100644 --- a/simulator.py +++ b/simulator.py @@ -509,7 +509,7 @@ class MultiMQTT: c.on_connect = lambda _c, _, __, rc: self._on_connect(name, rc) c.on_disconnect = lambda _c, _, __: self._on_disconnect(name) try: - c.connect(host, port, keepalive=30) + c.connect(host, port, keepalive=60, clean_start=True) c.loop_start() except Exception as e: print(f"[MQTT] ❌ {name} @ {host}:{port} → {e}") @@ -555,8 +555,9 @@ class MultiMQTT: brokers.append(("bunkerm", BUNKERM_HOST, BUNKERM_PORT, False, "bunker", "bunker", use_v5)) # OpenRemote MQTT broker (pour agents MQTT créés dans OpenRemote) + # Le broker Artemis d'OR accepte les connexions anonymes (pas de credentials) if ENABLE_OPENREMOTE: - brokers.append(("openremote", "openremote_manager_1", 1883, False, OR_ADMIN_USER, OR_ADMIN_PASS, use_v5)) + brokers.append(("openremote", "openremote_manager_1", 1883, False, "", "", use_v5)) print(f"[MQTT] 🔌 Connexion aux brokers (EMQX={enable_emqx}, Mosquitto={enable_mosquitto}, BunkerM={enable_bunkerm})...") print("[MQTT] 🔌 Connexion aux brokers...") @@ -564,7 +565,12 @@ class MultiMQTT: c = self._mk_client(name, host, port, tls=tls, user=user, pwd=pwd, use_v5=use_v5) self.clients[name] = c self.ok[name] = False - time.sleep(3) # Attend les connexions + # Attendre que tous les brokers soient connectés (Artemis peut être lent) + for _ in range(20): + time.sleep(1) + if all(self.ok.values()): + break + print(f"[MQTT] État des connexions: {dict(self.ok)}") def publish(self, topic: str, payload: str, sensor_type: str = "unknown") -> dict[str, bool]: results = {} @@ -837,38 +843,39 @@ def _or_put(asset_id: str, payload: dict) -> bool: def publish_openremote(sid: str, sensor: dict, values: dict) -> bool: """Met à jour les attributs d'un asset OpenRemote via REST.""" - # Mapping sid → asset ID (realm master) + # Mapping sid → asset ID (realm master) — assets avec agentLink + location + # Note: le compteur SENSORS est global (traffic=0-9, airquality=10-19, parking=20-29, noise=30-39, weather=40-49, light=50-59) ASSET_MAP = { - "traffic_000": "a8043c3dba95d5aa8283ce", - "traffic_001": "04d81c7396f131aa2985e8", - "traffic_002": "ef6d0b07c9eebbc4caf0a6", - "traffic_003": "cf7eb926b27fd029f7e352", - "traffic_004": "da52c73cf4657ef6e108c9", - "airquality_000": "4ea3e0c63624c751d7a658", - "airquality_001": "4f83219bbee703b3e0a255", - "airquality_002": "5335681981790e66cb97de", - "airquality_003": "03c18679226329183b44b6", - "airquality_004": "cb653676e1f5c8888263eb", - "parking_000": "6231f03dfd384cf70a761e", - "parking_001": "dafad430f5f2a9d692ad80", - "parking_002": "a447074cc2be9781780bb4", - "parking_003": "96020cc5aef95c5fda7bb4", - "parking_004": "ae981dc9d155d1313b9acf", - "noise_000": "0be31930e45d2eb5c12ccd", - "noise_001": "1802e76e3432d5eda1deb7", - "noise_002": "09c61402305f50282f7dd2", - "noise_003": "fbf0f80417d49c8c91fe09", - "noise_004": "93d09bfac36d2ed95fc858", - "weather_000": "9942f881ab6df375d8d9fa", - "weather_001": "5400fdf5c51a4fe4f5a89c", - "weather_002": "7ee9441fc1295c6f700da3", - "weather_003": "5f915a9a887c2dbd137775", - "weather_004": "ec9cfb15533ddfe16c6388", - "light_000": "1f4302946b1a4a1ded23f6", - "light_001": "35e6ef027ed9a157ad8780", - "light_002": "526538589aa981bdc77ce9", - "light_003": "40bbe989be2ae5b2a98b30", - "light_004": "fcad43e50a21d886c8f583", + "traffic_000": "429858caca3341f56fbf65", + "traffic_001": "301218322f5aaca9d6d168", + "traffic_002": "bd35fe2a90133118b9b004", + "traffic_003": "da59ec9301c4efd3fd55c4", + "traffic_004": "834f4b7b9df848f5c5c2d8", + "airquality_010": "0f922351a9894bc0144c94", + "airquality_011": "4f83219bbee703b3e0a255", + "airquality_012": "381cc31ab83dd66ed4be37", + "airquality_013": "808b73c22ecd19589a33be", + "airquality_014": "03c18679226329183b44b6", + "parking_020": "0ee6689f5c0499643d48eb", + "parking_021": "8fb6b2d0601d98b47a4172", + "parking_022": "0c00bda9e5075d12d59694", + "parking_023": "ae981dc9d155d1313b9acf", + "parking_024": "96020cc5aef95c5fda7bb4", + "noise_030": "0be31930e45d2eb5c12ccd", + "noise_031": "1802e76e3432d5eda1deb7", + "noise_032": "08edb6518750d50644afe3", + "noise_033": "93d09bfac36d2ed95fc858", + "noise_034": "7942726d84d2bd29de1e5d", + "weather_040": "9942f881ab6df375d8d9fa", + "weather_041": "5400fdf5c51a4fe4f5a89c", + "weather_042": "1a3bf32aa5208892e68965", + "weather_043": "d3725f922f96085f2df3f7", + "weather_044": "13be192a8c23dd8fdceada", + "light_050": "1f4302946b1a4a1ded23f6", + "light_051": "35e6ef027ed9a157ad8780", + "light_052": "526538589aa981bdc77ce9", + "light_053": "d4a6ac7f34d64e581937c0", + "light_054": "40bbe989be2ae5b2a98b30", } asset_id = ASSET_MAP.get(sid) if not asset_id: @@ -898,6 +905,16 @@ def publish_openremote(sid: str, sensor: dict, values: dict) -> bool: "timestamp": now, "unit": "µg/m³" if "ugm3" in field else ("°C" if "celsius" in field else ("%" if "percent" in field or "humidity" in field else ("dB" if "db" in field else ""))), } + + # Ajouter la location du capteur (GeoJSON Point) + lat = sensor.get("lat", 0) + lon = sensor.get("lon", 0) + attrs["location"] = { + "type": "GeoJSONPoint", + "value": {"type": "Point", "coordinates": [lat, lon]}, + "timestamp": now, + } + payload = { "id": asset_id, "name": sensor["name"], @@ -1100,11 +1117,15 @@ def main(): for sid, sensor in SENSORS.items(): stype = sensor["type"] - # Utiliser un index 1-5 basé sur le compteur par type pour correspondre aux agents OpenRemote - if not hasattr(mqtt_client, "type_counters"): - mqtt_client.type_counters = {} - mqtt_client.type_counters[stype] = mqtt_client.type_counters.get(stype, 0) + 1 - sensor_index = mqtt_client.type_counters[stype] + # Utiliser l'index du capteur dans FIXED_LOCATIONS (1-5) pour correspondre aux agents OpenRemote + # Le sid est formaté comme {stype}_{counter:03d} avec counter global + # On extrait l'index du capteur depuis le sid (derniers chiffres) + sensor_num = int(sid.split("_")[1]) + # Calculer l'index 1-5 basé sur la position dans le type + # traffic: 0-9, airquality: 10-19, parking: 20-29, noise: 30-39, weather: 40-49, light: 50-59 + type_offsets = {"traffic": 0, "airquality": 10, "parking": 20, "noise": 30, "weather": 40, "light": 50} + type_offset = type_offsets.get(stype, 0) + sensor_index = sensor_num - type_offset + 1 # 1-indexed topic = f"smartcity/{stype}/{sensor_index}" # --- Payload MQTT (ATTRIBUTES ONLY - pas de id/type/lat/lon !) @@ -1143,10 +1164,11 @@ def main(): if isinstance(lo, (int, float)): or_values[field] = round(random.uniform(lo, hi), 1) - # --- OpenRemote REST --- - if ENABLE_OPENREMOTE: - ok_or = publish_openremote(sid, sensor, or_values) - print(f" 🏠 OpenRemote: {'✅' if ok_or else '⚠️ skipped'}") + # --- OpenRemote REST --- (DÉSACTIVÉ: les agents MQTT gèrent les mises à jour) + # Le REST échoue en 403 sur les assets avec agentLink + # if ENABLE_OPENREMOTE: + # ok_or = publish_openremote(sid, sensor, or_values) + # print(f" 🏠 OpenRemote: {'✅' if ok_or else '⚠️ skipped'}") # # --- Orion-LD --- (DÉSACTIVÉ: tout passe par les IoT-Agents MQTT) # # if ENABLE_ORION: