Przejdź do głównej zawartości

Integracja PLC: WAGO PFC200 + CODESYS 3.5

Kompletny przewodnik konfiguracji sterownika WAGO PFC200 do wysyłania metryk PV i magazynu energii do EnergyPal przez HTTP POST.

Wymagania

  • Sterownik: WAGO PFC200 (750-8212) z e!RUNTIME
  • Biblioteki CODESYS: WagoAppHTTP, WagoTypes — zainstaluj przez Library Manager w środowisku CODESYS IDE
  • Sieć: sterownik musi mieć dostęp do internetu (port 443/HTTPS). WAGO PFC200 zawiera wbudowane certyfikaty CA.
  • Klucz API: Twój energy_connection_key od administratora EnergyPal
  • Skonfigurowane urządzenia: kody urządzeń (np. PV-1, BESS-1) muszą być zarejestrowane w EnergyPal. Zweryfikuj za pomocą GET /v1/devices.

Krok 1: Deklaracja bloku funkcyjnego FB_EnergyPalSender

Utwórz nowy POU typu FUNCTION_BLOCK w projekcie CODESYS. Wklej poniższą deklarację zmiennych:

FUNCTION_BLOCK FB_EnergyPalSender
VAR_INPUT
rSoC : REAL; (* Stan naladowania BESS [%] *)
rEnergyExported : REAL; (* Licznik rozladowania BESS [kWh] *)
rEnergyImported : REAL; (* Licznik ladowania BESS [kWh] *)
rPvGenerated1 : REAL; (* Licznik produkcji PV-1 [kWh] *)
rPvGenerated2 : REAL; (* Licznik produkcji PV-2 [kWh] *)
rEnergyConsumed : REAL; (* Licznik zuzycia LOAD-0 [kWh] *)
END_VAR
VAR_OUTPUT
bBusy : BOOL; (* Wysylanie w toku *)
bError : BOOL; (* Blad ostatniego wysylania *)
iHttpStatus : INT; (* Kod odpowiedzi HTTP *)
END_VAR
VAR
fbHttpClient : WagoAppHTTP.WagoHTTPClient;
fbTimer : TON;
bSend : BOOL;
bRequestDone : BOOL;
sJson : STRING(2048);
sUrl : STRING(255) := 'https://api.energypal.ai/v1/ingest';
sApiKey : STRING(255) := 'twoj-klucz-api'; (* <- wstaw swoj klucz *)
sContentType : STRING(64) := 'application/json';
sResponse : STRING(1024);
END_VAR

Zmień wartość sApiKey na swój klucz API. Jeśli masz inne kody urządzeń niż PV-1, PV-2, BESS-1, LOAD-0 — dostosuj je w implementacji poniżej.

Krok 2: Implementacja bloku

W zakładce implementacji bloku FB_EnergyPalSender wklej poniższy kod. Blok buduje JSON z aktualnymi wartościami metryk i wysyła go przez HTTP POST co 15 minut:

