Partnerzy

Od 1954 Finder pracował wyłącznie w zakresie przekaźników i timerów. Nasz wysoki stopień specjalizacji zaowocował ponad 10.000 różnych produktów w jednej z najszerszych dostępnych ofert. Firma szeroko się rozwija i inwestuje w przyszłość uzupełniając gamę swojego asortymentu. Prócz przekaźników oferuje rozwiązania przemysłu elektrycznego do zastosowań domowych jak i komercyjnych poprzez przekaźniki, urządzenia przeciwprzepięciowe, termostaty panelowe, zasilacze i liczniki energii. Gama asortymentu obejmuje ponad 12 tysięcy produktów.

KursyAutomatyki.pl - portal z kursami online z automatyki przemysłowej. Znajdziesz tam zarówno darmowe kursy, jak i płatne, pełne z wiedzy i doświadczenia od ekspertów. Po zapisie na kurs otrzymujesz dostęp do logicznego ciągu nagrań i ćwiczeń, do których możesz wracać wielokrotnie. Na zakończenie kursu czeka Cię test sprawdzający, po którym otrzymasz dwa certyfikaty w języku polskim i angielskim. Dołącz już teraz!

Automatyzacja to nasz świat. Perfekcyjne rozwiązania - nasz cel. Obecnie firma Pepperl+Fuchs jest znana klientom na całym świecie jako przedsiębiorstwo pionierskie i innowacyjne w dziedzinach takich, jak ochrona przeciwwybuchowa instalacji elektrycznych czy technologie czujników. Zawsze koncentrujemy się na wymaganiach klientów. Pasja, z jaką poświęcamy się automatyce, oraz przełomowe technologie, jakimi dysponujemy, pozwalają nam owocnie współpracować z klientami — tak dziś, jak i w przyszłości.

Rozwiązania dostarczane przez WAGO. już od wielu lat wspierają naszych klientów w dążeniu do sukcesu. Poczynając od prostych instalacji elektrycznych, a kończąc na skomplikowanej infrastrukturze zarządzającej procesami przemysłowymi czy automatyką budynkową. Sprawdźcie jak rozwiązania WAGO, mogą wesprzeć Was w drodze do Waszego sukcesu.

Dostarczamy produkty i rozwiązania z zakresu Przemysłowej Techniki Łączeniowej. Już od ponad 160 lat Weidmüller jest synonimem kompetencji i niezawodność. Oferujemy rozwiązania dla takich branż jak przemysł maszynowy, technika procesowa, produkcja urządzeń, energetyka i transport. Wspieramy naszych Klientów i Partnerów w ponad 80 krajach, produktami, rozwiązaniami i usługami w zakresie połączeń elektrycznych oraz układów zasilania, przetwarzania sygnałów oraz transmisji danych w środowisku przemysłowym.

Oni już dołączyli do Projektu iAutomatyka

Monitorowanie energii z openHAB

Na łamach portalu iAuomatyka można trafić na wiele artykułów na temat narzędzi open source. Do momentu dodania tego artykułu nie było żadnego na temat projektu openHAB. Bez wątpienia może on być uzupełnieniem wielu rozwiązań w obszarze automatyki budynkowej oraz przemysłowej.

Co to jest openHAB

openHAB to projekt oparty o licencję typu open source, tzn. taką, która pozwala na dostęp oraz modyfikację źródeł oprogramowania. Projekt ten jest dedykowany do integracji automatyki domowej. Sama nazwa to skrót od angielskiego sformułowania open Home Automation Bus, w swobodnym tłumaczeniu otwarta magistrala automatyki domowej. Wewnątrz społeczności jest on określany również krótko jako OH. Największym konkurentem openHAB jest Home Assistant (w skrócie HA). Co ciekawe, zarówno OH jak i HA są w podobnym wieku, pierwszy został wydany w 2011 roku, a drugi w 2013. Obok tych rozwiązań funkcjonuje również Node-RED, podobnie jak HA, wydany po raz pierwszy w 2013 roku.

Porównanie tych trzech narzędzi jest trudne, ponieważ Node-RED funkcjonuje w nieco innym obszarze. Każdy z tych projektów przyjął różny model rozwoju, zarządzania konfiguracją, a także wewnętrzne struktury danych temu służące. Poniższa tabela to dość subiektywne podsumowanie kilku aspektów, które mogą być interesujące dla czytelników portalu iAutomatyka:

Aspekt Home Assistant Node-RED openHAB
Przeznaczenie Automatyka domowa Automatyka Automatyka domowa
Silnik reguł Tak Tak, podstawa Tak, różne
Dashboardy Tak Tak, przez dodatek Tak
Integracja z bazą danych Tak Tak Tak
Integracja z MQTT Tak Tak Tak
Integracja z Modbus Tak Tak Tak
Język programowania Python Java Script Java

Patrząc na powyższe zestawienie, funkcjonalność wszystkich 3 projektów jest zbliżona, różnice uwypuklają się dopiero po bliższym przyjrzeniu się w jaki sposób są one realizowane. Dla przykładu podstawowym przeznaczeniem oraz zastosowaniem Node-RED jest modelowanie przepływów (od wejść do wyjść lub zapisu). Node-RED w tym obszarze nie ma sobie równych. Home Assistant z kolei łączy charakterystykę niektórych rodzajów wejść (np. wejść cyfrowych) z ich źródełem oraz przeznaczeniem. Podejście to pozwala na łatwiejsze zarządzanie konfiguracją. Z kolei openHAB mocno oddziela część pozyskiwania danych/informacji od ich procesowania oraz pozostawia sporo swobody w tym jak są one później modelowane i wizualizowane.

Tutaj też drobna ciekawostka – pod względem architektury i wykorzystania komponentów oprogramowania, openHAB ma wiele elementów wspólnych z rozwiązaniami takimi jak Bosch IoT Suite, co być może omówimy przy okazji kolejnego artykułu.

Koncepcje w openHAB

Do zrozumienia zasady działania openHAB należy przyswoić podstawowe założenia i pojęcia, które występują w systemie. Oprogramowanie to rozróżnia rzeczy (ang. Things), kanały (ang. Channels) oraz punkty danych (ang. Item), które w tym artykule będziemy czasami zamiennie określać jako elementy.

