Flex Platform API

EMS & BRP/BSP integratie

Base URL:https://fbkhhcsplwxkorfhgqwr.supabase.co

Overzicht

De publieke EnerSim Flex API beschrijft twee integratievlakken: het aanleveren van live meetdata vanuit uw EMS en het ontvangen van orders aan BRP/BSP zijde. De interne optimalisatie (solver) is geen publiek endpoint — deze wordt geactiveerd via de Flex pagina nadat EnerSim de EMS-verbinding heeft goedgekeurd.

EMS Bearer Token

Statisch token gekoppeld aan een locatie. Genereer via het EMS-paneel in de locatiedetails.

JWT Sessie Token

Gebruikers-JWT van Supabase Auth. Gebruik na inloggen via supabase.auth.signIn().

WebSocket integratie

Naast REST ondersteunt het platform twee optionele WebSocket-kanalen per locatie: een inbound stream (uw EMS → EnerSim) voor real-time telemetrie, en een outbound stream (EnerSim → uw EMS) voor directe setpoint-updates. REST blijft de canonieke fallback: als de WebSocket wegvalt, blijft het EMS op het laatst via ems-setpoints-push ontvangen volledige dagprofiel doordraaien.

Optioneel

WS is niet verplicht. Activeer per locatie via transport-modus REST / WS / beide.

Zelfde token

Inbound WS gebruikt het bestaande EMS Bearer token — geen extra credentials.

WS/functions/v1/ems-ws-ingress Bearer Token vereist

EMS → EnerSim — Live telemetrie (inbound)

Open een persistente WebSocket vanaf uw EMS naar dit endpoint. Elke binnenkomende frame wordt gevalideerd en in real-time doorgeleverd naar het Flex-dashboard via Supabase Realtime.

Connection URL

wss://fbkhhcsplwxkorfhgqwr.supabase.co/functions/v1/ems-ws-ingress

Het token kan op drie manieren worden meegegeven, kies er één:

  • HTTP header: Authorization: Bearer <token>
  • Query parameter: ?token=<token> (nuttig voor browser-clients)
  • Sec-WebSocket-Protocol: bearer, <token>

Frame schema (client → server)

tsstring (ISO 8601)optioneel

Timestamp in UTC. Valt terug op server-tijd als leeg.

power_kwnumberoptioneel

Netto vermogen in kW (positief = import)

soc_percentnumber (0–100)optioneel

Batterij state of charge

pv_kwnumberoptioneel

PV productie in kW

load_kwnumberoptioneel

Site belasting in kW

battery_kwnumberoptioneel

Batterijvermogen in kW (positief = laden)

ev_kwnumberoptioneel

EV laadvermogen in kW

grid_kwnumberoptioneel

Netuitwisseling in kW

typestringoptioneel

Gebruik "ping" om een keep-alive te sturen.

Voorbeeld frame

{
  "ts": "2026-04-23T08:15:00Z",
  "power_kw": 45.2,
  "soc_percent": 68.5,
  "pv_kw": 32.1,
  "load_kw": 77.3,
  "battery_kw": -10.0,
  "ev_kw": 7.4,
  "grid_kw": 45.2
}

Server → client messages

Bevestiging per frame

{ "type": "ack", "ts": "2026-04-23T08:15:00Z" }

Ping

{ "type": "ping" }

Pong

{ "type": "pong", "t": 1745395123456 }

Connectie-lifecycle

  • Bij open ontvangt u { "type": "hello", "location_id": "…", "session_id": "…" }.
  • Stuur elke 20 seconden een ping om de sessie levend te houden achter load balancers.
  • Ongeldige JSON en validatiefouten komen terug als { "type": "error", "message": "…" }. De socket wordt niet gesloten.
  • Implementeer reconnect met exponential backoff (1 s → 30 s cap) en jitter.
  • Rate limit: 60 frames per minuut per token (te hoge frequentie resulteert in 429 bij upgrade).

Node.js (ws)

import WebSocket from "ws";

const url = "https://fbkhhcsplwxkorfhgqwr.supabase.co/functions/v1/ems-ws-ingress";
const token = process.env.EMS_BEARER_TOKEN;

const ws = new WebSocket(url, {
  headers: { Authorization: `Bearer ${token}` },
});

