Na jaře 2024 jsem u svého dodavatele elektřiny přešel na tarif, kde se cena silové elektřiny mění každý měsíc. Jedná se o produkt s měsíční výpovědní lhůtou a tak jsem si řekl, že to zkusím a uvidím, jak to v konečném součtu bude vycházet.
A když už jsem byl u toho tarifu, rozhodl jsem se napravit jeden dluh z minulosti - v domovním rozvaděči jsem měl vyhrazené 4 moduly pro umístění podružného elektroměru. V rámci stavby se neosadil, neboť to nebyla zase tak klíčová součást, ale dnes už je. Pořídil jsem si Eastron SDM630 Modbus V2 MID. Jedná se o běžný EM s přímým měřením, 4Q (čili měří i přetoky) a data se z něj dají tahat pomocí RS485 a protokolu Modbus. Prodejce tvrdí, že je "úředně ověřený" (MID), ale nezjišťoval jsem, co to přesně znamená - předpokládám, že ho výrobce nějak pečlivěji zkalibruje či něco takového.
EM disponuje rozhraním RS485. Rychlost přenosu jde nastavit v několika stupních: 2400, 4800, 9600, 19200, 38400. Paritu pak klasicky lichá, sudá nebo žádná. Počet stopbitů 1 nebo 2. Nic zákeřného. Jelikož mám "vyčítací elektroniku" metr od EM, nastavil jsem nevyšší rychlost, žádnou paritu a jeden stopbit. V rámci protokolu se totiž počítá CRC, takže případné chyby neprojdou přes tuto kontrolu.
EM komunikuje protokolem Modbus RTU. O něm asi nemá smysl více psát, je to průmyslový standard. Důležité je však vědět, co do EM poslat a jak číst odpověď. ZDE je možné stáhnout dokumentaci a hned na straně 2 je tabulka s veličinami a odpovídajícími adresami. Funguje to v jednoduchosti tak, že EM pošleme žádost o přečtení hodnot z registrů od adresy X např. do adresy X+6 - tedy startovací adresa X a počet 6. To je vše.
Pro pochopení je nutné znát ještě jednu drobnost - pod každou adresou v registru EM se ukrývá 16-bitová hodnota, tedy WORD (2 bytes). Každá "elektrická" veličina je reprezentována datovým typem FLOAT (Big Endian ABCD), který se skládá ze 4 bytes. Čili jedna veličina = 2 WORDS = 4 bytes a hodnoty ze dvou adres registru EM. To je také důvod, proč jsou jednotlivé veličiny adresovány ob jedno (0,2,4...).
V níže uvedené tabulce je uveden příklad dotazu na aktuální výkon na fázi 1 (Phase 1 power).
SlaveID | Kód funkce | Počáteční adresa | Počet words | CRC | |||
1 | 4 | 0 | 0C | 0 | 2 | B1 | C8 |
Odpověď je pak v následující tabulce.
SlaveID | Kód funkce | Velikost odpovědi | Odpověď | CRC | ||||||
1 | 4 | 4 | 43 | 4B | 01 | E6 | 1E | 0C |
Když si pak 43 4B 01 E6 převedeme na FLOAT, dostaneme hodnotu 203.007416. Tedy výkon na fázi 1 v momentě dotazu.
Příklad pro více hodnot v jednom dotazu:
Po převodu na FLOAT je výkon na fázi1 218.53 W, na fázi2 8.83 W a na fázi3 pak 1666.53 W.
Hardware je tak trochu bastl ze šuplíkových zásob (doslova) - jedná se o prosté propojení Wemos D1 mini (ESP8266) a převodníku RS485/TTL MAX485. Nebylo by na něm nic zajímavého nebýt té šílenosti se dvěma tranzistory, ale o tom dále.
Wemos D1 mini je profláknutá deska, která má na sobě modul ESP12 (ESP8266 + příslušenství) a současně i převodník USB/serial CH340. Přes tento převodník se ESP8266 programuje a také s ním lze prostřednictvím něj komunikovat z počítače. ESP má bohužel pouze jeden plnohodnotný HW UART, takže převodník MAX485 musí být připojen na stejné RX/TX piny jako CH340. A v tom je trochu potíž.
Mezi výstupem CH340 a ESP je rezistor 470R (ano, ohmů). V klidovém stavu drží CH340 svůj výstup na H a to dosti tvrdě - skoro bych řekl, že silou napájecího napětí (3.3V). Pokud MAX485 přepneme do režimu příjmu a na RS485 přijde log.0, snaží se MAX na svém datovém výstupu RO přeprat tvrdý výstup z CH340 přes rezistor 470R na zem a vytvořit pro ESP pocit logické nuly. To se mu nedaří, neboť MAX485 výstup RO nesepne přímo k GND, ale přes nějaký svůj vnitřní pull-down odpor. Takže vznikne dělič a ESP má na RX pinu při logické nule na RS485 asi 2.7V. To je dost velké napětí na to, aby to chápal jako L.
Řešení je několik. Odoperovat SMD rezistor 470R a nahradit ho např. 4k7. Jenže tím vznikne "Wemos D1 mini Walda`s version" a to fakt nechci :-). Dále se dá použít jiná deska s ESP8266 apod. A nebo na to jít silou a toho prevíta CH340 přetlačit. K tomu stačí 2 běžné konfekční tranzistory BC546 a tři rezistory. Funguje to a v případě logické nuly na RS485 se za cenu sedmi miliampér tekoucími z CH340 dostanu na napětí 1.08V na RX pinu ESP. A to již bezpečně stačí na to, aby tuto úroveň ESP vyhodnotil jako L. Na níže uvedeném obrázku je to znázorněno - žlutá.
Levý tranzistor je přes rezistor 100R připojen na D2 Wemosu. Je to proto, že pin D2 ovládá signál READ_ENABLE MAX485 a ten je aktivní v logické nule. Čili tranzistorová šílenost začne do RX signálu mezi CH340 a ESP zasahovat až v momentě, kdy chce ESP z RS485 příjímat. A to chce jen velmi krátkou dobu po odeslání požadavku EM. Jindy je příjem z RS485 ignorován.
Software je klasický Arduino-style štrůdl s těmito funkcemi:
Pro komunikaci pomocí Modbusu existuje několik knihoven a rozhodně bych ušetřil kupu času. Jsem však tvor zvídavý a chtěl jsem se s tím poprat vlastními silami :-) Navíc komunikace s EM je tak primitivní, že jakékoliv "advanced" funkce knihoven bych ani náznakem nevyužil.
Vyčítání probíhá klasicky přes Serial1 a obecně jsem se v SW snažil využívat běžné Adrudino věci než se snažit cokoliv tvořit na míru konkrétnímu HW (např. reagovat na přerušení). Vyčítání probíhá v tzn. "skoro non-blocking mode", čili funkce loop() je volaná neustále jak v průběhu odesílání požadavku na EM, tak i v průběhu příjmu. Kód se trochu zesložitil, ale na druhou stranu lze na jiném HW (s více UART) komunikovat i s více EM, nebo např. s FV měničem apod. A to při zachování rychlé odezvy na požadavky. Jedniná vada na kráse je, že v "skoro non-blocking" režimu nelze odeslat poslední znak v TX bufferu (to je asi 270 us :-).
Proces vyčítání obsahuje 4 dotazy (data nejsou v EM adresně za sebou) každé 2 sekundy. Časově se to stihne za 77 ms při rychlosti sériového portu 38400. A 76 ms může ESP dělat i něco jiného než čekat na konec komunikace :-) Obrázek komunikace je na níže uvedeném obrázku.
Narozdíl od Modbusu jsem v tomto případě po knihovně sáhnul a to po PubSubClient.h. Odesílání přečtených veličin probíhá formou publikací do dvou témat a to ve JSON formátu. Pro tvorbu JSON jsem použil také hotovku - ArduinoJson.h.
MQTT-topic: my-eastron/data/live { "u1": 241.6957, "u2": 241.9206, "u3": 242.8587, "i1": 0.904172, "i2": 1.166418, "i3": 0.470194, "p1": 114.5953, "p2": 252.0929, "p3": 67.50797, "pf1": 0.52438, "pf2": 0.893374, "pf3": 0.591186 } MQTT-topic: my-eastron/data/consumption { "kwh-imp-1": 83.853, "kwh-imp-2": 55.373, "kwh-imp-3": 92.032, "kwh-exp-1": 0, "kwh-exp-2": 0, "kwh-exp-3": 0, "kwh-imp-tot": 231.258, "kwh-exp-tot": 0 }
Zde je výpis načtených hodnot z EM, který se posílá na konzoli. Hodnota readErrors znamená počet po sobě jdoucích selhání při čtení z EM. Pokud přesáhne 5, tak SW přestane odesílat data na MQTT - aby se neposílaly neaktuální data. A taky přestane blikat LEDka na Wemosu :-)