Session 2026-05-19: OpenRemote map display investigation, cleanup, fresh install
- Investigated map display issues (agentLink, GeoJSON coords, realm config) - Cleaned up all dashboards and containers - Fresh Manager installation (PostgreSQL in recovery) - Updated TODO.md with current status - GeoJSON proxy: fixed coordinate order (lon/lat) - Session resume saved
This commit is contained in:
11
TODO.md
11
TODO.md
@@ -1,6 +1,6 @@
|
||||
# Smart City Digital Twin — TODO List
|
||||
|
||||
> Dernière mise à jour : 2026-05-17 20:00
|
||||
> Dernière mise à jour : 2026-05-19 22:15
|
||||
|
||||
## ✅ Complété (5/13)
|
||||
| ID | Tâche |
|
||||
@@ -14,7 +14,7 @@
|
||||
## 🔴 Bloqué (5/13)
|
||||
| ID | Tâche | Raison |
|
||||
|----|-------|--------|
|
||||
| p1-or | OpenRemote agents MQTT | API 403, UI headless ne rend pas |
|
||||
| p1-or | OpenRemote agents MQTT + map display | PostgreSQL en recovery après reinstallation |
|
||||
| p4-ditto | Ditto.digitribe.fr | MongoDB localhost hardcodé |
|
||||
| p1-prometheus | Prometheus + Grafana | Réseau interne inaccessible |
|
||||
| p3-kepler | KeplerGL | Image Docker incomplète, build npm trop long |
|
||||
@@ -37,6 +37,13 @@
|
||||
| metabase | data-visualization | ✅ |
|
||||
| contexus | iot | ✅ |
|
||||
|
||||
## 📝 Notes 2026-05-19
|
||||
- **OpenRemote map display** : Investigation approfondie — points ne s'affichent pas malgré toutes les conditions remplies (location, agentLink, showOnDashboard, bon realm)
|
||||
- **Décision** : Repartir de zéro avec installation fraîche du Manager
|
||||
- **PostgreSQL** : En recovery (fsync du data directory) — peut prendre 10+ minutes
|
||||
- **Prochaines étapes** : Attendre PostgreSQL → Vérifier Manager/Keycloak → Lancer simulateur → Créer dashboard via UI → Vérifier affichage
|
||||
- **Custom project** : Répertoire `/home/eric/openremote/custom-project/` cloné — prêt pour développement custom
|
||||
|
||||
## Credentials
|
||||
- **GeoServer**: admin / Digitribe972
|
||||
- **PostGIS dédié**: smartcity / SmartCity972 (port 5433)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""GeoJSON proxy service for OpenRemote assets map display.
|
||||
Fetches IoT sensor assets from OpenRemote REST API and serves them as GeoJSON.
|
||||
Fetches all assets with location from OpenRemote REST API and serves them as GeoJSON.
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -12,31 +12,10 @@ from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
|
||||
OR_URL = os.environ.get("OR_URL", "http://openremote_manager_1:8080")
|
||||
OR_ADMIN_USER = os.environ.get("OR_ADMIN_USER", "admin")
|
||||
OR_ADMIN_PASS = os.environ.get("OR_ADMIN_PASS", "")
|
||||
OR_ADMIN_PASS = os.environ.get("OR_ADMIN_PASS", "Digitribe972")
|
||||
OR_REALM = os.environ.get("OR_REALM", "master")
|
||||
OR_CLIENT_SECRET = os.environ.get("OR_CLIENT_SECRET", "0oQjzTfiEELYmj5jFwT4iIuWUDtQDvVa")
|
||||
|
||||
# All known IOTSensor asset IDs (from simulator ASSET_MAP + DB)
|
||||
ASSET_IDS = [
|
||||
"429858caca3341f56fbf65", "301218322f5aaca9d6d168", "bd35fe2a90133118b9b004",
|
||||
"da59ec9301c4efd3fd55c4", "834f4b7b9df848f5c5c2d8",
|
||||
"0f922351a9894bc0144c94", "4f83219bbee703b3e0a255", "381cc31ab83dd66ed4be37",
|
||||
"808b73c22ecd19589a33be", "03c18679226329183b44b6",
|
||||
"0ee6689f5c0499643d48eb", "8fb6b2d0601d98b47a4172", "0c00bda9e5075d12d59694",
|
||||
"ae981dc9d155d1313b9acf", "96020cc5aef95c5fda7bb4",
|
||||
"0be31930e45d2eb5c12ccd", "1802e76e3432d5eda1deb7", "08edb6518750d50644afe3",
|
||||
"93d09bfac36d2ed95fc858", "7942726d84d2bd29de1e5d",
|
||||
"9942f881ab6df375d8d9fa", "5400fdf5c51a4fe4f5a89c", "1a3bf32aa5208892e68965",
|
||||
"d3725f922f96085f2df3f7", "13be192a8c23dd8fdceada",
|
||||
"1f4302946b1a4a1ded23f6", "35e6ef027ed9a157ad8780", "526538589aa981bdc77ce9",
|
||||
"d4a6ac7f34d64e581937c0", "40bbe989be2ae5b2a98b30",
|
||||
# Additional assets from DB
|
||||
"8b8f50aa8d13d65b2bafb7", "d642131a593c1cddcca3df",
|
||||
"f4afeba492308772a9a1a4", "988232e4b779fd2cde2157",
|
||||
"b75157bd68fde1577eda4d", "f388f67ec11e7860c352a3",
|
||||
"ba30baf1fb3c69bdcc1b44",
|
||||
]
|
||||
|
||||
_token_cache = {"token": "", "expires": 0}
|
||||
|
||||
|
||||
@@ -66,18 +45,50 @@ def get_token():
|
||||
|
||||
|
||||
def fetch_assets():
|
||||
"""Fetch IoT sensor assets from OpenRemote REST API."""
|
||||
"""Fetch all assets with location from OpenRemote REST API."""
|
||||
token = get_token()
|
||||
features = []
|
||||
|
||||
for asset_id in ASSET_IDS:
|
||||
# Query all assets with location attribute
|
||||
try:
|
||||
# Use the asset query API to get all assets with location
|
||||
query = json.dumps({
|
||||
"attributes": {
|
||||
"location": {
|
||||
"value": {"$exists": True}
|
||||
}
|
||||
}
|
||||
}).encode()
|
||||
req = urllib.request.Request(
|
||||
f"{OR_URL}/api/{OR_REALM}/asset/query",
|
||||
data=query,
|
||||
headers={
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
method="POST"
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
assets = json.loads(r.read().decode())
|
||||
if not isinstance(assets, list):
|
||||
assets = [assets]
|
||||
except Exception as e:
|
||||
# Fallback: try to get all assets and filter
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
f"{OR_URL}/api/{OR_REALM}/asset/{asset_id}",
|
||||
f"{OR_URL}/api/{OR_REALM}/asset?limit=100",
|
||||
headers={"Authorization": f"Bearer {token}", "Accept": "application/json"}
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=5) as r:
|
||||
asset = json.loads(r.read().decode())
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
assets = json.loads(r.read().decode())
|
||||
if not isinstance(assets, list):
|
||||
assets = [assets]
|
||||
except Exception as e2:
|
||||
return {"type": "FeatureCollection", "features": [], "error": str(e2)}
|
||||
|
||||
for asset in assets:
|
||||
try:
|
||||
attrs = asset.get("attributes", {})
|
||||
location = attrs.get("location", {})
|
||||
value = location.get("value") if isinstance(location, dict) else None
|
||||
@@ -102,9 +113,10 @@ def fetch_assets():
|
||||
if v is not None and not isinstance(v, (dict, list)):
|
||||
props[attr_name] = v
|
||||
|
||||
# GeoJSON coordinates are [longitude, latitude]
|
||||
features.append({
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [coords[0], coords[1]]},
|
||||
"geometry": {"type": "Point", "coordinates": [coords[1], coords[0]]},
|
||||
"properties": props
|
||||
})
|
||||
except Exception:
|
||||
|
||||
@@ -912,13 +912,14 @@ def publish_openremote(sid: str, sensor: dict, values: dict) -> bool:
|
||||
"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)
|
||||
# Ajouter la location du capteur (GeoJSON Point) avec meta showOnDashboard
|
||||
lat = sensor.get("lat", 0)
|
||||
lon = sensor.get("lon", 0)
|
||||
attrs["location"] = {
|
||||
"type": "GeoJSONPoint",
|
||||
"value": {"type": "Point", "coordinates": [lat, lon]},
|
||||
"timestamp": now,
|
||||
"meta": {"showOnDashboard": True},
|
||||
}
|
||||
|
||||
payload = {
|
||||
|
||||
Reference in New Issue
Block a user