Simulator: Add source+mqttTopic traceability for Fiware brokers
This commit is contained in:
31
simulator.py
31
simulator.py
@@ -193,7 +193,7 @@ STELLIO_INLINE_CONTEXT = [
|
|||||||
"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld",
|
"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld",
|
||||||
]
|
]
|
||||||
|
|
||||||
def _ngsi_payload(sid: str, sensor: dict, context: list | dict = ORION_CONTEXT) -> dict:
|
def _ngsi_payload(sid: str, sensor: dict, context: list | dict = ORION_CONTEXT, source: str = "simulator", topic: str = "") -> dict:
|
||||||
"""Construit un payload NGSI-LD avec Smart Data Models officiels."""
|
"""Construit un payload NGSI-LD avec Smart Data Models officiels."""
|
||||||
stype = sensor["type"]
|
stype = sensor["type"]
|
||||||
model_type = SMART_MODEL_MAPPING.get(stype, "Device")
|
model_type = SMART_MODEL_MAPPING.get(stype, "Device")
|
||||||
@@ -210,6 +210,11 @@ def _ngsi_payload(sid: str, sensor: dict, context: list | dict = ORION_CONTEXT)
|
|||||||
"coordinates": [sensor["lon"], sensor["lat"]]}},
|
"coordinates": [sensor["lon"], sensor["lat"]]}},
|
||||||
"name": {"type": "Property", "value": sensor["name"]},
|
"name": {"type": "Property", "value": sensor["name"]},
|
||||||
"batteryLevel": {"type": "Property", "value": random.randint(60, 100)},
|
"batteryLevel": {"type": "Property", "value": random.randint(60, 100)},
|
||||||
|
# NOUVEAU: Traçabilité MQTT (Conforme NGSI-LD)
|
||||||
|
# "source" est un champ standard NGSI-LD (ETSI)
|
||||||
|
# "mqttTopic" est une propriété personnalisée (étendue autorisée)
|
||||||
|
"source": {"type": "Property", "value": source},
|
||||||
|
"mqttTopic": {"type": "Property", "value": topic},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Attributs spécifiques par type de modèle
|
# Attributs spécifiques par type de modèle
|
||||||
@@ -264,7 +269,7 @@ def _ngsi_payload(sid: str, sensor: dict, context: list | dict = ORION_CONTEXT)
|
|||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def _frost_payload(sid: str, sensor: dict) -> dict:
|
def _frost_payload(sid: str, sensor: dict, source: str = "simulator", topic: str = "") -> dict:
|
||||||
"""Construit un payload SensorThings pour FROST-Server."""
|
"""Construit un payload SensorThings pour FROST-Server."""
|
||||||
stype = sensor["type"]
|
stype = sensor["type"]
|
||||||
ranges = SENSOR_RANGES.get(stype, {})
|
ranges = SENSOR_RANGES.get(stype, {})
|
||||||
@@ -300,7 +305,12 @@ def _frost_payload(sid: str, sensor: dict) -> dict:
|
|||||||
thing_payload = {
|
thing_payload = {
|
||||||
"name": f"Thing_{sid}",
|
"name": f"Thing_{sid}",
|
||||||
"description": f"Smart City {stype} sensor in Martinique",
|
"description": f"Smart City {stype} sensor in Martinique",
|
||||||
"properties": {"sensorType": stype, "region": "Martinique"},
|
"properties": {
|
||||||
|
"sensorType": stype,
|
||||||
|
"region": "Martinique",
|
||||||
|
"source": source, # Traçabilité
|
||||||
|
"mqttTopic": topic # Traçabilité
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return thing_payload, datastreams
|
return thing_payload, datastreams
|
||||||
|
|
||||||
@@ -456,7 +466,10 @@ STELLIO_TENANT = os.environ.get("STELLIO_TENANT", "urn:ngsi-ld:tenant:default")
|
|||||||
|
|
||||||
def publish_stellio(sid: str, sensor: dict) -> bool:
|
def publish_stellio(sid: str, sensor: dict) -> bool:
|
||||||
"""Publie sur Stellio via Traefik (gère le 409)."""
|
"""Publie sur Stellio via Traefik (gère le 409)."""
|
||||||
entity = _ngsi_payload(sid, sensor, context=STELLIO_INLINE_CONTEXT)
|
# Topic MQTT correspondant (pour traçabilité)
|
||||||
|
stype = sensor["type"]
|
||||||
|
topic = f"city/sensors/{stype}/{sid}"
|
||||||
|
entity = _ngsi_payload(sid, sensor, context=STELLIO_INLINE_CONTEXT, source="simulator", topic=topic)
|
||||||
# Stellio a besoin du @context pour résoudre les vocabulaires NGSI-LD
|
# Stellio a besoin du @context pour résoudre les vocabulaires NGSI-LD
|
||||||
# (uri.etsi.org résolu depuis le JAR embarqué)
|
# (uri.etsi.org résolu depuis le JAR embarqué)
|
||||||
url = f"{STELLIO_URL}/ngsi-ld/v1/entities"
|
url = f"{STELLIO_URL}/ngsi-ld/v1/entities"
|
||||||
@@ -496,7 +509,10 @@ def publish_stellio(sid: str, sensor: dict) -> bool:
|
|||||||
def publish_orion(sid: str, sensor: dict) -> bool:
|
def publish_orion(sid: str, sensor: dict) -> bool:
|
||||||
"""Publie sur Orion-LD (POST create, PATCH update)."""
|
"""Publie sur Orion-LD (POST create, PATCH update)."""
|
||||||
import socket
|
import socket
|
||||||
entity = _ngsi_payload(sid, sensor)
|
# Topic MQTT correspondant (pour traçabilité)
|
||||||
|
stype = sensor["type"]
|
||||||
|
topic = f"city/sensors/{stype}/{sid}"
|
||||||
|
entity = _ngsi_payload(sid, sensor, source="simulator", topic=topic)
|
||||||
if not hasattr(publish_orion, "orion_ip"):
|
if not hasattr(publish_orion, "orion_ip"):
|
||||||
try:
|
try:
|
||||||
publish_orion.orion_ip = socket.gethostbyname("fiware-gis-quickstart-orion-1")
|
publish_orion.orion_ip = socket.gethostbyname("fiware-gis-quickstart-orion-1")
|
||||||
@@ -611,7 +627,10 @@ def publish_frost(sid: str, sensor: dict, field: str, value: float) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Premier appel pour ce capteur : créer Thing + tous les Datastreams
|
# Premier appel pour ce capteur : créer Thing + tous les Datastreams
|
||||||
thing_payload, datastreams = _frost_payload(sid, sensor)
|
# Topic MQTT pour traçabilité
|
||||||
|
stype = sensor["type"]
|
||||||
|
topic = f"city/sensors/{stype}/{sid}"
|
||||||
|
thing_payload, datastreams = _frost_payload(sid, sensor, source="simulator", topic=topic)
|
||||||
print(f" 📊 FROST: POST Thing {sid}...")
|
print(f" 📊 FROST: POST Thing {sid}...")
|
||||||
tid = _http_post(f"{FROST_URL}/Things", thing_payload, FROST_HEADERS)
|
tid = _http_post(f"{FROST_URL}/Things", thing_payload, FROST_HEADERS)
|
||||||
if not tid:
|
if not tid:
|
||||||
|
|||||||
Reference in New Issue
Block a user