Sporo sprzętu energetycznego ma lokalny interfejs danych, z którego mało kto korzysta. Liczniki energii na szynę DIN, falowniki fotowoltaiczne, pompy ciepła i centrale wentylacyjne często obsługują Modbus. Protokół wywodzi się ze sterowników przemysłowych i nie potrzebuje chmury ani konta. Kiedy już działa, możesz odpytywać napięcie, moc i liczniki energii tak często, jak urządzenie na to pozwala.
Najtrudniej jest wyciągnąć z urządzenia pierwszą poprawną liczbę: okablowanie rządzi się regułami, które łatwo złamać, rejestry numeruje się na dwa sposoby, a wartość 32-bitowa zamienia się w bzdurę, jeśli jej połówki odczytasz w złej kolejności. Omawiam te problemy w kolejności, w jakiej na nie trafisz. Jako przykładów używam jednofazowego licznika Eastron SDM120 i falownika Fronius GEN24, bo obaj producenci publikują mapy rejestrów.
RTU czy TCP: sprawdź, co ma urządzenie
W domowych zastosowaniach spotyka się dwie odmiany Modbusa.
Modbus TCP działa przez Ethernet albo Wi-Fi. Standardowy port to 502, choć w niektórych urządzeniach można ustawić inny (Fronius GEN24 oferuje 502 albo 1502). Dokumentacja integracji Modbus w Home Assistant zwraca uwagę, że w wielu urządzeniach Modbus TCP jest fabrycznie wyłączony, więc najpierw zajrzyj do interfejsu WWW urządzenia albo do menu instalatora. W GEN24 ustawienie znajduje się w Communication > Modbus (komunikacja, Modbus).
Modbus RTU działa przez łącze szeregowe, w tym zastosowaniu prawie zawsze RS-485: dwuprzewodową magistralę różnicową z dodatkowym przewodem wspólnym. Żeby połączyć się z nią z komputera, potrzebujesz przejściówki USB na RS-485 albo bramki, która podłącza magistralę do sieci. Bramki działają na jeden z dwóch sposobów. Jedne tłumaczą RTU na Modbus TCP, inne przesyłają ramki RTU bez zmian przez TCP (tryb przezroczysty, nazywany też RTU przez TCP). Program musi wiedzieć, z jaką bramką ma do czynienia.
Jedna zasada ze specyfikacji łącza szeregowego wpływa na całą resztę: na magistrali RS-485 z Modbusem jest w danej chwili dokładnie jedno urządzenie nadrzędne (klient), a wszystkie pozostałe tylko odpowiadają. Jeśli port RS-485 licznika jest już odpytywany przez coś innego, na przykład przez rejestrator producenta albo przez sam falownik, nie możesz po prostu dopiąć do tej samej pary drugiego urządzenia nadrzędnego. Fronius powtarza to w instrukcji GEN24 w części o RTU. W takiej sytuacji szukaj interfejsu TCP w urządzeniu, które już prowadzi odpytywanie.
Magistrala RS-485, która działa
Większość problemów typu „Modbus nie działa” w RTU to problemy z okablowaniem. Zasady pochodzą ze specyfikacji Modbusa dla łącza szeregowego (V1.02) i z not aplikacyjnych producentów.
- Łańcuch, nie gwiazda. Poprowadź jeden kabel główny od urządzenia do urządzenia. Specyfikacja dopuszcza krótkie odgałęzienia o długości do 20 m, a HMS Networks odradza topologie gwiazdy, drzewa i pierścienia.
- Zakończ oba końce i tylko końce. Specyfikacja opisuje zakończenie linii na każdym końcu kabla głównego: rezystor 150 omów (0,5 W) albo rezystor 120 omów (0,25 W) szeregowo z kondensatorem 1 nF, który według specyfikacji jest lepszym wyborem, gdy linia jest spolaryzowana. Nigdy więcej niż dwa zakończenia i nigdy na odgałęzieniu. Wiele przejściówek i liczników ma wbudowany rezystor terminujący włączany przełącznikiem albo zworką, więc sprawdź, czy jest włączony tylko w dwóch urządzeniach na końcach.
- Poprowadź przewód wspólny. Specyfikacja wymaga przewodu wspólnego łączącego wszystkie urządzenia, uziemionego w jednym punkcie. Zwykle używa się ekranowanej skrętki. Fronius zaleca ją do okablowania RTU w GEN24, razem z uziemieniem w jednym punkcie.
- Polaryzuj w jednym miejscu. Jeśli magistrala potrzebuje rezystorów polaryzujących, montuje się je tylko w jednym miejscu, a według specyfikacji ich wartość powinna wynosić od 450 do 650 omów. Wiele przejściówek USB już je ma.
- Odległość i liczba urządzeń. Specyfikacja podaje maksymalnie 1000 m przy prędkości 9600 bodów lub niższej i kablu AWG26 lub grubszym, oraz do 32 urządzeń bez wzmacniaka.
Oznaczenia A i B wymagają osobnego ostrzeżenia. Specyfikacja Modbusa nazywa linie D0 (A) i D1 (B), a w normie RS-485 A to linia ujemna, a B dodatnia. Producenci nie trzymają się tego konsekwentnie. HMS Networks zauważa, że urządzenia bywają oznaczone +/-, D+/D- albo A/B z odwróconym znaczeniem. Jeśli wszystko inne się zgadza, a nic nie odpowiada, najpierw zamień miejscami oba przewody danych.
Ustawienia łącza i adresy
Każde urządzenie na magistrali RTU ma adres (w instrukcjach nazywany też slave ID albo unit ID) od 1 do 247. Adres 0 służy do rozgłaszania poleceń zapisu i urządzenia na niego nie odpowiadają. Adresy muszą być unikalne. To klasyczna pułapka przy zakupie dwóch takich samych liczników, bo oba przychodzą z adresem 1. Podłączaj je pojedynczo i zmień adres pierwszego, zanim dołożysz drugi.
Ustawienia łącza muszą się zgadzać dokładnie po obu stronach: prędkość, liczba bitów danych, parzystość i bity stopu. Specyfikacja ustala jako domyślne 19200 bodów z kontrolą parzystości typu parzystego (even) i wymaga obsługi 9600 i 19200, ale prawdziwe urządzenia się różnią. Instrukcja SDM120 podaje jako ustawienie fabryczne 2400 bodów, 8 bitów danych, brak kontroli parzystości, jeden bit stopu i adres 1.
Urządzenie, które odbierze ramkę z błędem parzystości albo sumy kontrolnej CRC, w ogóle nie odpowiada. Od strony komputera zła prędkość, zła parzystość, zły adres, zamienione przewody i brak urządzenia wyglądają tak samo: urządzenie milczy, a czas oczekiwania mija. Zmieniaj jedną rzecz naraz.
W SDM120 adres, prędkość i parzystość to rejestry zapisywalne (40021, 40029 i 40019), do których wpisuje się wartości zmiennoprzecinkowe. Według instrukcji nowe ustawienia łącza zaczynają obowiązywać dopiero po ponownym uruchomieniu licznika. Inne liczniki robią to inaczej, więc zanim cokolwiek zapiszesz, przeczytaj instrukcję.
Rejestry, kody funkcji i przesunięcie o jeden
Protokół Modbus ma cztery tablice danych:
- cewki (coils, pojedyncze bity do odczytu i zapisu);
- wejścia dyskretne (discrete inputs, pojedyncze bity tylko do odczytu);
- rejestry wejściowe (input registers, 16-bitowe, tylko do odczytu);
- rejestry zapisywalne (holding registers, 16-bitowe, do odczytu i zapisu).
Rejestry wejściowe odczytuje się kodem funkcji 04, a rejestry zapisywalne kodem 03, maksymalnie 125 rejestrów w jednym zapytaniu. Zapis używa kodu 06 (jeden rejestr) albo 16 (kilka rejestrów).
Teraz najbardziej mylący fragment. Specyfikacja mówi, że elementy danych są numerowane od 1 do n, ale w ramce adresowane od 0 do n-1. Wiele instrukcji używa „numeru rejestru” z cyfrą na początku oznaczającą tablicę: 3xxxx dla rejestrów wejściowych, 4xxxx dla zapisywalnych. W instrukcji SDM120 napięcie to rejestr 30001, czyli rejestr wejściowy numer 1, czyli adres 0 w zapytaniu. Moc czynna to 30013 (adres 12, czyli 0x000C), a całkowita energia czynna to 30343 (adres 342, czyli 0x0156).
Programy nie zgadzają się co do tego, której postaci oczekują. Integracja Modbus w Home Assistant chce adresu liczonego od zera, więc 40001 zamienia się w 0. Narzędzie wiersza poleceń mbpoll domyślnie przyjmuje numer liczony od jedynki, a na adresowanie od zera przełącza je opcja -0. Jeśli wartości wyglądają wiarygodnie, ale należą do sąsiedniego rejestru, najpewniej masz przesunięcie o jeden.
Odczyt wartości 32-bitowych
Rejestry mają 16 bitów, a Modbus przesyła je od najstarszego bajtu (big-endian). Wszystko, co większe, na przykład 32-bitowa liczba zmiennoprzecinkowa albo 32-bitowy licznik energii, zajmuje dwa rejestry, a protokół nie określa, który z nich idzie pierwszy.
SDM120 przechowuje odczyty jako 32-bitowe liczby zmiennoprzecinkowe IEEE 754 w dwóch kolejnych rejestrach wejściowych, starszym słowem naprzód. Instrukcja zaznacza też, że adres początkowy i liczba rejestrów muszą być parzyste. W przeciwnym razie zapytanie trafia w środek wartości, a licznik zwraca błąd.
Jeśli liczba zmiennoprzecinkowa wraca jako coś maleńkiego z ogromnym ujemnym wykładnikiem albo jako coś gigantycznego, spróbuj odwrotnej kolejności słów, zanim zaczniesz podejrzewać okablowanie. Błąd w okablowaniu daje brak odpowiedzi, a nie złą liczbę.
Pierwszy odczyt z wiersza poleceń
mbpoll to małe narzędzie wiersza poleceń, które działa jako urządzenie nadrzędne Modbusa przez RTU i TCP. Na podstawie jego strony podręcznika to polecenie jednorazowo odczytuje napięcie z SDM120 przez przejściówkę USB przy fabrycznych ustawieniach łącza:
mbpoll -m rtu -a 1 -b 2400 -P none -t 3:float -B -r 1 -c 1 -1 /dev/ttyUSB0
Co robią poszczególne opcje:
-m rtuwybiera Modbus RTU (domyślny jest TCP);-a 1to adres urządzenia;-b 2400 -P noneustawia prędkość i parzystość (domyślnie mbpoll używa 19200 bodów i parzystości typu parzystego,even);-t 3:floatodczytuje rejestry wejściowe jako 32-bitowe liczby zmiennoprzecinkowe;-Bustawia kolejność słów od starszego dla wartości 32-bitowych;-r 1to numer początkowy liczony od jedynki, czyli rejestr 30001;-c 1odczytuje jedną wartość, a-1wykonuje odczyt raz zamiast powtarzać go w pętli.
Zamień -r 1 na -r 13, żeby odczytać moc czynną. Przy urządzeniu z Modbus TCP pomiń -m rtu i opcje łącza szeregowego, a zamiast portu podaj adres IP. Jeśli urządzenie nie używa portu 502, dodaj -p.
Ten sam odczyt w Pythonie
W Pythonie zwykle sięga się po pymodbus. Ten fragment odczytuje rejestr napięcia przez Modbus TCP, na przykład przez bramkę tłumaczącą RTU na TCP. Sprawdziłem go z symulatorem z pakietu pymodbus w wersji 3.16.1. Wydania starsze niż 3.10 używały slave= zamiast device_id=.
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient("192.168.1.50", port=502)
client.connect()
rr = client.read_input_registers(0, count=2, device_id=1)
if rr.isError():
print("Modbus error:", rr)
else:
v = client.convert_from_registers(rr.registers, data_type=client.DATATYPE.FLOAT32)
print(f"Voltage: {v:.1f} V")
client.close()
Przy przejściówce USB zamień klienta na ModbusSerialClient(port="/dev/ttyUSB0", baudrate=2400, parity="N", stopbits=1, bytesize=8, timeout=1), również importowanego z pymodbus.client. Zwróć uwagę na 0 w read_input_registers(0, ...): to adres rejestru 30001 liczony od zera.
Falowniki i SunSpec
Wiele falowników fotowoltaicznych, w tym modele Fronius i SolarEdge, udostępnia dane według SunSpec, czyli standardowego zestawu map rejestrów opartego na Modbusie. W praktyce liczą się dwa szczegóły.
Po pierwsze mapy trzeba odszukać, bo nie leżą pod stałym adresem. Urządzenie SunSpec umieszcza je od adresu 0, 40000 albo 50000, a początek oznacza rejestrami 0x5375 0x6E53, czyli napisem „SunS” w kodzie ASCII. Dalej jest model wspólny (Common Model) o numerze 1, który opisuje urządzenie. Fronius pisze w instrukcji GEN24, że adresy rejestrów są dynamiczne i początku każdego modelu należy szukać, a nie wpisywać go na stałe.
Po drugie mapy całkowitoliczbowe używają współczynników skali. Wartość jest zapisana jako liczba całkowita, a osobny rejestr współczynnika skali podaje potęgę dziesięciu: prawdziwa wartość to wartość × 10^SF. We Froniusie można wybrać mapy zmiennoprzecinkowe albo całkowitoliczbowe ze współczynnikiem skali. Wartości, których urządzenie nie obsługuje, wracają jako specjalne znaczniki, takie jak 0x8000, 0xFFFF albo NaN, zależnie od typu danych. Program powinien traktować je jako brak danych, a nie jako odczyt.
Instrukcja Froniusa dodaje kilka praktycznych ograniczeń: czas oczekiwania co najmniej sekundę, zapytania wysyłane jedno po drugim, a nie równolegle, a w Modbus TCP adres falownika (unit ID) równy 1. Zapisy do rejestrów tylko do odczytu są po cichu ignorowane, więc brak błędu nie oznacza, że zapis się udał.
Modbus TCP to otwarte drzwi
Modbus TCP nie ma uwierzytelniania ani szyfrowania. Dokumentacja Home Assistant mówi to wprost: każde urządzenie, które dosięgnie portu, może odczytywać i zapisywać rejestry. W falowniku albo pompie ciepła rejestry zapisywalne mogą obejmować ustawienia, które zmieniają pracę urządzenia.
Praktyczne wnioski:
- nigdy nie przekierowuj portu 502 z routera do internetu;
- umieść urządzenia z Modbusem w osobnym segmencie sieci i dopuść do nich tylko komputer, który je odpytuje, tak jak opisuje nasz artykuł o sieciach VLAN dla IoT;
- korzystaj z ograniczeń po stronie urządzenia tam, gdzie istnieją: GEN24 może ograniczyć sterowanie do wybranych adresów IP, a jeśli tylko odczytujesz dane, sterowanie można zostawić wyłączone.
Modbus Organization opublikowała bezpieczną odmianę, Modbus/TCP Security, która opakowuje protokół w TLS z wzajemnym uwierzytelnianiem certyfikatami X.509 na porcie 802. W domowych urządzeniach energetycznych jej obsługa to rzadkość, więc planuj sieć tak, jakby jej nie było.
Co dalej
Kiedy rejestr poprawnie odczytuje się z wiersza poleceń, stałe rozwiązanie to już głównie konfiguracja. Home Assistant ma integracje dla konkretnego sprzętu (między innymi Fronius i SolarEdge) i ogólną integrację Modbus, konfigurowaną w YAML z adresami, typami danych i kolejnością słów, które właśnie ustaliłeś. Dzięki komponentowi Modbus Controller w ESPHome ESP32 z układem RS-485 może samodzielnie odpytywać licznik. W obu przypadkach wysyłaj zapytania z umiarem i po kolei.