Fix simulator for cariflex.digitribe.fr domain - working ingestion
This commit is contained in:
@@ -1,21 +1,15 @@
|
||||
#!/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
|
||||
"""Cariflex Simulator - Posts data to FlexMeasures via session cookies."""
|
||||
import requests
|
||||
import random
|
||||
import math
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from flexmeasures_client import FlexMeasuresClient
|
||||
|
||||
FM_HOST = "https://flexmeasures.digitribe.fr"
|
||||
FM_HOST = "https://cariflex.digitribe.fr"
|
||||
FM_EMAIL = "admin@digitribe.fr"
|
||||
FM_PASSWORD = "Digitribe972"
|
||||
with open("/tmp/fm_pass.txt") as f:
|
||||
FM_PASSWORD=f.read().strip()
|
||||
|
||||
# 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}
|
||||
@@ -27,7 +21,6 @@ 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:
|
||||
@@ -54,57 +47,92 @@ def generate_value(cfg, hour):
|
||||
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)
|
||||
def main():
|
||||
print(f"Cariflex Simulator -> {FM_HOST}", flush=True)
|
||||
print(f" Sensors: {len(SENSORS)}", flush=True)
|
||||
|
||||
success = 0
|
||||
failed = 0
|
||||
# Create session with CSRF token handling
|
||||
session = requests.Session()
|
||||
session.verify = False # Self-signed cert
|
||||
|
||||
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}")
|
||||
# Get login page to extract CSRF token
|
||||
login_url = f"{FM_HOST}/login"
|
||||
r = session.get(login_url)
|
||||
print(f" Login page: {r.status_code}", flush=True)
|
||||
|
||||
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()
|
||||
# Extract CSRF token
|
||||
from html.parser import HTMLParser
|
||||
class CSRFParser(HTMLParser):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.token = None
|
||||
def handle_starttag(self, tag, attrs):
|
||||
if tag == "input":
|
||||
attrs = dict(attrs)
|
||||
if attrs.get("name") == "csrf_token":
|
||||
self.token = attrs.get("value")
|
||||
|
||||
client = FlexMeasuresClient(
|
||||
email=FM_EMAIL,
|
||||
password=FM_PASSWORD,
|
||||
host="flexmeasures.digitribe.fr",
|
||||
ssl=True,
|
||||
request_timeout=60.0
|
||||
)
|
||||
parser = CSRFParser()
|
||||
parser.feed(r.text)
|
||||
csrf_token = parser.token
|
||||
print(f" CSRF token: {csrf_token[:20] if csrf_token else 'NOT FOUND'}...", flush=True)
|
||||
|
||||
print("✅ Connected to FlexMeasures")
|
||||
# Login
|
||||
r = session.post(login_url, data={
|
||||
"email": FM_EMAIL,
|
||||
"password": FM_PASSWORD,
|
||||
"csrf_token": csrf_token,
|
||||
"remember": "y",
|
||||
}, allow_redirects=True)
|
||||
print(f" Login: {r.status_code} (url: {r.url})", flush=True)
|
||||
|
||||
# Check if logged in
|
||||
if "dashboard" in r.url or "login" not in r.url:
|
||||
print(f" Logged in successfully!", flush=True)
|
||||
else:
|
||||
print(f" WARNING: May not be logged in (url: {r.url})", flush=True)
|
||||
|
||||
# Post sensor data
|
||||
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})")
|
||||
hour = now.hour
|
||||
|
||||
await asyncio.sleep(30)
|
||||
success = 0
|
||||
failed = 0
|
||||
|
||||
for sensor_id, cfg in SENSORS.items():
|
||||
value = generate_value(cfg, hour)
|
||||
start = (now - timedelta(minutes=5)).isoformat()
|
||||
|
||||
try:
|
||||
r = session.post(
|
||||
f"{FM_HOST}/api/v3_0/sensors/{sensor_id}/data",
|
||||
json={
|
||||
"values": [value],
|
||||
"start": start,
|
||||
"duration": "PT5M",
|
||||
"unit": cfg["unit"],
|
||||
"type": "PostSensorDataRequest",
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
if r.status_code in [200, 201]:
|
||||
success += 1
|
||||
else:
|
||||
failed += 1
|
||||
if failed <= 3:
|
||||
print(f" Sensor {sensor_id}: HTTP {r.status_code} - {r.text[:100]}", flush=True)
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
if failed <= 3:
|
||||
print(f" Sensor {sensor_id}: {e}", flush=True)
|
||||
|
||||
iteration += 1
|
||||
print(f" Iteration {iteration}: {success} OK, {failed} failed (hour={hour})", flush=True)
|
||||
|
||||
import time
|
||||
time.sleep(30)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user