Rzeczy służą do pozyskiwania danych i informacji. Rzeczą może być urządzenie fizyczne takie jak sterownik, usługa sieciowa oparta o HTTP lub usługa w chmurze (np. serwis z prognozą produkcji fotowoltaicznej). Rzecz będzie również reprezentować licznik energii elektrycznej np. z interfejsem modbus.
Ponieważ liczniki zazwyczaj oferują różne odczyty, które mogą być identyfikowane na różne sposoby, zależnie od protokołu (rejestr dla modbus, data Information Block dla m-bus) system ujednolica ten aspekt pod pojęciem kanał (ang. Channel).

Kanał to unikalny wskaźnik na daną lub informację udostępnioną przez rzecz (Thing). Dla licznika będzie to pobrana energia, odczyt aktualnego poboru mocy itp. Co do zasady stan kanału powinien być „atomowy”, tj.reprezentować jeden konkretny aspekt zintegrowanej rzeczy. Wartość prezentowana przez kanał powinna być łatwa do interpretacji i nadawać się do mapowania na jeden z podstawowych typów danych (tj. Liczba, Tekst, Data i Czas). Mając na uwadze powyższe możemy założyć, że każdy z rejestrów po stronie licznika można odzwierciedlić jako kanał. Tyle teoria, w praktyce protokoły takie jak modbus wymagają dodatkowo przynajmniej częściowego odwzorowania logiki protokołu
Pod kątem „atomowości” kanału możemy rozpatrzyć moduł posiadający 8 wejść i wyjść cyfrowych (8 DIO), których stan jest reprezentowany przez dwie wartości. Pierwsza składa się z bitów wejść, druga z bitów wyjść. Tworząc konfigurację naturalnie dążymy do tego, aby w oprogramowaniu stworzyć definicję 16 kanałów i w pełni odwzorować stan modułu. Oczywiście wciąż można korzystać z 2 kanałów z reprezentacja binarną (0110 1001, 0000 1010), całkowitą (105, 10) lub szesnastkową (0x69, 0x0A), natomiast podejście to uniemożliwi zwizualizowanie stanu poszczególnych wejść/wyjść a także utrudni przetwarzanie informacji w przypadku komunikacji na zewnątrz.

Istotnym aspektem w każdym systemie, który przetwarza dane są punkty danych. W openHAB jest to Item. W systemach typu SCADA lub oprogramowaniu inżynieryjnym może on być również określany jako tag. Item pozwala na przetworzenie danych z kanału lub wysłanie do niego sygnału (komendy, wartości). Ponieważ Item jest rozdzielny od kanału posiada on swoją nazwę a także etykietę tekstową (ang. label). Itemy wraz z odpowiednimi metadanymi mogą posłużyć do stworzenia „modelu”, który jest niezależny od stosowanych urządzeń oraz źródeł danych. Dzięki temu podejściu zyskujemy możliwość przenoszenia sporej części konfiguracji, ponieważ to model danych służy do tworzenia wizualizacji. Kanały rzeczy są istotne na, ale nie mają bezpośredniego zastosowania przy tworzeniu tzw. dashboardów.

Ostatni element układanki to powiązanie pomiędzy punktem a kanałem, określane jako Link. Link ma bardzo ważną rolę, ponieważ oprócz tego, że reprezentuje on powiązanie pomiędzy dwoma kluczowymi elementami w systemie, w bardziej złożonych przypadkach może być wykorzystywany do przetwarzania sygnału z kanału do itemu lub itemu do kanału. Co ważne – item może, ale nie musi być powiązany z jednym lub wieloma kanałami. Stan itemu może być przeliczany regułą i być pochodną innego itemu. Może on być również aktualizowany skryptem, który wywołuje API openHAB lub kontrolowany za pośrednictwem interfejsu użytkownika.

Każdy z powyższych elementów funkcjonuje niezależnie od pozostałych. Nawet jeśli link i item są powiązane, to powiązanie te jest dość luźne i można je tworzyć w różnej kolejności.

Zanim przejdziemy do omówienia instalacji jeszcze jeden ważny punkt, z którym na pewno spotykają się czytelnicy iAutomatyka. W przypadku systemów opartych o magistrale komunikacyjne (RS485, CAN itd.), która zapewnia dostęp do wielu urządzeń możemy mówić o dodatkowym rodzaju rzeczy, w dosłownym tłumaczeniu jest on określany jako most (ang. Bridge). Most pozwala na odwzorowanie powiązań między rzeczami i budować ich hierarchię. Dla przykładu mostem może być połączenie TCP do bramki Modbus TCP/RTU. Jeśli dany most utraci połączenie, będzie oznaczało to, że wszystkie rzeczy znajdujące się za nim, również to połączenie utraciły. Inny przykład to np. połączeniem do interfejsu CAN, wówczas sam interfejs będzie mostem a rzeczą węzeł CANopen. Inny przykład mostu to połączenie do brokera MQTT, pod którym będą mapowane do rzeczy pary topiców.
Warto tutaj zaznaczyć, że odwzorowanie most/rzecz zależy od dodatku/integracji i stopnia rozbudowy takowej. W niektórych przypadkach logika protokołu może być celowo uproszczona, aby ułatwić zarządzanie konfiguracją.
I już na sam koniec teorii, poniekąd przy okazji zarządzania konfiguracją, openHAB wprowadza dodatkowo koncepcję typu rzeczy (ang. Thing Type). Typ ten pozwala programistom dodatków na implementację predefiniowanych zestawów kanałów oraz kodu, który te kanały obsługuje. Dzięki temu użytkownik końcowy korzysta w swojej aplikacji z tych kanałów, bez konieczności ręcznego definiowania odwzorowania specyficznego osprzętu. Bardzo popularnym typem rzeczy w instalacjach domowych, ale nie tylko, są np. falowniki fotowoltaiczne. Falowniki zazwyczaj będą mają stały zestaw kanałów (różny pomiędzy producentami), który nie podlega znacznym zmianom. W ten oto sposób na bazie dodatku modbus można stworzyć kolejny, który będzie obsługiwał falowniki danego producenta.

Instalacja openHAB

Uzbrojeni w powyższy zasób wiedzy możemy przystąpić do kolejnego kroku, czyli stworzenia rozwiązania w oparciu o oprogramowanie. W celu ułatwienia procesu zaczynamy od systemu operacyjnego Microsoft Windows, który jest najczęściej spotykany na stacjach roboczych. Naturalnie, chętni mogą skorzystać z pakietów stworzonych pod Ubuntu oraz obrazu kontenera (czyt. docker image).

