GeoServer workspace Digitribe + InfluxDB support + data flow diagrams
This commit is contained in:
68
geoserver_config_status.md
Normal file
68
geoserver_config_status.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Configuration GeoServer - Smart City Digital Twin
|
||||||
|
|
||||||
|
## État au 04 Mai 2026 (22h15)
|
||||||
|
|
||||||
|
### ✅ Réalisé
|
||||||
|
1. **Workspace créé** : `Digitribe` (via REST API)
|
||||||
|
- URL: https://geoserver.digitribe.fr/geoserver/web/?workspace=Digitribe
|
||||||
|
2. **Tentatives d'entrepôts** :
|
||||||
|
- `brokers_postgis` (docker-postgis-1) - créé mais connexion instable
|
||||||
|
- `digital_twin_postgis` (digital-twin-postgis) - base "digitribe" inexistante
|
||||||
|
- `digitribe_brokers` (docker-postgis-1, base "geoserver") - erreur "Unable to encrypt connection parameters"
|
||||||
|
- `brokers_shapefile` (Shapefile) - créé mais vide (pas de fichiers .shp)
|
||||||
|
|
||||||
|
### ❌ Problèmes rencontrés
|
||||||
|
- **Erreur** : "Failed to find the datastore factory" / "Unable to encrypt connection parameters"
|
||||||
|
- **Cause probable** : Paramètres de connexion PostGIS mal formatés ou problème de chiffrement GeoServer
|
||||||
|
- **Identifiants testés** :
|
||||||
|
- docker-postgis-1 : user=`geoserver`, password=`geoserver`, db=`geoserver`
|
||||||
|
- digital-twin-postgis : user=`gis_user`, password=`gis_pass` (probable)
|
||||||
|
- frost_http-database-1 : user=`sensorthings`, password=`Digitribe972` (probable)
|
||||||
|
|
||||||
|
### 📋 Configuration pour MapStore
|
||||||
|
Une fois l'entrepôt fonctionnel, voici comment l'utiliser dans MapStore :
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Exemple de configuration MapStore (WMS)
|
||||||
|
{
|
||||||
|
"type": "wms",
|
||||||
|
"url": "https://geoserver.digitribe.fr/geoserver/wms",
|
||||||
|
"name": "Digitribe:broker_sensors",
|
||||||
|
"format": "image/png",
|
||||||
|
"workspace": "Digitribe"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔄 Prochaines étapes (pour reprise)
|
||||||
|
1. **Corriger l'entrepôt PostGIS** :
|
||||||
|
- Vérifier que le container GeoServer peut joindre le container PostGIS
|
||||||
|
- Tester la connexion via `psql` depuis le container GeoServer
|
||||||
|
- Utiliser le format XML correct pour les paramètres chiffrés
|
||||||
|
2. **Ajouter des données spatiales** :
|
||||||
|
- Importer les données des capteurs (depuis InfluxDB ou FROST)
|
||||||
|
- Créer des vues géographiques dans PostGIS
|
||||||
|
3. **Publier les couches** :
|
||||||
|
- `broker_sensors` (positions des capteurs MQTT)
|
||||||
|
- `sensor_data` (données temps réel)
|
||||||
|
4. **Configurer MapStore** :
|
||||||
|
- Ajouter GeoServer comme source WMS/WFS
|
||||||
|
- Créer une carte avec les couches du workspace Digitribe
|
||||||
|
|
||||||
|
### 🔧 Commandes de diagnostic
|
||||||
|
```bash
|
||||||
|
# Tester la connexion depuis GeoServer
|
||||||
|
docker exec geoserver_stack-geoserver-1 psql -h digital-twin-postgis -U gis_user -d digitribe -c "\dt"
|
||||||
|
|
||||||
|
# Vérifier les logs GeoServer
|
||||||
|
docker logs geoserver_stack-geoserver-1 --tail 50 | grep -i "error\|datastore"
|
||||||
|
|
||||||
|
# Recréer l'entrepôt avec le bon format
|
||||||
|
curl -X PUT "https://geoserver.digitribe.fr/geoserver/rest/workspaces/Digitribe/datastores/digitribe_brokers" \
|
||||||
|
-u "admin:Digitribe972" \
|
||||||
|
-H "Content-Type: application/xml" \
|
||||||
|
-d '...' # (XML avec paramètres corrects)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
**Fichiers** : `geoserver_config_status.md` (ce fichier)
|
||||||
|
**Statut** : Workspace ✅ | Entrepôts ⚠️ (à debugguer) | Prêt pour MapStore ❌
|
||||||
63
simulator.py
63
simulator.py
@@ -29,6 +29,10 @@ import urllib.request, urllib.error
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
# InfluxDB support
|
||||||
|
import influxdb_client
|
||||||
|
from influxdb_client.client.write_api import SYNCHRONOUS
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Configuration
|
# Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -45,6 +49,24 @@ OR_REALM = os.environ.get("OR_REALM", "smartcity")
|
|||||||
OR_TOKEN_REALM = os.environ.get("OR_TOKEN_REALM", "master") # Realm pour obtention token
|
OR_TOKEN_REALM = os.environ.get("OR_TOKEN_REALM", "master") # Realm pour obtention token
|
||||||
FROST_URL = os.environ.get("FROST_URL", "http://frost_http-web-1:8080/FROST-Server/v1.1")
|
FROST_URL = os.environ.get("FROST_URL", "http://frost_http-web-1:8080/FROST-Server/v1.1")
|
||||||
|
|
||||||
|
# InfluxDB config
|
||||||
|
ENABLE_INFLUX = os.environ.get("ENABLE_INFLUX", "1") == "1"
|
||||||
|
INFLUX_URL = os.environ.get("INFLUX_URL", "http://digital-twin-influxdb:8086")
|
||||||
|
INFLUX_ORG = os.environ.get("INFLUX_ORG", "digitribe")
|
||||||
|
INFLUX_BUCKET = os.environ.get("INFLUX_BUCKET", "iot_data")
|
||||||
|
INFLUX_TOKEN = os.environ.get("INFLUX_TOKEN", "my-super-secret-admin-token")
|
||||||
|
|
||||||
|
# Initialize InfluxDB client
|
||||||
|
_influx_client = None
|
||||||
|
_influx_write_api = None
|
||||||
|
if ENABLE_INFLUX:
|
||||||
|
try:
|
||||||
|
_influx_client = influxdb_client.InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
|
||||||
|
_influx_write_api = _influx_client.write_api(write_options=SYNCHRONOUS)
|
||||||
|
print(f"[INFLUX] ✅ Connected to {INFLUX_URL}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[INFLUX] ❌ Connection failed: {e}")
|
||||||
|
|
||||||
SENSOR_COUNTS = {
|
SENSOR_COUNTS = {
|
||||||
"traffic": int(os.environ.get("SENSOR_COUNT_traffic", "3")),
|
"traffic": int(os.environ.get("SENSOR_COUNT_traffic", "3")),
|
||||||
"airquality": int(os.environ.get("SENSOR_COUNT_airquality", "2")),
|
"airquality": int(os.environ.get("SENSOR_COUNT_airquality", "2")),
|
||||||
@@ -724,7 +746,35 @@ def publish_openremote(sid: str, sensor: dict, values: dict) -> bool:
|
|||||||
"attributes": attrs,
|
"attributes": attrs,
|
||||||
}
|
}
|
||||||
return _or_put(asset_id, payload)
|
return _or_put(asset_id, payload)
|
||||||
# =============================================================================
|
|
||||||
|
def publish_influx(sid: str, sensor: dict, values: dict) -> bool:
|
||||||
|
"""Write sensor data to InfluxDB."""
|
||||||
|
if not _influx_write_api:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
stype = sensor["type"]
|
||||||
|
lat = sensor.get("lat", BASE_LAT)
|
||||||
|
lon = sensor.get("lon", BASE_LON)
|
||||||
|
|
||||||
|
points = []
|
||||||
|
for field, value in values.items():
|
||||||
|
if isinstance(value, (int, float)):
|
||||||
|
p = influxdb_client.Point(stype)\
|
||||||
|
.tag("sensor_id", sid)\
|
||||||
|
.tag("location", sensor.get("name", sid))\
|
||||||
|
.field(field, float(value))\
|
||||||
|
.field("lat", float(lat))\
|
||||||
|
.field("lon", float(lon))
|
||||||
|
points.append(p)
|
||||||
|
|
||||||
|
if points:
|
||||||
|
_influx_write_api.write(bucket=INFLUX_BUCKET, record=points)
|
||||||
|
print(f" 📈 InfluxDB: {len(points)} points written")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ⚠️ InfluxDB → {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("╔══════════════════════════════════════════════════╗")
|
print("╔══════════════════════════════════════════════════╗")
|
||||||
print("║ Smart City Simulator — Martinique ║")
|
print("║ Smart City Simulator — Martinique ║")
|
||||||
@@ -813,6 +863,17 @@ def main():
|
|||||||
ok_fr = publish_frost(sid, sensor, field, val)
|
ok_fr = publish_frost(sid, sensor, field, val)
|
||||||
print(f" 📊 FROST: {'✅' if ok_fr else '❌'}")
|
print(f" 📊 FROST: {'✅' if ok_fr else '❌'}")
|
||||||
|
|
||||||
|
# --- InfluxDB ---
|
||||||
|
if ENABLE_INFLUX:
|
||||||
|
influx_vals = {}
|
||||||
|
for field, val_range in ranges.items():
|
||||||
|
if isinstance(val_range, tuple) and len(val_range) == 2:
|
||||||
|
lo, hi = val_range
|
||||||
|
if isinstance(lo, (int, float)):
|
||||||
|
influx_vals[field] = round(random.uniform(lo, hi), 1)
|
||||||
|
ok_influx = publish_influx(sid, sensor, influx_vals)
|
||||||
|
print(f" 📈 InfluxDB: {'✅' if ok_influx else '❌'}")
|
||||||
|
|
||||||
# --- BunkerM HTTP ---
|
# --- BunkerM HTTP ---
|
||||||
if os.getenv("BUNKERM_HTTP", "0") == "1":
|
if os.getenv("BUNKERM_HTTP", "0") == "1":
|
||||||
ok_bunkerm = publish_bunkerm(sid, sensor, payload_mqtt)
|
ok_bunkerm = publish_bunkerm(sid, sensor, payload_mqtt)
|
||||||
|
|||||||
Reference in New Issue
Block a user