Files
cariflex/scripts/cariflex_simulator.py
Eric F 6fe79471f3 Fix simulator (use FM client), install entsoe+weather plugins, fix Redis
- Simulator rewritten to use flexmeasures_client (works!)
- flexmeasures-entsoe installed (ENTSO-E data import)
- flexmeasures-weather installed (weather data)
- FlexMeasures Redis connection fixed (DNS resolution)
- Dashboard Grafana updated with Cariflex asset types
- Simulator running in background, posting to 40 sensors

TODO:
- S2 CEM deployment
- Scheduler FlexMeasures
- Logo Cariflex in FM UI
2026-06-08 08:33:16 -04:00

111 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""
Cariflex Simulator - Publishes simulated data to FlexMeasures API.
Uses flexmeasures_client for authentication and data posting.
Simulates 40 assets: 10 PV, 10 Battery, 10 EV Charger, 10 EV V2G
"""
import asyncio
import time
import random
import math
from datetime import datetime, timezone, timedelta
from flexmeasures_client import FlexMeasuresClient
FM_HOST = "https://flexmeasures.digitribe.fr"
FM_EMAIL = "admin@digitribe.fr"
FM_PASSWORD = "Digitribe972"
# Sensor mapping: sensor_id -> (name, type, unit, min, max)
SENSORS = {}
for i in range(1, 11):
SENSORS[40 + i] = {"name": f"pv_{i:02d}_power", "type": "pv", "unit": "kW", "min": 0, "max": 5}
for i in range(1, 11):
SENSORS[50 + i] = {"name": f"bat_{i:02d}_power", "type": "battery", "unit": "kWh", "min": 10, "max": 100}
for i in range(1, 11):
SENSORS[60 + i] = {"name": f"chg_{i:02d}_power", "type": "ev_charger", "unit": "kW", "min": 0, "max": 22}
for i in range(1, 11):
SENSORS[70 + i] = {"name": f"ev_{i:02d}_power", "type": "ev_v2g", "unit": "kWh", "min": 15, "max": 75}
def generate_value(cfg, hour):
"""Generate realistic value based on asset type and time of day."""
t = cfg["type"]
if t == "pv":
if 6 <= hour <= 18:
factor = max(0, math.sin((hour - 6) * math.pi / 12))
else:
factor = 0
return round(max(0, cfg["max"] * factor + random.gauss(0, 0.3)), 2)
elif t == "battery":
base = 50 + 30 * math.sin((hour - 6) * math.pi / 12)
return round(max(cfg["min"], min(cfg["max"], base + random.gauss(0, 2))), 2)
elif t == "ev_charger":
if 8 <= hour <= 22:
factor = random.uniform(0.2, 1.0)
else:
factor = random.uniform(0, 0.15)
return round(max(0, cfg["max"] * factor + random.gauss(0, 0.5)), 2)
elif t == "ev_v2g":
if 0 <= hour <= 6:
base = 60
elif 17 <= hour <= 21:
base = 30
else:
base = 45
return round(max(cfg["min"], min(cfg["max"], base + random.gauss(0, 3))), 2)
return 0
async def post_all_data(client):
"""Post data for all 40 sensors."""
now = datetime.now(timezone.utc)
hour = now.hour
start = now - timedelta(minutes=5)
success = 0
failed = 0
for sensor_id, cfg in SENSORS.items():
value = generate_value(cfg, hour)
try:
await client.post_sensor_data(
sensor_id=sensor_id,
values=[value],
start=start.isoformat(),
duration="PT5M",
unit=cfg["unit"]
)
success += 1
except Exception as e:
failed += 1
if failed <= 3:
print(f" ⚠️ Sensor {sensor_id}: {e}")
return success, failed
async def main():
print("🚗 Cariflex Simulator → FlexMeasures API")
print(f" Sensors: {len(SENSORS)} (10 PV, 10 Bat, 10 Chg, 10 EV)")
print(f" FM API: {FM_HOST}")
print()
client = FlexMeasuresClient(
email=FM_EMAIL,
password=FM_PASSWORD,
host="flexmeasures.digitribe.fr",
ssl=True,
request_timeout=60.0
)
print("✅ Connected to FlexMeasures")
iteration = 0
while True:
success, failed = await post_all_data(client)
iteration += 1
now = datetime.now(timezone.utc)
print(f" 📊 Iteration {iteration}: {success} OK, {failed} failed (hour={now.hour})")
await asyncio.sleep(30)
if __name__ == "__main__":
asyncio.run(main())