W pierwszym kroku pobieramy openHAB ze strony https://openhab.org.

Pobieranie openHABWybieramy system operacyjny Windows a następnie wersję stabilną. W kwietniu 2024 najświeższa wersja to 4.1.2. Pobrane archiwum rozpakowujemy na dysku do katalogu C:\tools\openhab-4.1.2.

W drugim kroku, ponieważ openHAB do uruchomienia wymaga środowiska Java Virtual Machine (JVM), zainstalujemy Eclipse Temurin 17. Instalator można pobierać ze strony: https://adoptium.net/temurin/releases/

Do działania openHAB wystarczy mniejszy pakiet tj. java runtime.

Pobieranie Java Runtime

Jako, że na poziomie systemu operacyjnego może funkcjonować kilka instalacji Java Virtual Machine, warto zweryfikować, czy nie mamy już zainstalowanej starszej wersji. Można to zrobić z poziomu wiersza poleceń komendą java –version. Jeśli wynik polecenia to błąd (command not found), możemy przechodzić do instalacji Temurina. Jeśli wynik polecenia nie wskazuje na wersję 17, należy rozważyć usunięcie starszej wersji przed instalacją Temurina. Jeśli z jakiś względów starsza wersja jest potrzebna bądź nie działa nam skrypt uruchomieniowy (tj. start.bat), to instalujemy Temuria, a do korekt wykorzystamy wiersz poleceń.

Na poziomie systemu operacyjnego funkcjonują tzw. zmienne środowiskowe. Te, które nas najbardziej interesują to PATH oraz JAVA_HOME. Zmienna PATH to miejsca, w których są poszukiwane programy, które możemy uruchomić z poziomu wiersza poleceń. Zmienna JAVA_HOME jest często wykorzystywana do tego, aby wskazać instalację Javy inną, niż ta, która znajduje się w PATH.

Ponieważ w moim przypadku mam już inną instalację Javy uruchamiam wiersz poleceń i wpisuję polecenie

cd \tools\openhab-4.1.2

Następnie ustawiamy zmienną środowiskową JAVA_HOME poleceniem:

set JAVA_HOME=C:\Program Files\Eclipse Adoptium\jre-17.0.10.7-hotspot

W tym samym oknie terminala, w którym ustawiliśmy JAVA_HOME wpisujemy:

.\start.bat

Gdyby powyższe nie zadziałało, warto zwrócić uwagę na cudzysłowy – w części po znaku równości nie powinno ich być.

Po wykonaniu polecenia na ekranie terminala powinien ukazać się poniższy efekt:

Okno terminala, które widzimy jest w dalszym ciągu wierszem poleceń, z poziomu którego możemy zarządzać openHAB, np. komenda info wyświetla informacje na temat instalacji oraz użycia procesora i pamięci przez proces programu. Korzystanie z wiersza poleceń zostawimy na inną okazję, tymczasem uruchamiamy przeglądarkę i wpisujemy w  pasku adresu http://127.0.0.1:8080.

W przypadku świeżej instalacji musimy przejść przez kreator instalacji. Po pierwsze tworzymy hasło administratora. Oczywiście, hasło powinno być bezpieczne, natomiast sam openHAB nie wymusza tutaj żadnych konkretnych polityk.Definiowanie hasła dla konta administratora openHABPomijamy ustawienie lokalizacji, ponieważ nie zamierzamy z niej korzystać. Drugi krok, który musimy wykonać to ustawienia języka oraz formowania danych.

Ustawienia języka i formatowania w openHABWarto tutaj wybrać język polski, mimo, że panelu administracyjny openHAB nie jest przetłumaczony w pełni. Prawidłowe ustawienie języka zapewni nam właściwą prezentację liczb zmiennoprzecinkowych – będą one miały faktycznie przecinek, a nie kropkę. Ustawiamy również strefę czasową, ponieważ jest ona istotna w przypadku rejestracji danych, pozostawienie jej bez zmian może prowadzić do błędnej prezentacji historii odczytów.

Wybór dodatkóœ do instalacjiW trzecim kroku możemy wybrać dodatki, z których pragniemy skorzystać. Odznaczamy te, które są zaznaczone domyślnie i wybieramy Modbus oraz Persistence SQLite, potwierdzamy wybór i czekamy aż system pobierze dodatki i otworzy kolejny ekran.

W międzyczasie nadmienię, że pierwszy dodatek pozwoli nam zintegrować urządzenie, które jest bardziej złożone niż najpopularniejsze akcesoria automatyki domowej takie jak inteligentna żarówka wifi lub czujnik temperatury. Drugi dodatek pozwala na zapis danych na dysku w osadzonej bazie SQL.
Jako, że openHAB jest rozwiązaniem o zbudowanym z komponentów, rdzeń systemu pozostaje niezmienny podczas gdy funkcjonalność jest rozbudowywana przy pomocy dodatków. Nawet jeśli o czymś zapomnieliśmy w trakcie instalacji i nie zaznaczyliśmy czegoś w kreatorze instalacji, zawsze można wrócić do listy dodatków dostępnej w ustawieniach oraz zainstalować to, czego nam zabrakło. Warto nadmienić, że instalacja lub usunięcie dodatku nie wymaga zrestartowania procesu.

Konfiguracja bazy danych

Ponieważ wybraliśmy bazę danych SQLite potrzebujemy wskazać miejsce zapisu danych. Z menu znajdującego się po lewej stronie wybieramy Ustawienia a następnie, nawigujemy się do sekcji „Add-on Settings” i klikamy „JDBC Persistence SQLite„. Wyświetlony formularz służy do konfiguracji połączenia z bazą danych oraz nadpisywania zapytań, jeżeli jest to z jakiś względów konieczne. Wystarczy, że w polu „Database URL” wpiszemy „jdbc:sqlite:./history.db” i zapiszemy te zmiany za pomocą przycisku Zapisz. Pozostałe opcje pozostawiamy bez zmian.

Ścieżka ./history.db spowoduje utworzenie bazy w katalogu userdata, wewnątrz folderu openhab-4.1.2, tj. C:\tools\openhab-4.1.2\userdata\history.db.

