OpenADR VTN/VEN deployment + Grafana dashboard update
This commit is contained in:
106
scripts/openadr_ven.py
Normal file
106
scripts/openadr_ven.py
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Cariflex - OpenADR VEN (Virtual End Node)
|
||||
Reçoit les signaux DSR du VTN et les transmet à FlexMeasures.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from openleadr import OpenADRClient, enable_default_logging
|
||||
import requests
|
||||
import re
|
||||
|
||||
enable_default_logging()
|
||||
logger = logging.getLogger("openleadr")
|
||||
|
||||
FM_HOST = "https://cariflex.digitribe.fr"
|
||||
FM_EMAIL = "admin@digitribe.fr"
|
||||
FM_PASSWORD = "Digitribe972"
|
||||
VEN_ID = "Cariflex-VEN"
|
||||
VTN_URL = "http://localhost:8081"
|
||||
|
||||
# Sensor IDs in FM
|
||||
SENSOR_CONSUMPTION_PRICE = 84
|
||||
SENSOR_LOAD_CONTROL = 86
|
||||
|
||||
|
||||
def fm_login():
|
||||
session = requests.Session()
|
||||
session.verify = False
|
||||
r = session.get(f"{FM_HOST}/login")
|
||||
match = re.search(r'<input[^>]*csrf_token[^>]*value="([^"]+)"', r.text)
|
||||
if match:
|
||||
csrf = match.group(1)
|
||||
r = session.post(f"{FM_HOST}/login", data={
|
||||
"email": FM_EMAIL, "password": FM_PASSWORD,
|
||||
"csrf_token": csrf, "remember": "y"
|
||||
}, allow_redirects=True)
|
||||
if "dashboard" in r.url:
|
||||
return session
|
||||
return None
|
||||
|
||||
|
||||
def post_sensor_data(session, sensor_id, value, unit, start, duration="PT1H"):
|
||||
r = session.post(
|
||||
f"{FM_HOST}/api/v3_0/sensors/{sensor_id}/data",
|
||||
json={"values": [value], "start": start, "duration": duration, "unit": unit},
|
||||
timeout=30
|
||||
)
|
||||
return r.status_code in [200, 201, 202]
|
||||
|
||||
|
||||
async def main():
|
||||
client = OpenADRClient(
|
||||
ven_id=VEN_ID,
|
||||
ven_name=VEN_ID,
|
||||
vtn_url=VTN_URL,
|
||||
)
|
||||
|
||||
logger.info(f"Starting Cariflex VEN: {VEN_ID}")
|
||||
logger.info(f"Connecting to VTN: {VTN_URL}")
|
||||
|
||||
# Login to FM
|
||||
session = fm_login()
|
||||
if session:
|
||||
logger.info("Logged in to FlexMeasures")
|
||||
else:
|
||||
logger.error("Failed to login to FlexMeasures")
|
||||
return
|
||||
|
||||
# Add event handler
|
||||
@client.on_event
|
||||
async def handle_event(event):
|
||||
logger.info(f"Received event: {event}")
|
||||
|
||||
# Extract signal data
|
||||
for signal in event.get("event_signals", []):
|
||||
signal_name = signal.get("signal_name")
|
||||
|
||||
for interval in signal.get("intervals", []):
|
||||
payload = interval.get("signal_payload", 0)
|
||||
dtstart = interval.get("dtstart", datetime.now(timezone.utc))
|
||||
|
||||
if signal_name == "ENERGY_PRICE":
|
||||
price = round(float(payload), 2)
|
||||
success = post_sensor_data(
|
||||
session, SENSOR_CONSUMPTION_PRICE, price, "EUR/MWh",
|
||||
dtstart.isoformat() if isinstance(dtstart, datetime) else str(dtstart)
|
||||
)
|
||||
logger.info(f"Price {price} EUR/MWh: {success}")
|
||||
|
||||
elif signal_name == "LOAD_CONTROL":
|
||||
success = post_sensor_data(
|
||||
session, SENSOR_LOAD_CONTROL, round(float(payload), 2), "%",
|
||||
dtstart.isoformat() if isinstance(dtstart, datetime) else str(dtstart)
|
||||
)
|
||||
logger.info(f"Load control {payload}: {success}")
|
||||
|
||||
return "optIn"
|
||||
|
||||
# Run the client
|
||||
await client.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user