fix: Stellio/Orion - use NGSI-LD core context only (remove raw.githubusercontent.com)
- STELLIO_INLINE_CONTEXT: replaced long inline dict with uri.etsi.org core URL - ORION_CONTEXT: removed raw.githubusercontent.com URLs (not accessible from containers) - publish_stellio(): added NGSILD-Tenant header (urn:ngsi-ld:tenant:default) - publish_stellio(): keep @context in payload (Stellio needs it to resolve vocabulary) - Added STELLIO_URL and STELLIO_TENANT env vars for host-based execution via Traefik Fixes: Stellio 503 JsonLdError, Orion-LD context resolution failures. Tested: Stellio 201, Orion-LD 207.
This commit is contained in:
36
simulator.py
36
simulator.py
@@ -131,14 +131,10 @@ for stype, locs in SENSOR_LOCATIONS.items():
|
||||
# =============================================================================
|
||||
# Contextes NGSI-LD : core + Smart Data Models
|
||||
# https://smartdatamodels.org pour les @context officiels
|
||||
STELLIO_CONTEXT_URL = "https://gitea.digitribe.fr/eric/smart-city-digital-twin-martinique/raw/branch/master/contexts"
|
||||
# Contexte NGSI-LD pur pour Orion-LD (vocabulaires standards uniquement)
|
||||
# Orion-LD ne peut pas résoudre raw.githubusercontent.com — utiliser uri.etsi.org uniquement
|
||||
ORION_CONTEXT = [
|
||||
f"{STELLIO_CONTEXT_URL}/ngsi-ld-core.jsonld",
|
||||
"https://raw.githubusercontent.com/smart-data-models/dataModel.Environment/master/context.jsonld",
|
||||
"https://raw.githubusercontent.com/smart-data-models/dataModel.Transportation/master/context.jsonld",
|
||||
"https://raw.githubusercontent.com/smart-data-models/dataModel.Parking/master/context.jsonld",
|
||||
"https://raw.githubusercontent.com/smart-data-models/dataModel.Weather/master/context.jsonld",
|
||||
"https://raw.githubusercontent.com/smart-data-models/dataModel.Device/master/context.jsonld",
|
||||
"https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld",
|
||||
]
|
||||
|
||||
# Mapping sensor type → Smart Data Model type NGSI-LD
|
||||
@@ -155,7 +151,16 @@ FROST_HEADERS = {"Accept": "application/json", "Content-Type": "application/json
|
||||
# Cache FROST : éviter de recréer Thing/Datastream
|
||||
_frost_cache: dict[str, tuple[str, str]] = {} # (sid, field) -> (thing_id, ds_id)
|
||||
|
||||
def _ngsi_payload(sid: str, sensor: dict) -> dict:
|
||||
# Contexte NGSI-LD pur pour Stellio et Orion-LD (vocabulaires standards uniquement)
|
||||
# Stellio et Orion-LD embarquent le contexte core NGSI-LD : https://uri.etsi.org/ngsi-ld/
|
||||
# On n'utilise PAS les vocabulaires smartdatamodels.org distants (inaccessibles depuis les containers)
|
||||
# Les types d'entité Smart Data Models (AirQualityObserved, etc.) sont reconnus par leur nom
|
||||
# Les propriétés spécifiques sont stockées telles quelles (vocabulaire libre)
|
||||
STELLIO_INLINE_CONTEXT = [
|
||||
"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:
|
||||
"""Construit un payload NGSI-LD avec Smart Data Models officiels."""
|
||||
stype = sensor["type"]
|
||||
model_type = SMART_MODEL_MAPPING.get(stype, "Device")
|
||||
@@ -163,7 +168,7 @@ def _ngsi_payload(sid: str, sensor: dict) -> dict:
|
||||
|
||||
# Attributs communs à tous les modèles
|
||||
payload = {
|
||||
"@context": ORION_CONTEXT,
|
||||
"@context": context,
|
||||
"id": f"urn:ngsi-ld:{model_type}:{sid}",
|
||||
"type": model_type,
|
||||
"dateObserved": {"type": "Property", "value": now},
|
||||
@@ -413,19 +418,24 @@ try:
|
||||
except:
|
||||
pass
|
||||
ORION_URL = f"http://{ORION_IP or ORION_HOST}:1026" if ORION_IP else "http://fiware-gis-quickstart-orion-1:1026"
|
||||
STELLIO_URL = "http://stellio-api-gateway:8080"
|
||||
STELLIO_URL = os.environ.get("STELLIO_URL", "http://stellio-api-gateway:8080")
|
||||
# Configuration OpenRemote (URLs dynamiques)
|
||||
OR_URL = os.environ.get("OR_URL", "http://openremote-manager-1:8080") # Hostname Docker interne
|
||||
OR_REALM = os.environ.get("OR_REALM", "smartcity") # Default: smartcity
|
||||
OR_TOKEN_URL = os.environ.get("OR_TOKEN_URL", f"http://openremote-keycloak-1:8080/auth/realms/{OR_TOKEN_REALM}/protocol/openid-connect/token")
|
||||
OR_TOKEN_TTL = int(os.environ.get("OR_TOKEN_TTL", "3600")) # Refresh token every hour
|
||||
STELLIO_TENANT = os.environ.get("STELLIO_TENANT", "urn:ngsi-ld:tenant:default")
|
||||
|
||||
def publish_stellio(sid: str, sensor: dict) -> bool:
|
||||
"""Publie sur Stellio (gère le 409)."""
|
||||
entity = _ngsi_payload(sid, sensor)
|
||||
url = f"{STELLIO_URL}/ngsi-ld/v1/entities" # Sans options=upsert
|
||||
"""Publie sur Stellio via Traefik (gère le 409)."""
|
||||
entity = _ngsi_payload(sid, sensor, context=STELLIO_INLINE_CONTEXT)
|
||||
# Stellio a besoin du @context pour résoudre les vocabulaires NGSI-LD
|
||||
# (uri.etsi.org résolu depuis le JAR embarqué)
|
||||
url = f"{STELLIO_URL}/ngsi-ld/v1/entities"
|
||||
headers = {
|
||||
"Content-Type": "application/ld+json",
|
||||
"Accept": "application/ld+json",
|
||||
"NGSILD-Tenant": STELLIO_TENANT,
|
||||
}
|
||||
try:
|
||||
body = json.dumps(entity).encode()
|
||||
|
||||
Reference in New Issue
Block a user