Domyślna konfiguracja zapisu do bazy jest określona jako „everyChange”, co oznacza że wpis w bazie jest tworzony tylko i wyłącznie jeśli stan itemu (pochodzący z kanału) zgłoszony przez dodatek różni się od poprzedniego. Inne strategie to np. „everyUpdate”, która powoduje zapis każdej próbki.

Jeśli ktoś preferuje zewnętrzną bazę danych, to może skorzystać z jednej z kilku dostępnych opcji – oczywiście dostępna jest integracja z InfluxDB. Z relacyjnych baz danych można wykorzystać MySQL, PostgreSQL, Oracle a także Microsoft SQL Server. Co istotne, w jednym momencie możemy mieć skonfigurowane tylko jedno połączenie do bazy SQL. Czyli, jeśli chcemy zacząć zapisywać dane w MySQL to nie możemy dalej korzystać ze SQLite.

Odczyt licznika

W celu zademonstrowania możliwości konfiguracyjnych openHAB potrzebujemy urządzenia, które chcielibyśmy zintegrować. Autor wybrał dwukierunkowy licznik energii elektrycznej PRO380-Mod firmy inepro Metering. Jest to dość popularny typ licznika, który jest sprzedawany pod różnymi markami. Charakterystyczną cechą licznika jest wyświetlacz LCD podświetlany na niebiesko oraz pomarańczowe akcenty na obudowie. Aby nie siedzieć z laptopem w szafie licznik zostanie podpięty pod konwerter Modbus RTU/Modbus TCP.

Ponieważ asortyment oparty o protokół Modbus wymaga pracy z dokumentacją, w pierwszej kolejności należy zaopatrzyć się w listę rejestrów właściwą danemu urządzeniu. Z jej pomocą możemy przystąpić do ustalenia przesunięcia pomiędzy dokumentacją, implementacją protokołu po stronie urządzenia oraz narzędzia odczytującego. Słynne nawigowanie +1, -1.

W celu ustalenia przesunięcia potrzebujemy zidentyfikować rejestr, który ma stabilną oraz łatwą do  zweryfikowania wartość. Ponieważ PRO380-Mod domyślnie ma ustawiony identyfikator jednostki (modbus unit id) na 1 oraz baud rate na 9600 możemy skorzystać z tych dwóch wartości aby określić ewentualne przesunięcie rejestrów.

Zgodnie z dokumentacją identyfikator licznika znajduje się w rejestrze 1018 oraz 4003, natomiast prędkość transmisji w rejestrze 1020 oraz 4004. Rejestry są blisko siebie, co ułatwi sprawę. Warto zwrócić uwagę na to, że w pierwszej i drugiej kolumnie dokumentacji dalsze rejestry mają postać 400A. Oznacza to, że producent w dokumentacji skorzystał z notacji szesnastkowej, którą potrzebujemy przełożyć na reprezentację dziesiętną.

Możemy się domyślać że zastosowanie dwóch schematów adresowania wynika z różnej obsługi protokołu w narzędziach, gdzie niektóre narzędzia łączą adres rejestru oraz identyfikator funkcji. Co ciekawe, drugi zestaw rejestrów ma nieco inną charakterystykę. Ma mniejsze przerwy pomiędzy rejestrami, dzięki czemu możemy próbować odczytać całość przy pomocy kilku bloków danych.

Wracamy do przeglądarki. Z menu znajdującego się po lewej stronie wybieramy Ustawienia a następnie „Things„. W prawym dolny rogu klikamy ikonę +, która dla ułatwienia znajduje się w niebieskim kółku. Na screenie poniżej liczby z czerwonym podkładem pokazują kolejność klikania.

Z listy, która się pojawiła wybieramy „Modbus Binding„. Naszym oczom powinna ukazać się lista podobna do tej poniżej.

Dlaczego na tej liście jest aż tyle pozycji? Odpowiedź jest prosta – są to predefiniowane typy rzeczy, które obsługuje dodatek modbus. Podczas uruchomienia openHAB wybraliśmy dodatek Modbus, co spowodowało zainstalowanie dodatków pomocniczych, które bazują na Modbus. To dlatego na liście mamy między innymi Licznik, stację ładowania a także falownik fotowoltaiczny. Z listy wybieramy „Modbus TCP Slave„.

Naszym oczom powinna ukazać się formatka do wprowadzenia konfiguracji połączenia. Oprócz unit id, adresu IP oraz portu możemy również zmienić „kodowanie” na rtu over tcp. Oprócz tego, mamy również możliwość zaznaczenia opcji „Discovery Enabled”. Jej wybranie spowoduje po zapisie przeskanowanie rejestrów w poszukiwaniu znanych urządzeń. Zostawiamy ją wyłączoną (jest wyłączona gdy przełącznik jest szary) i zapisujemy konfigurację.

Nasza rzecz powinna teraz być na liście i mieć zaznaczony na zielono status „ONLINE”. Chyba, że wpisaliśmy nieprawidłowy adres IP, wówczas trzeba wykonać korektę. Poza tym, że nasza rzecz jest na zielono, nic w niej nie ma.

Potrzebujemy wrócić tutaj na chwilę do koncepcji rzeczy, mostów oraz kanałów. To, co przed chwilą zdefiniowaliśmy to most, czyli połączenie TCP. Teraz potrzebujemy dla tego połączenia zdefiniować zakres rejestrów do odczytu. Zrobimy to za pomocą elementu poller, po czym ustalimy mapowanie wartości za pomocą elementu data.

Klikamy raz jeszcze niebieski „+” w celu dodania kolejnej rzeczy. Tym razem wybieramy Regular Poll. Naszym oczom powinna ukazać się ponownie formatka, jednak tym razem z innym zestawem pól. Ponieważ poller działa w kontekście połączenia Modbus to w polu „Parent Bridge” wybieramy utworzone wcześniej połączenie TCP. Dopiero po tym przechodzimy niżej.

W sekcji konfiguracji mamy możliwość zdefiniowania rejestru startowego (pole Start) oraz długości odczytu (pole Length). W pierwszym wpisujemy wartość 4096 (odpowiednik 0x1000) a w drugim 34. Powinno to pozwolić nam na odczyt bloku identyfikacyjnego włącznie z rejestrem baud rate (odpowiednik 0x1020 to 4128). Dla pola Typ wybieramy holding register (odpowiednik funkcji 03). Po zapisaniu nasz element również powinien pojawić się na liście ze statusem ONLINE.

