Jak już jakiś czas temu wspominałem, że zamierzam przyjrzeć się plikowi OM.LUA. Jest mi to potrzebne do dalszej pracy z Grentonem.
Konfiguracja CLU
Clu Grentona jest konfigurowane przez Object Managera, w którym użytkownik może wyklikać konfigurację. Następnie ta konfiguracja jest wysyłana na CLU za pomocą protokołu tftp. W skład konfiguracji wchodzą następujące pliki:
CONFIG.TXT – jest to plik w którym zapisane są klucze szyfrujące, wersja oprogramowania, ip CLU
OM.LUA – plik służący do konfiguracji modułów.
USER.LUA – plik w którym przechowywane są skrypty (funkcje) napisane przez użytkownika.
MAIN.LUA – jest to główny plik uruchamiany po włączeniu się CLU. Dołącza on konfigurację z plików USER, OM,
Plik MAIN.LUA wygląda następująco. Dodałem komentarze z prawej strony
collectgarbage("collect") require "user" -- dołączenie skryptów użytkownika collectgarbage("collect") require "om" -- dołączenie konfiguracji modułów collectgarbage("collect") function checkAlive() -- nazwa jest trochę myląca. Funkcja ta zwraca "id" Clu, które jest skonfigurowane w pliku OM.LUA return "0d1cf150" end SYSTEM.Init() -- inicjalizacja systemu. Prawdopodobnie, wywołanie tej metody wyzwala event OnInit. repeat SYSTEM.Loop() -- główna pętla Clu. until 1==2
Co robi plik OM.LUA?
Przejdźmy do najważniejszego, czyli konfiguracji modułów. Konfiguracja ta jest zapisana w OM, ale przy wysyłce na CLU jest tłumaczona do LUA.
Plik zaczyna się od konfiguracji samego CLU:
CLU_0d1cf150 = OBJECT:new(0, 0xC0A802C8) -- NAME_CLU DOM=CLU_0d1cf150
Obiekty modułów są tworzone za pomocą fabryki(?) o nazwie OBJECT. W nazwie zmiennej, do której przypisane jest CLU zaszyte jest ID modułu. Czyli CLU_0d1cf150 to szesnastkowy zapis: 220000592. Poniżej jest też komentarz w którym zapisana jest nazwa jaką przyznałem CLU, czyli DOM. Prawdopodobnie jest to potrzebne, gdy podłączamy się z OM pod istniejącą konfigurację i nie chcemy zmieniać nazw obiektów, które już zostały zdefiniowane. Metoda “new” przyjmuje dwa argumenty. Pierwszy – 0 (zero) to w tym przypadku ID urządzenia. Drugi argument to IP. Wartość jest zapisana w Hex. Aby odczytać IP należy przekonwertować tę liczbę do postaci dziesiętnej, a potem użyć funkcji z PHP long2ip.
0xC0A802C8(HEX) -> 3232236232(DEC) -> long2ip(3232236232) -> 192.168.2.200
Następnie zdefiniowane są moduły. W moim przypadku wpisy wyglądają następująco:
-- MODULES mm_180001305 = OBJECT:new(2, 0x0aba9a19, 0x00) -- 180001305 00 10 mm_200003152 = OBJECT:new(2, 0x0bebce50, 0x01) -- 200003152 01 0b mm_200003293 = OBJECT:new(2, 0x0bebcedd, 0x01) -- 200003293 01 0b mm_460000424 = OBJECT:new(2, 0x1b6b0ca8, 0x08) -- 460000424 00 11 mm_113247182 = OBJECT:new(2, 0x06c003ce, 0xff) -- 113247182 28 01 mm_154160907 = OBJECT:new(2, 0x09304f0b, 0xff) -- 154160907 28 01
I tym razem użyta jest metoda OBJECT:new czyli ta sama co przy tworzeniu CLU. W tym przypadku przyjmuje trzy parametry a nie jak poprzednio dwa. W tym wypadku “2” może oznaczać, że są to moduły na szynę DIN. Wartości w drugim argumencie to ID moich modułów. Co do ostatniego argumentu nie jestem pewien. Wydaje mi się, że oznacza typ modułu.
0x00- digital in
0x01 – digital out
0x08 – analog out
0xFF – czujnik temperatury 1-wrie
Z prawej strony znajduje się komentarz, który powiela te informacje, ale typy (np. 10) zgadzają się ze słownikami zaszytymi w kodzie OM. Wygląda na to, że CLU ma własny słownik i OM ma własny.
Po skonfigurowaniu modułów można zacząć konfigurować poszczególne wejścia i wyjścia, które te moduły posiadają. Konfiguracja znów odbywa się za pomocą metody w new klasy OBJECT i wygląda następująco:
-- IO_MODULES DIN_6650 = OBJECT:new(3, mm_180001305, 0) -- NAME_IO x180001305_DIN1=DIN_6650 DIN_1277 = OBJECT:new(3, mm_180001305, 1) -- NAME_IO x180001305_DIN2=DIN_1277 DIN_8304 = OBJECT:new(3, mm_180001305, 2) -- NAME_IO x180001305_DIN3=DIN_8304 DIN_4380 = OBJECT:new(3, mm_180001305, 3) -- NAME_IO x180001305_DIN4=DIN_4380 DIN_1066 = OBJECT:new(3, mm_180001305, 4) -- NAME_IO x180001305_DIN5=DIN_1066 DIN_7578 = OBJECT:new(3, mm_180001305, 5) -- NAME_IO x180001305_DIN6=DIN_7578 DIN_3284 = OBJECT:new(3, mm_180001305, 6) -- NAME_IO x180001305_DIN7=DIN_3284 DIN_0388 = OBJECT:new(3, mm_180001305, 7) -- NAME_IO x180001305_DIN8=DIN_0388
Rozszyfrowałem parametry następująco. Jest to konfiguracja 8 wejść digital in (od 0 do 7). Każde wyjście jest przypisane do globalnej zmiennej. O nazwach zaczynających się od prefiksu “DIN_”. Pierwszym parametrem jest 3, co prawdopodobnie oznacza, żeby używać fabryki obiektów klasy DigitalIn. Potem przekazana jest do obiektu modułu w ramach, którego pracuje dane wejście, a na koniec przypisane jest konkretne wejście (cyfry 0-7).
Podobnie wygląda konfiguracja DigitalOut:
DOUT_2485 = OBJECT:new(4, mm_200003152, 0) -- NAME_IO x200003152_DOUT1=DOUT_2485 DOUT_6848 = OBJECT:new(4, mm_200003152, 1) -- NAME_IO x200003152_DOUT2=DOUT_6848 DOUT_8565 = OBJECT:new(4, mm_200003152, 2) -- NAME_IO x200003152_DOUT3=DOUT_8565 DOUT_4705 = OBJECT:new(4, mm_200003152, 3) -- NAME_IO x200003152_DOUT4=DOUT_4705 DOUT_6710 = OBJECT:new(4, mm_200003293, 0) -- NAME_IO x200003293_DOUT1=DOUT_6710 DOUT_3423 = OBJECT:new(4, mm_200003293, 1) -- NAME_IO x200003293_DOUT2=DOUT_3423 DOUT_4513 = OBJECT:new(4, mm_200003293, 2) -- NAME_IO x200003293_DOUT3=DOUT_4513 DOUT_4114 = OBJECT:new(4, mm_200003293, 3)
W sekcji powyżej widać konfigurację dwóch modułów DigitalIN: mm_200003152 oraz mm_200003293. Kolejną sekcja urządzeń będzie AnalogIn:
AnalogOUT_0042 = OBJECT:new(13, mm_460000424, 0) -- NAME_IO x460000424_AnalogOUT1=AnalogOUT_0042 AnalogOUT_4654 = OBJECT:new(13, mm_460000424, 1) -- NAME_IO x460000424_AnalogOUT2=AnalogOUT_4654 AnalogOUT_2371 = OBJECT:new(13, mm_460000424, 2) -- NAME_IO x460000424_AnalogOUT3=AnalogOUT_2371 AnalogOUT_0007 = OBJECT:new(13, mm_460000424, 3) -- NAME_IO x460000424_AnalogOUT4=AnalogOUT_0007 AnalogIN_3611 = OBJECT:new(12, mm_460000424, 0) -- NAME_IO x460000424_AnalogIN1=AnalogIN_3611 AnalogIN_6008 = OBJECT:new(12, mm_460000424, 1) -- NAME_IO x460000424_AnalogIN2=AnalogIN_6008 AnalogIN_7445 = OBJECT:new(12, mm_460000424, 2) -- NAME_IO x460000424_AnalogIN3=AnalogIN_7445 AnalogIN_4221 = OBJECT:new(12, mm_460000424, 3)-- NAME_IO x460000424_AnalogIN4=AnalogIN_4221
Tu też nie ma nic nowego. Moduł AnalogIN/OUT posiada 4 wejścia i wyjścia, których odzwierciedlenie widać w powyższej konfiguracji.
Na koniec zostały dwa czujniki temperatury podpięte pod 1-wire:
ONEW_SENSOR_7372 = OBJECT:new(23, mm_113247182, 0) -- NAME_IO x113247182_ONEW_SENSOR1=ONEW_SENSOR_7372 ONEW_SENSOR_6304 = OBJECT:new(23, mm_154160907, 0) -- NAME_IO x154160907_ONEW_SENSOR1=ONEW_SENSOR_6304
Nie jestem pewien skąd się wziął tak duży rozjazd pomiędzy ID tych czujników, tj: 113247182 a 154160907. Możliwe, że w termometrze jest zapisane to ID?
Kolejna sekcja to zdefiniowanie dwóch metod, które pozwalają na zapis zmiennych do globalnego scope w LUA.
function setVar(name, value) _G[name] = value end function getVar(name) return _G[name] end
Funkcje zostały zdefiniowane, ale w pliku OM.LUA nie ma śladu ich użycia. Pewnie używane są przez kod wbudowany w CLU. Następna sekcja odpowiedzialna jest za eventy (zdarzenia).
function EventsFor_DIN_6650_0() light_switch(nil) end DIN_6650:add_event(0, EventsFor_DIN_6650_0)
W tej chwili mam zdefiniowany jeden event, który na zdarzenie OnChange (to jest to zero) włączy fukcję (skrypt) light_switch. Następnie funkcja ta zostaje dodana do konkretnego wejścia, w tym wypadku do DIN_6650. Metoda add_event posiada dwa argumenty. Pierwszy to numer zdarzenia. Prawdopodobnie przypisane są po kolei, ale tylko zgaduję. Prawdopodobnie słownik wygląda tak:
0 – OnChange
1 – OnSwitchOn
2 – OnSwitchOff
3 – OnShortPress
4 – OnLongPress
5 – OnHold
6 – OnClick
Przed ostatnią sekcją jest inicjalizacja wartości domyślnych dla modułów. Wygląda ona następująco (po prawej moje komentarze)
function OnInit() -- INIT_CLU_OBJECTS DIN_6650:set(1, 0) -- moduł DigitalIN. 0 oznacza Intertion DIN_6650:set(2, 500) -- 2 oznacza HoldDelay DIN_6650:set(3, 50) -- 3 oznacza HoldInterwal DIN_1277:set(1, 0) DIN_1277:set(2, 500) DIN_1277:set(3, 50) DIN_8304:set(1, 0) DIN_8304:set(2, 500) DIN_8304:set(3, 50) DIN_4380:set(1, 0) DIN_4380:set(2, 500) DIN_4380:set(3, 50) DIN_1066:set(1, 0) DIN_1066:set(2, 500) DIN_1066:set(3, 50) DIN_7578:set(1, 0) DIN_7578:set(2, 500) DIN_7578:set(3, 50) DIN_3284:set(1, 0) DIN_3284:set(2, 500) DIN_3284:set(3, 50) DIN_0388:set(1, 0) DIN_0388:set(2, 500) DIN_0388:set(3, 50) DOUT_2485:set(0, 0) -- czy dane wejście jest włączone czy wyłączone DOUT_6848:set(0, 0) DOUT_8565:set(0, 0) DOUT_4705:set(0, 0) DOUT_6710:set(0, 0) DOUT_3423:set(0, 0) DOUT_4513:set(0, 0) DOUT_4114:set(0, 0) AnalogOUT_0042:set(0, 0) -- analog in ma sporo parametrów: AnalogOUT_0042:set(1, 0) -- Value, Value%, Scale, AnalogOUT_0042:set(2, 1) AnalogOUT_0042:set(3, 500) -- tego 500 nie ma w konfiguracji AnalogIn w OM. Możliwe, że jest to jakiś interwał. Np 500ms. AnalogOUT_0042:set(4, 0) AnalogOUT_0042:set(5, 10) AnalogOUT_4654:set(0, 0) AnalogOUT_4654:set(1, 0) AnalogOUT_4654:set(2, 1) AnalogOUT_4654:set(3, 500) AnalogOUT_4654:set(4, 0) AnalogOUT_4654:set(5, 10) AnalogOUT_2371:set(0, 0) AnalogOUT_2371:set(1, 0) AnalogOUT_2371:set(2, 1) AnalogOUT_2371:set(3, 500) AnalogOUT_2371:set(4, 0) AnalogOUT_2371:set(5, 10) AnalogOUT_0007:set(0, 0) AnalogOUT_0007:set(1, 0) AnalogOUT_0007:set(2, 1) AnalogOUT_0007:set(3, 500) AnalogOUT_0007:set(4, 0) AnalogOUT_0007:set(5, 10) AnalogIN_3611:set(2, 1) AnalogIN_3611:set(3, 0) AnalogIN_3611:set(4, 0) AnalogIN_3611:set(5, 0) AnalogIN_3611:set(6, 10) AnalogIN_6008:set(2, 1) AnalogIN_6008:set(3, 0) AnalogIN_6008:set(4, 0) AnalogIN_6008:set(5, 0) AnalogIN_6008:set(6, 10) AnalogIN_7445:set(2, 1) AnalogIN_7445:set(3, 0) AnalogIN_7445:set(4, 0) AnalogIN_7445:set(5, 0) AnalogIN_7445:set(6, 10) AnalogIN_4221:set(2, 1) AnalogIN_4221:set(3, 0) AnalogIN_4221:set(4, 0) AnalogIN_4221:set(5, 0) AnalogIN_4221:set(6, 10) ONEW_SENSOR_7372:set(1, 0.5) -- Czujniki temperatury wpięte w 1-wire. 0.5 to Treshold ONEW_SENSOR_7372:set(2, 0) -- minValue ONEW_SENSOR_7372:set(3, 100) -- maxValue ONEW_SENSOR_6304:set(1, 0.5) ONEW_SENSOR_6304:set(2, 0) ONEW_SENSOR_6304:set(3, 100) end
Ostatnią sekcją jest przypisanie zdarzenia OnInit do CLU.
CLU_0d1cf150:add_event(0, OnInit)
Podsumowanie:
- Konfigurację zaszytą w plikach dość łatwo zrozumieć.
- Klasa OBJECT i metoda new mają bardzo dużo odpowiedzialności. Sterowane numerkami może powodować ból głowy.
- Komentarze NAME_IO mogą się przydać przy pisaniu alternatywnego klienta.
Pozdrawiam,
T