(* === Cykliczny timer - wysylanie co 15 minut === *)
fbTimer(IN := NOT fbTimer.Q, PT := T#900S);

IF fbTimer.Q AND NOT bBusy THEN
bSend := TRUE;
END_IF

(* === Budowanie JSON === *)
IF bSend THEN
bSend := FALSE;
bBusy := TRUE;
bError := FALSE;

sJson := CONCAT('{"metrics":{',
'"PV-1":{"energy_generated_meter":', REAL_TO_STRING(rPvGenerated1), '},',
'"PV-2":{"energy_generated_meter":', REAL_TO_STRING(rPvGenerated2), '},',
'"BESS-1":{"soc":', REAL_TO_STRING(rSoC),
',"energy_exported_meter":', REAL_TO_STRING(rEnergyExported),
',"energy_imported_meter":', REAL_TO_STRING(rEnergyImported),
'},',
'"LOAD-0":{"energy_consumed_meter":', REAL_TO_STRING(rEnergyConsumed),
'}}}');

(* === Konfiguracja i wysylanie HTTP POST === *)
fbHttpClient.sUrl := sUrl;
fbHttpClient.sContentType := sContentType;
fbHttpClient.sRequestData := sJson;
fbHttpClient.bExecute := TRUE;

(* Dodaj naglowek X-API-Key *)
fbHttpClient.AddHeader('X-API-Key', sApiKey);
END_IF

(* === Obsluga odpowiedzi === *)
fbHttpClient();

IF fbHttpClient.bDone OR fbHttpClient.bError THEN
bBusy := FALSE;
iHttpStatus := fbHttpClient.iStatusCode;
bError := fbHttpClient.bError OR (iHttpStatus <> 200);
sResponse := fbHttpClient.sResponseData;
fbHttpClient.bExecute := FALSE;
END_IF

Krok 3: Wywołanie w PLC_PRG

W głównym programie PLC_PRG utwórz instancję bloku i podłącz zmienne procesowe ze swojej instalacji:

PROGRAM PLC_PRG
VAR
fbSender : FB_EnergyPalSender;

(* --- Wstaw tutaj swoje zmienne procesowe --- *)
rSoC_BMS : REAL; (* np. odczyt z Modbus / wejscia analogowego *)
rExportMeter_BMS : REAL;
rImportMeter_BMS : REAL;
rPvMeter_Inverter1 : REAL;
rPvMeter_Inverter2 : REAL;
rConsumptionMeter : REAL; (* calkowite zuzycie energii [kWh] *)
END_VAR

(* Wywolanie bloku wysylajacego *)
fbSender(
rSoC := rSoC_BMS,
rEnergyExported := rExportMeter_BMS,
rEnergyImported := rImportMeter_BMS,
rPvGenerated1 := rPvMeter_Inverter1,
rPvGenerated2 := rPvMeter_Inverter2,
rEnergyConsumed := rConsumptionMeter
);

(* Opcjonalnie: diagnostyka w wizualizacji *)
(* fbSender.bBusy - czy trwa wysylanie *)
(* fbSender.bError - czy ostatnie wyslanie sie nie powiodlo *)
(* fbSender.iHttpStatus - kod HTTP odpowiedzi (200 = OK) *)

Uwagi konfiguracyjne

  • Interwał wysyłania: timer T#900S oznacza wysyłanie co 15 minut (zgodnie z interwałem agregacji systemu). Zmień na T#300S (5 minut) jeśli chcesz większą redundancję na wypadek błędu połączenia.
  • Liczniki kumulatywne: wartości energy_*_meter muszą być zawsze rosnące. Nigdy nie resetuj — system automatycznie oblicza przyrost energii.
  • Obsługa błędów: jeśli iHttpStatus jest różny od 200, blok automatycznie ponowi wysyłanie przy następnym cyklu timera. System jest idempotentny — duplikaty w 15-minutowym oknie są pomijane.
  • Kody urządzeń: muszą dokładnie odpowiadać konfiguracji w EnergyPal. Zweryfikuj za pomocą GET /v1/devices.
  • Device codes: jeśli masz inną liczbę inwerterów lub magazynów, dostosuj budowanie stringa sJson w implementacji.
  • Diagnostyka: zmienne wyjściowe bBusy, bError, iHttpStatus możesz podłączyć do wizualizacji CODESYS, aby monitorować status wysyłania.

Odczyt cen energii

Aby pobierać prognozy cen energii na sterowniku WAGO (do optymalizacji magazynu), zobacz dedykowany przewodnik: Odczyt cen energii (WAGO + CODESYS).

Testowanie za pomocą curl

Przed konfiguracją PLC przetestuj połączenie z API:

# Wysłanie testowych danych
curl -X POST https://api.energypal.ai/v1/ingest \
-H "Content-Type: application/json" \
-H "X-API-Key: twoj-klucz-api" \
-d '{
"metrics": {
"PV-1": {"energy_generated_meter": 12345.0},
"BESS-1": {"soc": 85.5, "energy_exported_meter": 500.0, "energy_imported_meter": 450.0},
"LOAD-0": {"energy_consumed_meter": 98765.0}
}
}'

# Weryfikacja kodów urządzeń
curl -H "X-API-Key: twoj-klucz-api" https://api.energypal.ai/v1/devices