Teraz możemy przystąpić do mapowania dwóch pierwszych rejestrów, które pozwolą nam na ustalenie ewentualnego przesunięcia adresów. Raz jeszcze przechodzimy przez niebieski „+„, ale tym razem wybieramy Modbus Data.

W polu Parent wskazujemy na wcześniej utworzony Poller, a w ustawieniach wpisujemy rejestr, który chcemy zmapować. W naszym przykładzie jest to 4120 (odpowiednik 0x1018, unit id). Zmieniamy również Read Value Type na „16 bit signed integer (int16)„, co powinno wystarczy na spodziewany zakres wartości (0-247). Pozostałe opcje pozostawiamy bez zmian. Zapisujemy i powtarzamy proces dla kolejnego rejestru.

Drugie mapowanie rejestru to 4128 (0x1020, baud) Read Value Type również int16.

Mamy zatem zmapowane rejestry, ale gdzie są odczytane wartości? Do tej pory zdefiniowaliśmy rzeczy, ale nie stworzyliśmy lub skonfigurowaliśmy kanałów. Dodatek modbus, jak widać, dość dokładnie odzwierciedla logikę protokołu. Pozwala on na zdefiniowanie połączenia oraz bloków danych wraz z wykorzystywaną funkcją odczytu. W jego przypadku nie musimy tworzyć kanałów, ponieważ te są, tylko że zostały zdefiniowane za nas na poziomie rzeczy Modbus Data. Po przejściu z „Ustawienia” do listy rzeczy tj. „Things” i kliknięciu elementu „Modbus Data: unit id” tuż pod nazwą widoczną na kolejnym ekranie, widzimy 3 zakładki: Thing, Channels oraz Code. W pierwszej zakładce już byliśmy, ponieważ służy ona do zmiany konfiguracji, po przełączeniu do drugiej widzimy listę kanałów dostępnych dla danej rzeczy.

Po kliknięciu w “Value as Number” nie ma nic, ponieważ nie ma elementu (itemu) który odbiera dane z tego kanału. W tym celu klikamy w „Add Link to Item..„. W formatce wybieramy „Create a new item” oraz uzupełniamy dane. W polu label wpisujemy „Unit id” i zapisujemy.

Po zapisaniu powinniśmy wrócić do listy kanałów. Tym razem poniżej „Value as Number” powinno być coś więcej:

Wszystko wskazuje na to, że mapowanie jest prawidłowe. Dla pewności powtarzamy proces dla rejestru baud rate. Jeśli wszystko jest w porządku możemy przystąpić do mapowania odczytów, przede wszystkim, tych związanych z odczytami mocy i energii. Nie mniej, zanim do tego przejdziemy, musimy odpowiedzieć sobie na pytanie czy rzeczywiście trzeba aż tyle się naklikać żeby dodać tylko dwa rejestry? Co jeżeli urządzenia ma ich kilkaset?

Proces ten oczywiście można przyspieszyć. Przeprowadzenie go przez interfejs użytkownika pozwoliło na zaznajomieniu z panelem administracyjnym oraz pokazanie, że w razie problemów zawsze można z skorzystać z niego, aby przeprowadzić szybką diagnostykę połączenia czy też mapowania rejestrów.

Zarządzanie konfiguracją

Jedną z mocnych stron openHAB jest możliwość przeniesienia praktycznie całej konfiguracji akwizycji i procesowania danych do plików. Oznacza to, że proces czasochłonnego nawigowania się przeglądarką przez dziesiątki formularzy możemy zastąpić kilkoma (kilkunastoma lub kilkudziesięcioma) minutami w edytorze tekstowym, który przyśpieszy pracę na powtarzalnych fragmentach konfiguracji. Ponadto konfiguracja zachowana w pliku, ułatwia również wykorzystanie systemu kontroli wersji takiego jak Git, Mercurial lub SVN. Zawsze taki plik można też udostępnić drugiej osobie, aby mogła powielić konfigurację bez klikania.

Zanim zagłębimy się w detale jak zrobić mapowanie, garść informacji. Pliki konfiguracyjne w openHAB korzystają z dedykowanej składni, która jest właściwa tylko temu narzędziu. Składnia tych plików jest określana jako DSL, czyli z Domain Specific Language, oznacza to język specyficzny dla domeny. Ponieważ poznaliśmy już 2 obszary tj. Things oraz Items, wiemy że „domeny”, a przynajmniej dość specyficzne obszary, są dwa. Dla każdego z nich będzie obowiązywać nas inna składnia konfiguracji – jedna dla rzeczy, druga dla itemów.

Konfiguracja rzeczy z pliku

Pliki konfiguracyjne rzeczy i itemów są odczytywane z różnych katalogów. Pierwsze należy skopiować do katalogu conf/things/, drugie do conf/items/. W obydwu przypadkach plikom trzeba nadać odpowiednie rozszerzenie, odpowiednio .things lub .items. Warto zaznaczyć, że plików może być wiele oraz ich nazwy nie są powiązane z dodatkami. Na start wewnątrz conf/things tworzymy plik pro380.things z poniższą zawartością:

Bridge modbus:tcp:pro380 "Licznik Modbus PRO-380-Mod"  {

  Bridge poller info "Information block"  {
    Thing data serialNumber "serial number" 
    Thing data code "code" 
    Thing data modbusId "modbus id" 
    Thing data baudRate "baud rate" 
    Thing data protocolVersion "protocol version" 
    Thing data softwareVersion "software version" 
    Thing data hardwareVersion "hardware version" 
  }
}

Tym razem skorzystaliśmy z innego zakresu rejestrów (zakres od 0x4000 zamiast 0x1000), niemniej zakres informacji jest tożsamy z wcześniejszym. Dzięki skorzystaniu z pliku mamy możliwość stworzenia hierarchii most/rzecz tj. Bridge/Thing o której dowiedzieliśmy się w pierwszej części artykułu.

Poller „info” jest umieszczony wewnątrz mostu „modbus:tcp:pro380”, co automatycznie powoduje przydzielenie go do „połączenia”. Podobnie sprawa ma się z mapowaniem rejestrów poprzez „Thing data”, elementy te są wewnątrz pollera, przez co z automatu operują one na bloku danych zdefiniowanym przez poller.