ws.on("open", () => {
  setInterval(() => {
    ws.send(JSON.stringify({
      ts: new Date().toISOString(),
      power_kw: readPowerKw(),
      soc_percent: readSoc(),
      pv_kw: readPv(),
    }));
  }, 5000);
});

ws.on("message", data => {
  const msg = JSON.parse(data.toString());
  if (msg.type === "ack") { /* ok */ }
  if (msg.type === "error") console.warn("ingress error:", msg.message);
});

ws.on("close", () => {
  // reconnect met exponential backoff
});

Browser / Deno

const ws = new WebSocket(
  "https://fbkhhcsplwxkorfhgqwr.supabase.co/functions/v1/ems-ws-ingress?token=" + encodeURIComponent(token)
);
ws.onopen = () => ws.send(JSON.stringify({ ts: new Date().toISOString(), power_kw: 12.3 }));
ws.onmessage = e => console.log("msg", JSON.parse(e.data));
WS{uw_ems_ws_url} HMAC-SHA256 signering

EnerSim → EMS — Setpoint-stream (outbound)

EnerSim opent een korte uitgaande WebSocket naar de URL die u op de Flex pagina configureert (transport-modus ws of beide). Na elke solver-run of BRP-override wordt een frame gepubliceerd met het effectieve setpoint voor de komende kwartieren. Uw EMS bevestigt implicit door de setpoints toe te passen.

Connectieparameters

  • Uw endpoint moet een wss:// URL zijn.
  • Configureer optioneel een Bearer token: EnerSim stuurt deze mee als Sec-WebSocket-Protocol bearer, <token>.
  • Eerste bericht is het setpoint-frame.
  • EnerSim sluit de verbinding 200 ms na verzending; bewaar geen langlevende sessies aan EMS-zijde.
  • Bij timeout of foutstatus wordt de verbinding gemarkeerd als error; het EMS valt terug op het laatst via REST ontvangen dagprofiel.

Frame schema

versionstringverplicht

Schema-versie, momenteel "1.0".

typestringverplicht

Altijd "setpoint_update".

locationobjectverplicht

id + name van de locatie.

generated_atstring (ISO 8601 UTC)verplicht

Tijdstip waarop EnerSim het frame heeft samengesteld.

horizon_start_utcstring (ISO 8601 UTC)verplicht

Begin van het eerste slot (15 minuten).

slotsarrayverplicht

Tot 8 kwartierslots vanaf horizon_start_utc.

ts_utcstringverplicht

Start van het slot (UTC).

effective_kwnumberverplicht

Setpoint dat het EMS moet toepassen (positief = import, negatief = export).

scheduled_kwnumberoptioneel

Origineel gepland setpoint voor dit slot.

brp_override_kwnumber | nulloptioneel

BRP-override, indien van toepassing.

override_reasonstring | nulloptioneel

Toelichting op de override.

Voorbeeld setpoint frame

{
  "version": "1.0",
  "type": "setpoint_update",
  "location": { "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "name": "Mijn site" },
  "generated_at": "2026-04-23T08:14:58Z",
  "horizon_start_utc": "2026-04-23T08:15:00Z",
  "slots": [
    {
      "ts_utc": "2026-04-23T08:15:00Z",
      "effective_kw": -12.5,
      "scheduled_kw": -12.5,
      "brp_override_kw": null,
      "override_reason": null
    },
    {
      "ts_utc": "2026-04-23T08:30:00Z",
      "effective_kw": 20.0,
      "scheduled_kw": 8.0,
      "brp_override_kw": 20.0,
      "override_reason": "BRP curtailment"
    }
  ]
}
Fallback-gedrag: Elk volledig horizon-profiel wordt óók via REST (/functions/v1/ems-setpoints-push) gepusht. Het EMS moet autonoom op het laatst bekende REST-profiel kunnen doordraaien zodra de WS-verbinding langer dan één slot (15 min) wegvalt.

Rate Limits & Best Practices

  • Max. 100 records per ingest request
  • Max. 1000 ingest requests per uur per locatie
  • Stuur data elke 1 minuut voor optimale forecasting
  • Gebruik altijd UTC timestamps
  • Implementeer exponential backoff bij 429 errors
  • Voeg zoveel mogelijk metadata toe voor betere forecasts
  • Roteer de Bearer token elke 90 dagen
  • Vraag solver-activering pas aan nadat de EMS verbindingstest is geslaagd