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 (tyle trwa okres, w którym zapisywane są liczniki). Zmień na T#300S (5 minut) jeśli chcesz większą redundancję na wypadek błędu połączenia. Jeśli sterownik pobiera też polecenia z GET /v1/strategy, ustaw T#60S: polecenie zależy od ostatniego odczytu SoC każdego magazynu, a gdy najnowszy odczyt któregokolwiek magazynu jest starszy niż 30 minut, serwer nie wybiera polecenia z planu, więc przy cyklu 15-minutowym jedno nieudane wysłanie może przełączyć sterownik w tryb zastępczy. Przykład zawsze wysyła rSoC i nie ma wejścia, które mówi, że odczyt z magazynu się nie powiódł. Jeśli Twój odczyt może się nie udać, dodaj takie wejście i w cyklu z nieudanym odczytem buduj sJson bez pary "soc", żeby serwer nigdy nie wziął starej wartości za świeżą.
  • 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. Ponowne wysłanie nigdy nie zapisze licznika dwa razy: licznik zapisany już w bieżącym 15-minutowym okresie zostanie pominięty. soc nie jest w ten sposób pomijany; zasady zapisu odczytów SoC opisuje POST /v1/ingest.
  • Kody urządzeń: muszą dokładnie odpowiadać konfiguracji w EnergyPal. Zweryfikuj za pomocą GET /v1/devices.
  • Inne urządzenia: 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. Kod 200 nie dowodzi, że zapisano wszystkie urządzenia: błędny kod urządzenia jest zgłoszony w device_results w sResponse.

Odbiór polecenia sterowania​

Aby sterować magazynem i falownikiem PV, sterownik pobiera polecenie z GET /v1/strategy raz na minutę. Ta strona opisuje pola odpowiedzi, bramkę strategy_valid, którą sterownik musi sprawdzić przed zastosowaniem polecenia, i zachowanie, gdy nie przychodzi świeża odpowiedź.

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