Dodatkowo, dzięki propagacji typu dodatku (modbus:), nie musimy powtarzać tej informacji przy każdej kolejnej rzeczy – możemy korzystać z odwołania do poller i data zamiast modbus:poller i modbus:data.

Pełna składnia pliku things jest opisana w oficjalnej dokumentacji, i ma kilka opcji, których nie będziemy roztrząsać. Powyższy przykład jest bardzo kompaktową reprezentacją mapowania rejestrów.

Konfiguracja itemów z pliku

Skoro mamy definicję rzeczy, to teraz kolej na definicję itemów. Tworzymy plik pro380.items w katalogu conf/items z zawartością:

Number PRO380_Serial "Pro 380 Serial Number" { channel="modbus:data:pro380:info:serialNumber:number" }

Number PRO380_Code "Pro 380 code" { channel="modbus:data:pro380:info:code:number" }

Number PRO380_ModbusId "Pro 380 Modbus id" { channel="modbus:data:pro380:info:modbusId:number" }

Number PRO380_BaudRate "Pro 380 baudRate" { channel="modbus:data:pro380:info:baudRate:number" }

Number PRO380_Protocol_Version "Pro 380 protocolVersion" { channel="modbus:data:pro380:info:protocolVersion:number" }

Number PRO380_Software_Version "Pro 380 softwareVersion" { channel="modbus:data:pro380:info:softwareVersion:number" }

Number PRO380_Hardware_Version "Pro 380 hardwareVersion" { channel="modbus:data:pro380:info:hardwareVersion:number" }

Tym razem znowu pojawiły się nawiasy klamrowe, natomiast ich zawartość ma inne przeznaczenie. Wewnątrz nich definiujemy wskaźnik na kanał, z którego pragniemy wyciągnąć informacje (lub zapisać). Składnia jest nieco inna tj. $Typ $Nazwa „$etykieta” { channel=”$channel-id” }.

Warto zwrócić uwagę, że channel-id rozwija się do wartości z pliku things tj. modbus:$TypRzeczy:$IdPołączenia>:$Id Pollera:$IdMapowania:$IdentyfikatorKanału. Identyfikator jest długi, ponieważ plik items nie definiuje sposobu na stworzenie hierarchii. Dodatkowo dla innych dodatków identyfikator kanału będzie wyglądał nieco inaczej i odzwierciedlał właściwą im logikę mapowania połączeń i kanałów.

Jednostki miar i wielkości fizyczne

Oprócz tego, że w pliku items możemy zdefiniować powiązany kanał możemy również pójść krok dalej i określić po pierwsze – jednostkę bazową do zapisu stanu w bazie, jednostkę do prezentacji danych a także sposób transformowania wartości przesyłanej z/do kanału.

Na razie ograniczymy się do samych jednostek, ponieważ są one istotne z punktu widzenia ponownego wykorzystania definicji itemów.

W przypadku gdy mamy do czynienia z wielkością fizyczną możemy wykorzystać jedną z kilkunastu predefiniowanych wielkości z układu SI, która pozwoli na przypisanie domyślnej jednostki dla danego odczytu. Na przykład Tworząc item typu Number:Power (który jest rozszerzeniem wartości liczbowej) system automatycznie zakłada, że jednostką bazową jest Watt. Niestety dodatek Modbus nie ma możliwości przypisania jednostki dla stanów liczbowych zgłoszonych przez kanał, przez co stworzony Number:Power będzie powodował błędną reprezentację odczytu – nasz licznik raportuje moc jako liczbę zmiennoprzecinkową wyrażającą moc, ale w kilowatach. Aby poprawnie zmapować te rzeczy, jak również poradzić sobie z sytuacją gdy nasza konfiguracja ewoluuje a mamy już wcześniejszą historię odczytów, możemy określić jednostkę bazową itemu. Służą do tego tzw. Metadane. Możemy je definiować przez interfejs użytkownika, ale również w plikach. Metadane są uporządkowane według przestrzeń nazw (ang. namespace), która może być wartością prostą (tekst) i opcjonalnie zawierać konfigurację.

Przyjrzyjmy się zapisowi:

Number:Power PRO380_ActivePower_Total "Total active power" {
  channel="modbus:data:pro380:p2:totalActivePower:number",
  unit="kW",
  stateDescription=""
}

Oznacza on, że jednostką bazową danego itemu jest kilowat (przestrzeń nazw/parametr unit=”kW”). W praktyce oznacza to tyle, że jest to jednostka do której jest normalizowany stan itemu. Jeśli kanał zgłosi wartość 2 (bez jednostki), to faktyczny stan itemu zostanie ustawiony na 2 kW. Ta wartość zostanie też zapisana w bazie danych.

Na powyższym przykładzie mamy jeszcze jedną konstrukcję, która jest nieco bardziej złożona. Jest to stateDescription, który nie ma przypisanej wartości tekstowej, ale za to ma parametr pattern. Ponieważ metadane mogą przybierać dość złożony kształt, ich definicja oparta jest o konstrukcję klucz=wartość, która może być wykorzystywana przez rdzeń systemu, ale również dodatki.

Przestrzeń nazw stateDescription służy do mapowania stanu itemu. Mapowanie to może np. Przypisywać etykiety tekstowe do wartości liczbowych, ale również narzucać formatowanie wartości liczbowych. Właśnie temu służy pattern. Jeśli wewnętrzny stan itemu to 2 kW to wzorzec %.2f W spowoduje że wartość będzie wyświetlana jako 2000.00 W. Część .2 oznacza dwa miejsca po przecinku, podczas gdy %f liczbę zmiennoprzecinkową. Kombinacji jest oczywiście więcej – możemy stosować dopełnienie zerami (%.03f => 2000.000), usuwać miejsca po przecinku (%.0f => 2000) czy wymuszać reprezentację szesnastkową (%02x, dla wejścia 10 wyświetli 0a).

Warto mimo wszystko pamiętać, że stateDescription jest sposobem na określenie formatu prezentacji i ma zastosowanie głównie w interfejsie użytkownika. Zapis do urządzenia jest kontrolowany przez dodatek.

Pełna konfiguracja rzeczy i mapowanie danych

W celu zaoszczędzenia pracy kompletna konfiguracja może zostać pobrana z repozytorium github autora: https://github.com/splatch/iautomatyka.

