Zanim zaczniesz
- Node-RED włączony. Cerbo GX z Venus OS Large i włączonym Node-RED; edytor otwiera się pod adresem
https://venus.local:1881. Jak to zrobić: pierwsze uruchomienie Node-RED. - Monitor baterii widoczny w GX. SoC pochodzi z monitora baterii albo BMS podłączonego do GX, np. SmartShunt, BMV czy Lynx Shunt. Jeśli GX nie pokazuje stanu naładowania, Node-RED też go nie dostanie.
- Przekaźnik w trybie ręcznym. Victron: przekaźnik da się sterować z Node-RED dopiero po przełączeniu go na sterowanie ręczne. Dla przekaźników Cerbo GX: Settings → Integrations → Relays, funkcja „Manual”. W tym samym menu jest też polaryzacja przekaźnika (normalnie otwarty albo normalnie zamknięty).

Inne przekaźniki też da się sterować z Node-RED, ale każdy trzeba najpierw przestawić: w BMV opcję przekaźnika na REM (w VictronConnect), w Lynx Shunt VE.Can funkcję na „Manual control” (w menu GX), w większych regulatorach MPPT i w urządzeniach serii RS tryb ręczny (w VictronConnect). Przekaźnika Lynx Smart BMS nie da się sterować z Node-RED. Nie da się też sterować przekaźnikiem alarmowym ani stycznikiem AC-out 2 w MultiPlusie i Quattro.
Chcesz uruchamiać agregat? Do tego GX ma wbudowany automatyczny start i stop agregatu przekaźnikiem, z własnymi warunkami startu (w instrukcji GX rozdział „Generator auto start/stop”), i Node-RED nie jest potrzebny. Przykład Victron z agregatem (niżej) nie steruje przekaźnikiem bezpośrednio, tylko używa węzła Generator.
Jak działa ten flow
- Battery (input)Stan naładowania z monitora baterii — przy każdej zmianie, a bez „only changes” także co 5 s.
- histereza (function)SoC ≤ 30% → 1, SoC ≥ 50% → 0, pomiędzy bez zmian. Wysyła tylko zmianę stanu.
- Relay (output)1 zamyka, 0 otwiera przekaźnik 1 w Cerbo GX (/Relay/0/State).
- debugPokazuje w panelu Debug każdą wartość wysłaną do przekaźnika.
Budowa krok po kroku
- Nowa zakładka. W edytorze Node-RED dodaj nową zakładkę flow (przycisk „+” nad obszarem roboczym), żeby przykład nie mieszał się z innymi flow.
- Węzeł Battery. Z sekcji węzłów Victron w palecie przeciągnij węzeł wejściowy Battery. W jego ustawieniach wybierz swój monitor baterii i pomiar „State of charge (%)”. Pole „only changes” zostaw puste — wtedy węzeł wysyła SoC przy każdej zmianie i dodatkowo co 5 sekund, więc funkcja szybko dostaje wartość także po restarcie.
- Węzeł function. Dodaj zwykły węzeł function, nazwij go „histereza” i wklej kod z sekcji „Kod histerezy”. Połącz wyjście węzła Battery z wejściem funkcji.
- Węzeł Relay. Dodaj węzeł wyjściowy Relay, wybierz „Venus device” i „Venus relay 1 state” (ścieżka
/Relay/0/State— numeracja w ścieżce zaczyna się od 0, więc indeks 0 to przekaźnik 1). Węzeł ustawia to, co dostanie wmsg.payload: 0 — Open, 1 — Closed. Połącz z nim wyjście funkcji. - Węzeł debug. Podłącz do wyjścia funkcji także węzeł debug. Wartości zobaczysz w panelu Debug po prawej stronie edytora, a pod węzłem „histereza” — bieżący SoC i stan przekaźnika.
- Deploy i test. Kliknij Deploy. Żeby nie czekać na rozładowanie baterii, dołóż tymczasowo węzeł inject z wartością liczbową (typ „number”, np. 25, a potem 55) podłączony do funkcji i sprawdź, czy przekaźnik w menu Relays się przełącza. Potem usuń inject i znowu kliknij Deploy.
Kod histerezy
Gdyby przekaźnik miał się włączać i wyłączać przy jednym progu, np. 40%, to przy SoC wahającym się wokół tej wartości przełączałby się raz za razem. Histereza rozdziela te progi: przekaźnik zamyka się przy 30% lub mniej, a otwiera dopiero przy 50% lub więcej. Pomiędzy zostaje w poprzednim stanie. Funkcja pamięta ten stan w kontekście węzła i wysyła wiadomość tylko przy zmianie, więc do przekaźnika nie trafia ta sama wartość co 5 sekund.
// Histereza: zamknij przekaźnik przy SoC <= 30 %, otwórz przy SoC >= 50 %.
// Progi są przykładowe - ustaw własne.
const PROG_ZAL = 30;
const PROG_WYL = 50;
const soc = msg.payload;
if (typeof soc !== 'number' || isNaN(soc)) return null; // brak odczytu: nic nie rób
const poprzedni = context.get('stan');
let stan = (poprzedni === undefined) ? 0 : poprzedni;
if (soc <= PROG_ZAL) stan = 1; // 1 = Closed
else if (soc >= PROG_WYL) stan = 0; // 0 = Open
// pomiędzy progami stan się nie zmienia
node.status({fill: stan ? 'green' : 'grey', shape: 'dot',
text: 'SoC ' + soc.toFixed(1) + ' %, przekaźnik ' + (stan ? 'zamknięty' : 'otwarty')});
if (stan === poprzedni) return null; // wysyłaj tylko zmianę
context.set('stan', stan);
msg.payload = stan;
return msg;
| SoC | Co robi funkcja | Przekaźnik |
|---|---|---|
| 60% | pierwszy odczyt, 50% lub więcej → wysyła 0 | otwarty |
| 40% | między progami — nic nie wysyła | otwarty |
| 30% | 30% lub mniej → wysyła 1 | zamknięty |
| 45% | między progami — nic nie wysyła | zamknięty |
| 50% | 50% lub więcej → wysyła 0 | otwarty |
- Odwrotna logika. Chcesz odłączać odbiornik przy niskim SoC, a nie go włączać? Zamień w kodzie 1 i 0 w dwóch liniach z progami albo podłącz obwód do drugiego styku przekaźnika — NC zamiast NO.
- Brak odczytu. Jeśli
msg.payloadnie jest liczbą (np. monitor baterii zniknął), funkcja nic nie wysyła i przekaźnik zostaje w dotychczasowym stanie. - Po restarcie. Kontekst węzła jest domyślnie w pamięci RAM urządzenia GX i znika przy restarcie albo zaniku zasilania. Pierwszy odczyt po restarcie zawsze ustawia przekaźnik: przy SoC między progami na 0 (otwarty) — także wtedy, gdy przed restartem był zamknięty. Jak zachować kontekst, opisuje sekcja „Na co uważać”.
Gotowy flow do importu
Ten sam flow w formacie JSON. Węzły Victron są zbudowane tak jak w przykładach z dokumentacji palety node-red-contrib-victron.
- Skopiuj cały blok poniżej, razem z nawiasami
[i]. - Import. W edytorze otwórz menu (przycisk w prawym górnym rogu) → Import albo naciśnij Ctrl-I, wklej tekst i kliknij Import. Flow pojawi się w nowej zakładce „Przekaźnik wg SoC”.
- Wybierz swój monitor baterii. Otwórz węzeł „SoC baterii” i wybierz z listy swój monitor baterii oraz „State of charge (%)”.
- Sprawdź przekaźnik w węźle „Przekaźnik 1 GX”, zmień progi w funkcji, jeśli trzeba, i kliknij Deploy.
Węzeł Battery wskazuje przykładowy SmartShunt z dokumentacji Victron (com.victronenergy.battery/277). Numer na końcu jest inny w każdej instalacji — zależy od urządzenia i sposobu podłączenia. Dopóki nie wybierzesz w węźle swojego monitora baterii, funkcja nie dostanie SoC, a przekaźnik się nie przełączy.
[
{"id":"c24a5c0f10000001","type":"tab","label":"Przekaźnik wg SoC","disabled":false,"info":"Histereza 30/50 % - przykład z cpv24.pl"},
{"id":"c24a5c0f10000002","type":"victron-input-battery","z":"c24a5c0f10000001","service":"com.victronenergy.battery/277","path":"/Soc","serviceObj":{"service":"com.victronenergy.battery/277","name":"SmartShunt (przykład - wybierz swój)"},"pathObj":{"path":"/Soc","type":"float","name":"State of charge (%)"},"initial":"","name":"SoC baterii","onlyChanges":false,"x":150,"y":120,"wires":[["c24a5c0f10000003"]]},
{"id":"c24a5c0f10000003","type":"function","z":"c24a5c0f10000001","name":"histereza","func":"// Histereza: zamknij przekaźnik przy SoC <= 30 %, otwórz przy SoC >= 50 %.\n// Progi są przykładowe - ustaw własne.\nconst PROG_ZAL = 30;\nconst PROG_WYL = 50;\n\nconst soc = msg.payload;\nif (typeof soc !== 'number' || isNaN(soc)) return null; // brak odczytu: nic nie rób\n\nconst poprzedni = context.get('stan');\nlet stan = (poprzedni === undefined) ? 0 : poprzedni;\nif (soc <= PROG_ZAL) stan = 1; // 1 = Closed\nelse if (soc >= PROG_WYL) stan = 0; // 0 = Open\n// pomiędzy progami stan się nie zmienia\n\nnode.status({fill: stan ? 'green' : 'grey', shape: 'dot',\n text: 'SoC ' + soc.toFixed(1) + ' %, przekaźnik ' + (stan ? 'zamknięty' : 'otwarty')});\n\nif (stan === poprzedni) return null; // wysyłaj tylko zmianę\ncontext.set('stan', stan);\nmsg.payload = stan;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":120,"wires":[["c24a5c0f10000004","c24a5c0f10000005"]]},
{"id":"c24a5c0f10000004","type":"victron-output-relay","z":"c24a5c0f10000001","service":"com.victronenergy.system/0","path":"/Relay/0/State","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus device"},"pathObj":{"path":"/Relay/0/State","type":"enum","name":"Venus relay 1 state","enum":{"0":"Open","1":"Closed"},"writable":true},"initial":"","name":"Przekaźnik 1 GX","onlyChanges":true,"x":600,"y":120,"wires":[]},
{"id":"c24a5c0f10000005","type":"debug","z":"c24a5c0f10000001","name":"stan przekaźnika","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":610,"y":180,"wires":[]}
]
Wbudowane przykłady Victron
Paleta Victron ma wbudowaną bibliotekę przykładów: menu (prawy górny róg) → Import → Examples → node-red-contrib-victron. Te same flow są też na stronie wiki palety, więc można je przejrzeć bez edytora. Trzy z nich są najbliżej tego przykładu:
| Przykład | Co robi | Czym różni się od flow z tej strony |
|---|---|---|
| Threshold Control | Wyjście włącza się, gdy wartość wejściowa przekroczy próg ON, a wyłącza, gdy spadnie poniżej progu OFF. Przed każdym przełączeniem czeka ustawione opóźnienie (ON/OFF delay). Progi i ręczne sterowanie są na dashboardzie. | Steruje tym samym przekaźnikiem 1 (/Relay/0/State), ale wejściem jest napięcie baterii z węzła System (/Dc/Battery/Voltage), a nie SoC, i dochodzą opóźnienia. Wymaga dodatkowych modułów: node-red-dashboard, node-red-contrib-ui-led i node-red-contrib-countdown. |
| Run generator at certain time when SOC is below 50% | Codziennie o 18.00 sprawdza zapamiętany SoC. Jeśli jest niski, uruchamia agregat na 45 minut: węzeł trigger wysyła 1, a po 45 minutach 0. SoC trafia do kontekstu flow.SOC przez węzeł change. | Steruje węzłem Generator (Manual Start), a nie przekaźnikiem. Uwaga: opis mówi „poniżej 50%”, ale węzeł switch w tym flow sprawdza „mniejsze lub równe 50” (nazwa „Start if SOC is <= 50%”). |
| Only messages at regular intervals | Węzeł change zapisuje ostatnią wartość do kontekstu, a węzeł inject odczytuje ją w stałych odstępach. | Przydaje się, gdy potrzebujesz ostatniej wartości w stałym rytmie, niezależnym od tego, kiedy węzeł wejściowy ją wysyła. |
Opis wszystkich węzłów wejściowych i wyjściowych Victron: węzły Victron w Node-RED.
Na co uważać
- Kontekst po restarcie. Aby kontekst przetrwał restart, Victron opisuje w FAQ plik
/data/home/nodered/.node-red/settings-user.jsz ustawieniemcontextStorage(modułlocalfilesystem, zapis co 300 s, czyli co 5 minut). Gdy to jest domyślny magazyn kontekstu, kod funkcji działa bez zmian. Victron przestrzega, żeby nie zapisywać zbyt często, bo zużywa to pamięć flash. - Tryb bezpieczny. Jeśli po zmianach flow przeciąża GX albo działa źle, włącz Node-RED w menu GX w trybie bezpiecznym (safe mode). Node-RED wystartuje bez uruchamiania flow, można je poprawić, a ruszą po kliknięciu Deploy.
- Restart Node-RED. Z menu GX: wyłącz i włącz Node-RED w Venus OS Large Features → Node-RED.
- Czas w flow. W przykładach sterowanych godziną, np. z agregatem o 18.00, Node-RED używa strefy czasowej ustawionej w Remote Console. Po jej zmianie trzeba zrestartować Node-RED.
Flow w Node-RED nie zastępuje BMS, bezpieczników ani wyłączników — przy restarcie GX albo błędzie w flow przekaźnik może zostać w nieoczekiwanym stanie. Obwód podłączony do przekaźnika musi być bezpieczny w obu stanach. Victron nie zapewnia wsparcia dla instalacji, które używają Node-RED do zaawansowanych rozwiązań.
Urządzenia, których to dotyczy
Źródła
- Venus OS Large image: Signal K and Node-RED — rozdz. 2, 5.4 i 5.7, FAQ Q4, Q5, Q9 i Q11victronenergy.com · EN
- Instrukcja Cerbo GX — konfiguracja, Settings → Integrations → Relaysvictronenergy.com · EN
- node-red-contrib-victron — Input nodes (Battery, /Soc)github.com · EN
- node-red-contrib-victron — Output nodes (Relay, /Relay/{relay}/State)github.com · EN
- node-red-contrib-victron — Example Flowsgithub.com · EN
Dalej: Node-RED na Cerbo GX — wszystkie artykuły · pierwsze uruchomienie · węzły Victron · Cerbo GX
