fix: Simulateur MQTT 3/4 + OpenRemote master + Mapsettings

- MQTT OK: 3/4 (EMQX, Mosquitto, BunkerM)
- OpenRemote: utilise realm master (token fonctionnel)
- Realm smartcity recréé dans Keycloak
- Assets IOTSensor créés dans master (30) et smartcity (30)
- Mapsettings: layers iot-sensors + labels pour master et smartcity
- INTERVAL=5s, réseau openremote_default ajouté
- Dockerfile: --no-cache rebuild
This commit is contained in:
Eric FELIXINE
2026-05-11 14:19:53 -04:00
parent ae153c4e5e
commit 918c03dffa
18 changed files with 5862915 additions and 37 deletions

View File

@@ -70,7 +70,7 @@ ENABLE_FROST = os.environ.get("ENABLE_FROST", "1") == "1"
ENABLE_OPENREMOTE = os.environ.get("ENABLE_OPENREMOTE", "1") == "1"
OR_ADMIN_USER = os.environ.get("OR_ADMIN_USER", "admin")
OR_ADMIN_PASS = os.environ.get("OR_ADMIN_PASS", "Digitribe972")
OR_REALM = os.environ.get("OR_REALM", "smartcity")
OR_REALM = os.environ.get("OR_REALM", "master")
OR_TOKEN_REALM = os.environ.get("OR_TOKEN_REALM", "master") # Realm pour obtention token
#ENABLE_IOT_AGENT = os.environ.get("ENABLE_IOT_AGENT", "1") == "1"
FROST_URL = os.environ.get("FROST_URL", "http://localhost:8090/FROST-Server/v1.1") # Exposer frost_http-web-1:8080 -> host:8086
@@ -497,7 +497,8 @@ class MultiMQTT:
ws: bool = False, use_v5: bool = False) -> mqtt.Client:
cid = f"smartcity-sim-{name}-{os.getpid()}"
protocol = mqtt.MQTTv5 if use_v5 else mqtt.MQTTv311
c = mqtt.Client(client_id=cid, protocol=protocol)
# Use Callback API v1 for compatibility with existing lambda callbacks
c = mqtt.Client(client_id=cid, protocol=protocol, callback_api_version=mqtt.CallbackAPIVersion.VERSION1)
if user:
c.username_pw_set(user, pwd)
if tls:
@@ -536,11 +537,28 @@ class MultiMQTT:
def _setup(self):
# Utiliser les variables d'environnement pour les brokers
brokers = [
("emqx", EMQX_HOST, EMQX_PORT, False, "", "", False),
("mosquitto", MOSQUITTO_HOST, MOSQUITTO_PORT, False, "", "", False), # Same as emqx
("bunkerm", BUNKERM_HOST, BUNKERM_PORT, False, "bunker", "bunker", False),
]
mqtt_version = os.environ.get("MQTT_PROTOCOL_VERSION", "311")
use_v5 = (mqtt_version == "5")
print(f"[MQTT] Version du protocole: {'v5.0' if use_v5 else 'v3.1.1'} (MQTT_PROTOCOL_VERSION={mqtt_version})")
# Check which brokers are enabled
enable_emqx = os.environ.get("ENABLE_EMQX", "1") == "1"
enable_mosquitto = os.environ.get("ENABLE_MOSQUITTO", "1") == "1"
enable_bunkerm = os.environ.get("ENABLE_BUNKER", "1") == "1"
brokers = []
if enable_emqx:
brokers.append(("emqx", EMQX_HOST, EMQX_PORT, False, "", "", use_v5))
if enable_mosquitto:
brokers.append(("mosquitto", MOSQUITTO_HOST, MOSQUITTO_PORT, False, "", "", use_v5))
if enable_bunkerm:
brokers.append(("bunkerm", BUNKERM_HOST, BUNKERM_PORT, False, "bunker", "bunker", use_v5))
# OpenRemote MQTT broker (pour agents MQTT créés dans OpenRemote)
if ENABLE_OPENREMOTE:
brokers.append(("openremote", "openremote_manager_1", 1883, False, OR_ADMIN_USER, OR_ADMIN_PASS, use_v5))
print(f"[MQTT] 🔌 Connexion aux brokers (EMQX={enable_emqx}, Mosquitto={enable_mosquitto}, BunkerM={enable_bunkerm})...")
print("[MQTT] 🔌 Connexion aux brokers...")
for name, host, port, tls, user, pwd, use_v5 in brokers:
c = self._mk_client(name, host, port, tls=tls, user=user, pwd=pwd, use_v5=use_v5)
@@ -749,9 +767,9 @@ def _get_or_token() -> str:
return _or_token_cache["token"]
try:
# Use password grant with admin user (full rights)
token_url = f"http://localhost:8080/auth/realms/{OR_REALM}/protocol/openid-connect/token"
token_url = f"http://openremote-keycloak-1:8080/auth/realms/{OR_TOKEN_REALM}/protocol/openid-connect/token"
client_id = os.environ.get("OR_CLIENT_ID", "openremote")
client_secret = os.environ.get("OR_CLIENT_SECRET", "QVTnyObwXdpQ0Vuc60kFSonidK49FiXb")
client_secret = os.environ.get("OR_CLIENT_SECRET", "0oQjzTfiEELYmj5jFwT4iIuWUDtQDvVa")
data = urllib.parse.urlencode({
"grant_type": "password",
"username": os.environ.get("OR_ADMIN_USER", "admin"),
@@ -806,16 +824,38 @@ 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 (créés manuellement dans OR)
# Mapping sid → asset ID (realm master)
ASSET_MAP = {
"traffic_000": "7b5c5670d1b84865ba3ac7", # Traffic Fort-de-France Centre
"traffic_001": "557f6e993b994d3cb81017", # Traffic Fort-de-France North
"traffic_002": "cb81dfd2d2dc4d25adc9c2", # Traffic Fort-de-France South
"airquality_000": "a51c982a2d3e451898b978", # Air Quality Fort-de-France
"parking_000": "b8f0df19e0af47b386ebb9", # Parking Fort-de-France Centre
"noise_000": "9035103d1866454fb7e451", # Noise Fort-de-France Centre
"weather_000": "b9de80905ac640f488ab27", # Weather Lamentin Airport
"light_000": "ee7823a41e594851ba202f", # Light Fort-de-France
"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",
}
asset_id = ASSET_MAP.get(sid)
if not asset_id:
@@ -1047,7 +1087,12 @@ def main():
for sid, sensor in SENSORS.items():
stype = sensor["type"]
topic = f"city/sensors/{stype}/{sid}"
# 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]
topic = f"smartcity/{stype}/{sensor_index}"
# --- Payload MQTT (ATTRIBUTES ONLY - pas de id/type/lat/lon !)
# # L'IoT Agent n'attend que les readings, pas le body complet