Wizualizacja danych

Skoro mamy mapowanie danych i uzyskaliśmy już interesujące nas informacje to pora na wizualizację danych. Ponieważ korzystamy z openHAB, tym razem obejdziemy się bez Grafany. Wykresy obsługiwane przez OH są prostsze, trochę mniej dynamiczne, ale dzięki temu że są wbudowane w istniejący interfejs użytkownika i mogą bazować na osadzonej bazie danych. Zmniejszamy w ten sposób liczbę konfiguracji i ograniczamy obciążenie procesora dodatkowymi programami. Oczywiście wszystko to odbywa się to kosztem mniejszej liczby opcji.

Na wstępie dodam, że Dashboardy nie są możliwe do zdefiniowania przy pomocy plików. Podobnie jak w przypadku Grafany ich definicje są zapisywane na dysku w pliku JSON. Ich definicje w formacie YAML można przekopiować ręcznie do przeglądarki, ewentualnie skopiować cały plik z definicją wizualizacji.

Ostatnia dygresja zanim przejdziemy do samego dashboardu – openHAB ma kilka interfejsów graficznych. Historycznie mamy do dyspozycji Basic UI (proste i szybki interfejs pod telefony), Hab Panel (rozbudowany kreator dashboardów, ale od jakiegoś czasu nierozwijany) oraz main ui, z którego skorzystamy. Ten sposób na budowanie wizualizacji stał się częścią projektu od wydania 3.0 (grudzień 2020) jako fuzja basic ui oraz habpanelu. To właśnie z tego interfejsu korzystamy do zarządzania konfiguracją, skorzystamy z niego też do wizualizacji. Sama aplikacja mobilna openHAB obsługuje zarówno Basic UI jak i main ui.

Wewnątrz main ui wizualizacja sprowadza się do trzech koncepcji. Pierwszą są strony, które możemy budować korzystając z edytora graficznego. Strony mogą być dodawane do menu, powyżej linku do ustawień. Drugim są widgety, czyli fragmenty do parametryzacji i ponownego użycia, które możemy tworzyć samodzielnie i wykorzystywać przy konstruowaniu stron.
Standardowa dystrybucja openHAB obsługuje 6 typów stron – wykres (chart), map (tj. openstreetmap), strona z zakładkami (tabbed page), layout (tj. dashboard), sitemap (tj. basic ui) oraz floor plan (rzut).

Wykres zużycia energii

Nie wchodząc w zbędne szczegóły, wracamy do przeglądarki. Z nawigacji po lewej stronie wybieramy „Ustawienia” a następnie „Pages„. W prawym dolnym rogu klikamy „+” w niebieskim kółku, z wyświetlonych opcji wybieramy „create chart„.

Naszym oczom powinien ukazać się nowy widok, który ma kilka opcji. Nawigacja po nim nie jest najprostsza. Zacznijmy od spraw najbardziej istotnych.

W pierwszym formularzu, w który mamy identyfikator oraz label możemy przypisać identyfikator techniczny (widoczny w pasku adresu) oraz etykietę tekstową wyświetlaną. W sekcji sidebar & visibility definiujemy poziom dostępu do strony oraz to, czy powinna ona być widoczna w menu.

Poniżej w sekcji “Chart Configuration” mamy już opcje właściwe wykresom. Ponieważ wykresy przede wszystkim obrazują zmianę wraz z upływem czasu zaczynamy od ustalenia typu wykresu. Czy jest on dynamiczny (Dynamic period) tj. pozwala na zmniejszenie lub rozszerzenie przedziału czasu, czy też jest on ograniczony do zakresu czasu typu dzień, miesiąc, rok. Wybieramy dzień (Day). Wybór ten nie oznacza, że utkniemy na dniu dzisiejszym, a jedynie że w przypadku nawigacji posuwamy się o +/- dzień.

Poniżej tych ustawień mamy ogólny widok, który pozwala na dobranie części, z których zbudujemy wykres. Komponentów jest kilka, natomiast minimum, od którego zaczynamy to układ współrzędnych.
Sekcja „other components” zawiera komponenty pomocnicze, które można wykorzystać niezależnie od  współrzędnych.

Zaczynamy od dodania siatki (Grid), następnie klikamy „+” na czarnym tle obok osi Y i wybieramy „value axis”. Powtarzamy tę czynność dla osi X, ale wybieramy „category axis”, i zaznaczamy w polu Categories „Hours of Day” – jest to zakres do którego chcemy ograniczyć oś X.

W trakcie konfiguracji można zauważyć, że w obydwu osiach powtarza nam się możliwość wyboru value axis lub category axis. Wynika to z tego, że możemy stworzyć wykres, w którym oś czasu jest pionowa (Y) lub pozioma (X). W naszym przypadku wykres będzie tradycyjny, czyli poziomy.

Ostatnia czynność to dodanie danych do wykresu. Klikamy „Add aggregate series”. W popupie, który wyskoczył mamy multum opcji. Przede wszystkim w polu „Name” możemy określić etykietę tekstową danych. Druga istotna opcja to „Item” w którym wybieramy element, którego historię chcemy wizualizować. Klikając w to pole mamy możliwość wyboru elementu, zamiast wpisywania jego nazwy – wybieramy PRO380_ActiveEnergy_Total.


Druga część formularza to typ wizualizacji, innymi słowy czy tworzymy wykres słupkowy czy liniowy. Wybieramy wykres słupkowy, czyli „Bar”. Ponieważ historia zapisów jest uporządkowana chronologicznie, ale nie jest pogrupowana, potrzebujemy wybrać również wymiar w którym chcemy umieścić odczyty. Robimy to korzystając z opcji „First Dimension” w której wybieramy godzinę „Hour of Day”. Spowoduje to przyporządkowanie odczytu do godzin, tak aby mieściły się one w zakresie osi X. Limit ten zdefiniowaliśmy wcześniej.

