LW IT Solutions
« Blog Overview /Smart Home/Tutorials / Tutorial: Odczyt rejestrów SunSpec z falownika PV...
This post in other languages:

Tutorial: Odczyt rejestrów SunSpec z falownika PV przez Modbus TCP

Tutorial: Odczyt rejestrów SunSpec z falownika PV przez Modbus TCP
Spis treści
  1. Dlaczego sam numer rejestru nie wystarcza
  2. Znalezienie adresu bazowego i znacznika
  3. Przejście łańcucha modeli
  4. Współczynniki skali, typy danych i wartości zastępcze
  5. Odczyt jednej wartości od początku do końca
  6. Przeniesienie całości do Home Assistant
  7. Źródła

Numer rejestru znaleziony we wpisie na forum działa. Działa do najbliższego firmware’u, do kolejnego modelu tego samego falownika, do chwili dołączenia drugiego urządzenia odkładającego tę samą wartość gdzie indziej. Wtedy numer przestaje się zgadzać i nic tego nie mówi: Modbus podaje to, co stoi pod tym adresem, a liczby prawdopodobnej nie da się odróżnić od poprawnej.

Z tego powodu istnieje SunSpec. To spis położony na przestrzeni rejestrów, a jego odczytanie kosztuje cztery kroki działające jednakowo w każdym falowniku z tą obsługą.

Mapa rejestrów od adresu 40000 ze znacznikiem SunS, dwoma nagłówkami modeli wraz z blokami i znacznikiem końca, obok rozkodowanie jednej wartości wraz z jej rejestrem skali
Łańcuch opisuje sam siebie: każdy model podaje własną długość, adres następnego wynika więc z bieżącego. Znaleźć trzeba tylko początek.

Dlaczego sam numer rejestru nie wystarcza

Modbus nie zna nazw, jednostek ani typów. Odczyt daje szesnaście bitów, a każda wykładnia tych bitów odbywa się po stronie czytającego. Rejestr o zawartości 1234 może oznaczać 1234 waty, 123,4 wolta albo 12,34 ampera – a protokół nic o tym nie mówi.

SunSpec dokłada trzy rzeczy, a wszystkie trzy stoją w samej przestrzeni rejestrów: znacznik mówiący, że spis istnieje, łańcuch bloków mówiący, jakie pomiary są i gdzie, oraz na każdą grupę wartości współczynnik skali mówiący, gdzie stoi przecinek.

Praktycznym skutkiem jest to, że raz napisany czytnik działa również przy następnym urządzeniu. Waży to więcej, niż brzmi, bo rozwiązanie alternatywne – tabela adresów na każdego producenta i każdy stan firmware’u – jest właśnie tym, co po cichu się dezaktualizuje.

Znalezienie adresu bazowego i znacznika

Spis zaczyna się pod jednym z trzech adresów, a dwa pierwsze rejestry mówią, czy zaczyna się właśnie tam. Zawierają cztery znaki SunS, jako wartość 32-bitowa 0x53756E53.

from pymodbus.client import ModbusTcpClient

c = ModbusTcpClient("192.168.1.50", port=502)
c.connect()

for basis in (40000, 0, 50000):
    r = c.read_holding_registers(basis, count=2, slave=1)
    if not r.isError() and r.registers == [0x5375, 0x6E53]:
        print("SunSpec od", basis)
        break

W tym krótkim kawałku kodu tkwią dwa kamienie potknięcia. Pierwszym jest przesunięcie o jeden, na którym każdy raz się przewraca: dokumentacja liczy rejestry od jedynki, a protokół adresuje je od zera. Adres wydrukowany w podręczniku jako 40001 jest na łączu przesunięciem 40000, a odczyt pod 40001 daje drugą połowę znacznika i żadnej zgodności.

Drugim jest adres urządzenia. Falownik z wbudowanym licznikiem odpowiada jako dwa urządzenia na tym samym połączeniu, każde z własnym identyfikatorem i własnym spisem SunSpec. Odczyt mocy licznika pod identyfikatorem falownika daje wartość, która nie jest błędem i nie jest prawdą. Które identyfikatory są w użyciu, pokazuje strona Modbus w interfejsie webowym urządzenia – i tam też Modbus TCP zostaje w ogóle włączony, bo w większości falowników jest fabrycznie wyłączony.

