#!/usr/bin/env python3 """Cariflex - Crée les sensors et injecte données météo/prix.""" import json import requests import re import warnings import random from datetime import datetime, timezone, timedelta import pytz warnings.filterwarnings("ignore") FM_HOST = "https://cariflex.digitribe.fr" CREDS_FILE = "/tmp/fm_creds.json" MARTINIQUE_TZ = pytz.timezone("America/Martinique") with open(CREDS_FILE) as f: creds = json.load(f) session = requests.Session() session.verify = False # Login r = session.get(f"{FM_HOST}/login") match = re.search(r']*csrf_token[^>]*value="([^"]+)"', r.text) csrf = match.group(1) r = session.post(f"{FM_HOST}/login", data={ "email": creds["email"], "password": creds["password"], "csrf_token": csrf, "remember": "y" }, allow_redirects=True) print(f"Login: {'OK' if 'dashboard' in r.url else 'FAILED'}") RESOLUTION = "PT1H" print("\n=== Création des sensors ===") sensors_to_create = [ {"name": "irradiance", "unit": "W/m²", "generic_asset_id": 81, "event_resolution": RESOLUTION}, {"name": "temperature", "unit": "°C", "generic_asset_id": 81, "event_resolution": RESOLUTION}, {"name": "wind_speed", "unit": "m/s", "generic_asset_id": 81, "event_resolution": RESOLUTION}, {"name": "consumption_price", "unit": "EUR/MWh", "generic_asset_id": 82, "event_resolution": RESOLUTION}, {"name": "production_price", "unit": "EUR/MWh", "generic_asset_id": 82, "event_resolution": RESOLUTION}, ] created_sensors = {} for s in sensors_to_create: r = session.post(f"{FM_HOST}/api/v3_0/sensors", json=s) if r.status_code == 201: sid = r.json().get("id") created_sensors[s["name"]] = sid print(f" ✓ Sensor '{s['name']}' (ID {sid})") if not created_sensors: # Find existing sensors r = session.get(f"{FM_HOST}/api/v3_0/sensors") for s in r.json(): if s["name"] in ["irradiance", "temperature", "wind_speed", "consumption_price", "production_price"]: created_sensors[s["name"]] = s["id"] print(f" Found sensor '{s['name']}' (ID {s['id']})") print(f"\nSensors: {created_sensors}") # Inject weather data from Open-Meteo print("\n=== Données météo réelles ===") LAT, LON = 14.6091, -61.2155 today = datetime.now(MARTINIQUE_TZ).strftime("%Y-%m-%d") try: resp = requests.get( f"https://api.open-meteo.com/v1/forecast?" f"latitude={LAT}&longitude={LON}" f"&hourly=shortwave_radiation,temperature_2m,wind_speed_10m" f"&timezone=America/Martinique" f"&start_date={today}&end_date={today}", timeout=15 ) if resp.status_code == 200: wdata = resp.json() times = wdata["hourly"]["time"] for sensor_name, (key, unit) in { "irradiance": ("shortwave_radiation", "W/m²"), "temperature": ("temperature_2m", "°C"), "wind_speed": ("wind_speed_10m", "m/s") }.items(): if sensor_name not in created_sensors: continue sensor_id = created_sensors[sensor_name] values = wdata["hourly"][key] posted = 0 for i, t in enumerate(times): dt = datetime.fromisoformat(t) r = session.post(f"{FM_HOST}/api/v3_0/sensors/{sensor_id}/data", json={"values": [round(max(0, values[i]), 1)], "start": dt.isoformat(), "duration": RESOLUTION, "unit": unit}, timeout=30) if r.status_code in [200, 201, 202]: posted += 1 print(f" '{sensor_name}': {posted}/{len(times)} posted") else: print(f" API error: {resp.status_code}") except Exception as e: print(f" Error: {e}") # Inject DSO prices (24h) print("\n=== Prix DSO ===") if "consumption_price" in created_sensors and "production_price" in created_sensors: c_id = created_sensors["consumption_price"] p_id = created_sensors["production_price"] now_utc = datetime.now(timezone.utc) posted = 0 for h in range(24): dt = now_utc - timedelta(hours=23-h) hd = dt.hour cp = round(random.uniform(80, 150) if 6 <= hd <= 22 else random.uniform(40, 80), 2) pp = round(random.uniform(60, 120) if 6 <= hd <= 22 else random.uniform(30, 60), 2) for sid, price in [(c_id, cp), (p_id, pp)]: r = session.post(f"{FM_HOST}/api/v3_0/sensors/{sid}/data", json={"values": [price], "start": dt.isoformat(), "duration": RESOLUTION, "unit": "EUR/MWh"}, timeout=30) if r.status_code in [200, 201, 202]: posted += 1 print(f" Prix injectés: {posted}") print("\n=== Terminé ===")