Ostatni już punkt to wybór metody agregowania danych. Ponieważ w danej godzinie możemy mieć wiele odczytów zużycia energii, metoda agregacji pozwala nam na zdecydowanie który z nich chcemy wybrać. Możemy skorzystać z kilku podstawowych algorytmów. Najprostsze to te, które operują na wartościach z danego zakresu np. minimum lub maksimum. Te bardziej złożone operują na wartościach z sąsiednich zakresów np. diff_first lub diff_last. Algorytmy te porównują próbki według ich czasu powstania, ale z sąsiednich zakresów. Oznacza to, że korzystając z algorytmu diff_first porównamy (czysto teoretycznie) odczyt liczydła z 00:02:00 oraz 00:01:00. Analogicznie dla diff_last, przy odpowiedniej częstotliwości próbkowania wynik będzie różnicą pomiędzy próbką z 00:02:59 a 00:01:59. Wybieramy diff_last, ponieważ interesuje nas zużycie w przedziale na podstawie ostatniego odczytu. Jeśli mamy wszystko możemy podejrzeć czy całość rysuje się prawidłowo – wystarczy kliknąć w prawym dolny rogu przełącznik „Run mode”.

Brakuje nam tylko jednej rzeczy, żeby poczuć się jak w Grafanie – dymku z wartością. Dodajemy zatem “tooltip”, z domyślnymi opcjami. Pomoże on w zweryfikowaniu wyników obliczeń diff_last. Po tym wszystkim możemy zapisać wykres i sprawdzić czy pojawi się w menu.

Kompletna konfiguracja wykresu (zakładka code) wygląda tak:

config:
  chartType: day
  label: Zużycie
  sidebar: true
  visibleTo:
  - role:administrator
  - role:user

slots:
  grid:
  - component: oh-chart-grid
    config: {}
  series:
  - component: oh-aggregate-series
    config:
      aggregationFunction: diff_last
      dimension1: hour
      item: PRO380_ActiveEnergy_Total
      name: PRO380_ActiveEnergy_Total
      type: bar
      gridIndex: 0
      xAxisIndex: 0
      yAxisIndex: 0
  tooltip:
  - component: oh-chart-tooltip
    config:
      orient: horizontal
      show: true
  xAxis:
  - component: oh-category-axis
    config:
      categoryType: day
      gridIndex: 0
      monthFormat: defaul
      weekdayFormat: default
  yAxis:
  - component: oh-value-axis
    config:
      gridIndex: 0

Składnia powyżej to YAML, tj. Yet Another Markup Language. To, co go charakteryzuje to konieczność zachowania stałego wcięcia, zupełnie jak w plikach z kodem Python. Można go skopiować do przeglądarki. Spodziewany efekt znajduje się poniżej:

Wysoki słupek na początku wynika z przerwy w odczytach. Jeśli zatrzymaliśmy system monitorowania energii (czyli naszego openHABa) i ostatni odczyt, który zarejestrował był np. o godzinie 15:59 poprzedniego dnia, to po uruchomieniu systemu z powrotem o 8:00 mamy lukę w odczytach. Jako, że system nie posiada odczytów od 16:00 do 7:59, a liczydło nie stało w miejscu, to mamy efekt kumulacji i widoczne przekłamanie na wykresie.

Poprzez powielenie oh-aggregate-series można dorzucić kolejne “słupki” dla fazy 1, 2 oraz 3. Nie mniej, w przypadku faz chcielibyśmy wartości umieścić na jednym słupku, aby zaprezentować ich wartości obok łącznego zużycia. W ten sposób będziemy mogli ocenić, czy obciążenie faz jest stabilne, czy się zmienia i mamy duże dysproporcje zużycia między fazami. Do układania danych na sobie służy parametr „stack” na poziomie serii danych. Parametr ten można dodać w kodzie, ale nie w formularzu.

Potrzebujemy ręcznie zmodyfikować kod i dodać poniżej pierwszej serii danych kolejne trzy:

  - component: oh-aggregate-series
    config:
      aggregationFunction: diff_las
      dimension1: hour
      item: PRO380_ActiveEnergy_L1
      name: L1
      stack: phases
      type: bar
      gridIndex: 0
      xAxisIndex: 0
      yAxisIndex: 0
  - component: oh-aggregate-series
    config:
      aggregationFunction: diff_last
      dimension1: hour
      item: PRO380_ActiveEnergy_L2
      name: L2
      stack: phases
      type: bar
      gridIndex: 0
      xAxisIndex: 0
      yAxisIndex: 0
  - component: oh-aggregate-series
    config:
      aggregationFunction: diff_last
      dimension1: hour
      item: PRO380_ActiveEnergy_L3
      name: L3
      stack: phases
      type: bar
      gridIndex: 0
      xAxisIndex: 0
      yAxisIndex: 0

Rezultat powyższych zmian powinien wyglądać mniej-więcej tak:

Słupek niebieski to zużycie łączne, podczas gdy sąsiedni stos to zużycie energii na poszczególnych fazach.

Najbardziej użyteczne i równocześnie rozbudowane pod względem dostępnych opcji są strony typu chart oraz layout. Istotnym dodatkiem są tabbed pages, które pozwalają na grupowanie stron, dzięki czemu ograniczają konieczność rozbudowy menu.

Podsumowanie

Jak widać można stworzyć kompletny system odczytu zużycia energii oraz wizualizacji korzystając tylko i wyłącznie z jednego narzędzia. Tym narzędziem może być openHAB, który nie tylko nie wymaga ponoszenia wysokich kosztów licencyjnych, ale pozwala na w miarę łatwą integrację z istniejącymi systemami automatyki oraz systemami odczytowymi.

W tym artykule starałem się pokazać, że całość może działać z systemem Microsoft Windows, natomiast nic nie stoi na przeszkodzie aby całość uruchomić pod Linuxem (Ubuntu, Debian). Niezależnie czy mówimy o stacji roboczje czy komputerze przemysłowym dzięki wykorzystaniu Java Virtual Machine openHAB będzie działał tak samo dobrze i na systemach wyposażonych w procesor ARM jak i Intel.

Ponieważ pisanie artykułu zajęło mi kilka dni, w bazie danych udało mi się zebrać również pokaźną liczbę próbek, co wynika z odczytu napięcia, natężenia oraz mocy co 500ms. Moja baza SQLite, która zawiera dane z 10 dni waży bagatela, 150 MB.
Warto o tym pamiętać, zwłaszcza jeśli zapisujemy dane korzystając z wbudowanej pamięci flash (eMMC) lub karty SD. Obydwa nośniki są wrażliwe na ilość zapisów, a jak widać tych, możemy mieć bardzo dużo.