Przejście łańcucha modeli

Po znaczniku następuje szereg bloków, a każdy blok zaczyna się od dwóch rejestrów: numeru modelu i długości. Długość dodana do bieżącego położenia daje początek następnego bloku, a numer modelu 65535 kończy łańcuch.

pos = basis + 2
while True:
    kopf = c.read_holding_registers(pos, count=2, slave=1).registers
    modell, laenge = kopf[0], kopf[1]
    if modell == 0xFFFF:
        break
    print(f"model {modell:5d}  dlugosc {laenge:3d}  dane od {pos + 2}")
    pos += 2 + laenge

Zwykły falownik odpowiada trzema albo czterema modelami, a numery mówią, czym każdy z nich jest.

Model Zawartość
1 Wspólne: producent, oznaczenie modelu, numer seryjny, wersja firmware’u
101, 102, 103 Falownik jedno-, dwu-, trójfazowy – liczby całkowite ze współczynnikami skali
111, 112, 113 Te same pomiary jako liczby zmiennoprzecinkowe, bez współczynników skali
160 Poszczególne łańcuchy, jeden powtarzalny blok na każdy regulator MPP
201 do 204 Licznik, po jednym modelu na rodzaj przyłączenia

To, czy urządzenie oferuje 103 czy 113, bywa zwykle ustawieniem, a nie właściwością. Wiele falowników ma przełącznik między liczbami całkowitymi ze współczynnikami skali a zmiennym przecinkiem, i to on wyznacza, która z dwóch rodzin modeli pojawi się w łańcuchu. Czytnik oczekujący jednego, a zastający drugie, nie melduje w ogóle żadnych pomiarów – objaw mylący dla ustawienia, którego zmiany nikt nie pamięta.

Współczynniki skali, typy danych i wartości zastępcze

Wewnątrz bloku modelu położenie wartości stoi w specyfikacji i liczone jest od początku danych. Prąd fazy A siedzi na przesunięciu 2, a należący do niego współczynnik skali na przesunięciu 5.

Model 103, dane od 40071

  przesuniecie 1   A      uint16   prad calkowity
  przesuniecie 2   AphA   uint16   faza A
  przesuniecie 3   AphB   uint16   faza B
  przesuniecie 4   AphC   uint16   faza C
  przesuniecie 5   A_SF   int16    wspolczynnik skali dla wszystkich czterech

  40072 = 1234        wartosc surowa
  40075 = 0xFFFE      uzupelnienie do dwoch, czyli −2

  1234 × 10⁻² = 12,34 A

Współczynnik skali jest wykładnikiem dziesiętnym ze znakiem i obowiązuje dla całej grupy wartości, a nie dla jednej. Dlatego pojawia się raz na cztery prądy i dlatego prąd odczytany bez niego daje liczbę stukrotnie za dużą – a ta w instalacji domowej nadal wygląda na wiarygodny pomiar.

W praktyce liczą się jeszcze trzy właściwości kodowania. Wartości zajmujące dwa rejestry stoją słowem starszym z przodu, co odpowiada konwencji Modbusa i co niemal każda biblioteka robi poprawnie sama z siebie. Pola tekstowe mają stałą długość i są dopełniane bajtami zerowymi, a nie nimi kończone. A wartość, której urządzenie nie prowadzi, nie wynosi zera, lecz jest wartością zastępczą: 0x8000 dla int16, 0xFFFF dla uint16, 0x80000000 dla int32. Czytnik traktujący je jako liczby melduje 65535 woltów – a reguła je odrzucająca ma trzy linie.

LEER = {"int16": 0x8000, "uint16": 0xFFFF,
        "int32": 0x80000000, "uint32": 0xFFFFFFFF}

def wert(roh, typ, sf):
    if roh == LEER.get(typ):
        return None
    return roh * (10 ** sf)

Odczyt jednej wartości od początku do końca

Wszystkie części razem dają czytnik, który model odnajduje, zamiast zakładać jego adres.

def modell_finden(c, basis, gesucht, slave=1):
    pos = basis + 2
    while True:
        m, laenge = c.read_holding_registers(pos, count=2, slave=slave).registers
        if m == 0xFFFF:
            return None
        if m == gesucht:
            return pos + 2, laenge
        pos += 2 + laenge

def vorzeichen(r):
    return r - 0x10000 if r > 0x7FFF else r

start, _ = modell_finden(c, 40000, 103)
block    = c.read_holding_registers(start, count=6, slave=1).registers

strom = block[1]                 # AphA, przesuniecie 2 liczone od jedynki
sf    = vorzeichen(block[4])     # A_SF, przesuniecie 5
print(f"{strom * 10 ** sf:.2f} A")

Warto odczytywać cały blok jednym żądaniem, a nie każdą wartość osobno. Odczyt Modbusa kosztuje niezależnie od długości kilka milisekund czasu obiegu – sześć rejestrów w jednym wywołaniu kosztuje więc tyle, co jeden rejestr w jednym wywołaniu. Ważniejsze zaś: wszystkie sześć wartości pochodzi wtedy z tej samej chwili. Sześć osobnych odczytów prądu, napięcia i mocy daje trzy wielkości do siebie niepasujące, a zbudowane na nich sprawdzenie wiarygodności odzywa się bez powodu.

Uwaga o częstotliwości odpytywania: falownik nie jest bazą danych. Żądanie co pięć sekund jest bezproblemowe, raz na sekundę bywa w części urządzeń granicą, a szybciej wytwarza przekroczenia czasu wyglądające na usterki sieci. Same wartości pomiarowe i tak rzadko odświeżają się częściej niż co sekundę.

Przeniesienie całości do Home Assistant

Gdy adresy są znane, ten sam odczyt działa również opisowo. Integracja Modbus w Home Assistant zajmuje się typem danych i znakiem; wpisać trzeba jedynie współczynnik skali jako liczbę, bo integracja nie odczytuje go z urządzenia.

modbus:
  - name: wechselrichter
    type: tcp
    host: 192.168.1.50
    port: 502
    sensors:
      - name: "Prad faza A"
        slave: 1
        address: 40072
        data_type: uint16
        scale: 0.01
        precision: 2
        unit_of_measurement: "A"
        device_class: current
        state_class: measurement
        scan_interval: 10
      - name: "Moc czynna"
        slave: 1
        address: 40084
        data_type: int16
        scale: 1
        precision: 0
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        scan_interval: 10

Wpisany na stałe scale jest kompromisem tej drogi i warto odnotować, skąd się bierze. Współczynnik skali odczytano raz powyższym skryptem; stoi w urządzeniu i praktycznie nigdy się nie zmienia, ale gwarancji na to nie ma. Po aktualizacji firmware’u porównanie wartości wyświetlanej z ekranem falownika trwa dziesięć sekund i wyłapuje stukrotność natychmiast.

Ostatnie pole rozstrzyga, czy wartość trafi do statystyki energii, a nie tylko na kartę. Wartość mocy w watach to device_class: power ze state_class: measurement; stan licznika w kilowatogodzinach to device_class: energy ze state_class: total_increasing. Jedno z drugim nie jest wymienne, a wybrać jako źródło energii da się wyłącznie to drugie.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Napisanie komentarza

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

ALL ARTICLES & CATEGORIES

CCTV

Śledź tę kategorię przez RSS

Cloud & AI

Śledź tę kategorię przez RSS

Data Privacy

Wszystkie artykuły w tej kategorii (12) Śledź tę kategorię przez RSS

Digital Analytics

Wszystkie artykuły w tej kategorii (47) Śledź tę kategorię przez RSS

Digital Marketing

Wszystkie artykuły w tej kategorii (29) Śledź tę kategorię przez RSS

IT & Networks

Wszystkie artykuły w tej kategorii (16) Śledź tę kategorię przez RSS

Music Production

Śledź tę kategorię przez RSS

Raspberry Pi

Śledź tę kategorię przez RSS

Smart Home

Wszystkie artykuły w tej kategorii (18) Śledź tę kategorię przez RSS

Tworzenie stron internetowych

Śledź tę kategorię przez RSS

Wtyczki i triki WordPress

Śledź tę kategorię przez RSS