Berry to lekki język skryptowy przeznaczony dla systemów wbudowanych. Posiada dynamicznie typowany, jednoprzebiegowy kompilator i interpreter o rozmiarze głównej implementacji mniejszym niż 40 KiB, który może działać na stercie mniejszej niż 4 KiB. Dzięki najnowszej integracji z OBK , Berry może teraz działać na większości nowych modułów IoT, w tym BK7231, W800/W600, ESP32, BL602, LN882, Realtek. Może również działać w symulatorze OBK Windows, dzięki czemu można łatwo wypróbować Berry, wraz z pełną integracją MQTT i Home Assistant.
Więcej informacji na temat Berry można znaleźć w dokumentacji Berry:
https://berry.readthedocs.io/en/latest/index.html
Skupmy się teraz na uruchomieniu Berry w OBK. Obecnie dostępne są dwie opcje:
Opcja 1 : możesz po prostu użyć OpenBeken Simulator aby wypróbować Berry na Windows, wystarczy pobrać binaria tutaj: https://github.com/openshwprojects/OpenBK7231T_App/releases
Opcja 2 : Możesz użyć kompilacji online (nie jest wymagany toolchain), aby włączyć Berry dla wybranej platformy, postępuj zgodnie z tym samouczkiem . Należy pamiętać, że na niektórych platformach może być konieczne wyłączenie niektórych innych funkcji, aby zachować wystarczająco mały rozmiar pliku binarnego do uruchomienia. Wynika to z faktu, że OBK jest domyślnie dostarczany z większością włączonych funkcji, więc każdy plik binarny ma sterownik TuyaMCU, sterownik LED, sterownik WS2812 z animacjami, a nawet obsługę Tasmota JSON, a najprawdopodobniej nie będziesz tego robić. Więc edytuj obk_config.h do swoich potrzeb. Pamiętaj tylko - dla Berry musisz włączyć definicję ENABLE_OBK_BERRY.
Co więcej, rozmiary stosów mogą nie być obecnie dostosowane do Berry, więc może być konieczne ich zwiększenie we własnym zakresie. Nadal istnieje również miejsce na optymalizację kodu Berry, na przykład niektóre programy obsługi zdarzeń mogą być mniej lub bardziej opóźnione, aby uniknąć dużego zapotrzebowania na stos. Może to ulec zmianie w przyszłości.
Ten samouczek będzie oparty na OBK Windows Simulator, więc każdy może go uruchomić, nawet bez urządzeń IoT.
Nie zapomnij pobrać próbek symulatora OBK tutaj:
https://github.com/openshwprojects/obkSimulator
Zostaną one wykorzystane tutaj do celów demonstracyjnych.
Zakładam również, że wiesz mniej więcej jak uruchomić OBK Simulator - tworzy on okno symulacji i stronę wirtualnego urządzenia na lokalnym IP, port 80. Aby uzyskać więcej informacji, zobacz powiązany temat Symulator.
Pierwsze kroki Berry
Zacznijmy od wykonania kilku prostych poleceń Berry w linii poleceń OBK:
berry print("Hello, Berry")
To samo można zrobić w konsoli Web App:
W ten sposób można przetestować różne polecenia berry, na przykład wyrażenia:
berry print("Hello " + str(5+2*2))
Pierwsze polecenia Berry
Najprostszym sposobem na wywołanie komend OBK z Berry jest polecenie "runCmd".
Polecenia powinny być pobierane stąd:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/commands.md
Na przykład wywołujesz setChannel z Berry, aby ustawić nową wartość kanału. W OBK może to na przykład ustawić stan przekaźnika, wraz z całą publikacją MQTT i aktualizacją stanu:
berry runCmd("setChannel 1 1")
Możesz użyć tego samego podejścia do uruchamiania poleceń tekstowych:
berry runCmd("MQTTHost 192.168.0.213")
Podobnie można użyć poleceń publikowania OBK, aby opublikować dane w Home Assistant:
Pliki skryptów Berry
Główne skrypty Berry powinny znajdować się w modułach Berry. Moduły Berry mogą być tworzone w systemie plików LittleFS:
Zacznijmy od stworzenia najprostszego modułu. Nazwijmy go autoexec.be. Będzie on uruchamiany przy każdym starcie urządzenia.
autoexec = module('autoexec')
# Add functions to the module
autoexec.myInit = def()
setChannel(1, 42)
end
# Call function on first load
autoexec.myInit()
# Berry modules must return the module object
return autoexec
Aby przyspieszyć prototypowanie, można użyć przycisku "Zapisz, zresetuj SVM i uruchom plik". Spowoduje to również próbę wyczyszczenia stanu urządzenia w celu symulacji ponownego uruchomienia, ale może nie zawsze być niezawodne.
Wykonanie skryptu w czasie
OBK zawiera dwa polecenia, które pozwalają na uruchamianie skryptów w czasie:
- setTimeout - uruchamia polecenia raz
- setInterval - uruchamia komendę wielokrotnie
Za pomocą setInterval można zrobić proste demo "migającej diody LED" (lub przekaźnika, lub czegokolwiek):
autoexec = module('autoexec')
autoexec.myToggle= def()
runCmd("toggleChannel 1")
end
setInterval(autoexec.myToggle, 500)
return autoexec
To samo można zrobić z setTimeout, jeśli zajdzie taka potrzeba:
autoexec = module('autoexec')
autoexec.myToggle= def()
runCmd("toggleChannel 1")
setTimeout(autoexec.myToggle, 500)
end
autoexec.myToggle()
return autoexec
Reagowanie na zdarzenia - przyciski
Berry może reagować na zdarzenia OpenBeken. Na przykład, można go użyć z przyciskiem Btn_ScriptOnly. Ustaw rolę Btn_ScriptOnly dla danego pinu, powiedzmy 14, i wypróbuj następujący kod:
autoexec = module('autoexec')
autoexec.myToggle= def()
runCmd("toggleChannel 1")
runCmd("toggleChannel 2")
end
addEventHandler("OnClick", 8, autoexec.myToggle);
return autoexec
Dla celów demonstracyjnych umieściłem dwa przekaźniki ("żarówki") na kanale 1 i kanale 2:
Reagowanie na zdarzenia - kanały
Podobne podejście można zastosować, aby na przykład wyłączyć przekaźnik po pewnym czasie. W tym przypadku wychwycimy sytuację, w której kanał staje się 1 i po pewnym czasie ustawimy go z powrotem na 0. Należy pamiętać, że w tym demo ustawiłem z powrotem rolę przycisku pin PWM2 na Btn, więc ma on automatyczną interakcję z kanałem 1. Tak więc przełączanie kanału 1 jest obsługiwane wewnętrznie przez OBK, jak zwykle.
autoexec = module('autoexec')
autoexec.myToggle= def()
runCmd("setChannel 1 0")
end
autoexec.myDelay= def()
setTimeout(autoexec.myToggle, 1000)
end
addEventHandler("Channel1", 1, autoexec.myDelay);
return autoexec
Kod można uprościć dodając funkcje inline:
autoexec = module('autoexec')
autoexec.myToggle= def()
runCmd("setChannel 1 0")
end
addEventHandler("Channel1", 1, def()
setTimeout(autoexec.myToggle, 1000)
end);
return autoexec
i jeszcze dalej:
autoexec = module('autoexec')
addEventHandler("Channel1", 1, def()
setTimeout(def()
runCmd("setChannel 1 0")
end, 1000)
end);
return autoexec
Zatrzymywanie i uruchamianie interwałów
setInterval zwraca uchwyt, który może być później użyty do zatrzymania interwału. Można go przechowywać w zmiennej globalnej i później wywołać "cancel". Poniższy przykład demonstruje zatrzymywalne demo setInterval, w którym pierwsze naciśnięcie przycisku uruchamia interwał, który miga diodami LED, a drugie naciśnięcie przycisku zatrzymuje go.
autoexec = module('autoexec')
g_handle = 0;
autoexec.myToggle= def()
if g_handle == 0
g_handle = setInterval(def()
runCmd("toggleChannel 1")
runCmd("toggleChannel 2")
end, 200 )
else
cancel(g_handle)
g_handle = 0
end
end
addEventHandler("OnClick", 8, autoexec.myToggle);
return autoexec
Wywoływanie funkcji modułów z zewnątrz
Pamiętaj, że możesz po prostu użyć modułów Berry w dowolnym miejscu wewnątrz OBK. Rozważmy uproszczoną wersję wspomnianego modułu:
autoexec = module('autoexec')
g_handle = 0;
autoexec.myToggle= def()
if g_handle == 0
g_handle = setInterval(def()
runCmd("toggleChannel 1")
runCmd("toggleChannel 2")
end, 200 )
else
cancel(g_handle)
g_handle = 0
end
end
return autoexec
Gdy już masz go w LFS, możesz po prostu uruchomić polecenie OBK:
berry import autoexec; autoexec.myToggle()
i poprawnie przełączy interwał mrugania.
Bezpośrednia obsługa komend
Istnieje więcej sposobów wywoływania funkcji Berry z zewnątrz. Na przykład można po prostu utworzyć własną obsługę poleceń w Berry:
autoexec = module('autoexec')
g_handle = 0;
autoexec.myToggle= def()
if g_handle == 0
g_handle = setInterval(def()
runCmd("toggleChannel 0")
runCmd("toggleChannel 1")
runCmd("toggleChannel 2")
end, 200 )
else
cancel(g_handle)
g_handle = 0
end
end
addEventHandler("OnCmd", "MyCmd", autoexec.myToggle)
return autoexec
Pamiętaj, że teraz możesz uruchomić to polecenie z dowolnego miejsca - nawet z MQTT!
Bezpośrednie argumenty polecenia
Polecenia mogą mieć argumenty, które są również przekazywane do Berry. Argumenty są domyślnie ciągami znaków, więc aby użyć ich jako liczby, należy rzutować je na int. W tym przykładzie zmodyfikujemy komendę mrugania, aby zawierała pojedynczy argument, którym jest interwał mrugania. Aby przekonwertować go na ciąg znaków, użyłem funkcji int(del).
autoexec = module('autoexec')
g_handle = 0;
autoexec.myToggle= def(del)
if g_handle == 0
g_handle = setInterval(def()
runCmd("toggleChannel 0")
runCmd("toggleChannel 1")
runCmd("toggleChannel 2")
end, int(del))
else
cancel(g_handle)
g_handle = 0
end
end
addEventHandler("OnCmd", "MyCmd", autoexec.myToggle)
return autoexec
Użycie jest bardzo proste:
Oczywiście w razie wątpliwości można po prostu wydrukować informacje debugowania:
Pokazuje informacje o sekcji stanu
OpenBeken posiada stronę główną z sekcją stanu, która jest automatycznie odświeżana w tle.
autoexec = module('autoexec')
g_handle = 0;
autoexec.myToggle= def(del)
if g_handle == 0
print("Will runinterval with del "+str(del));
g_handle = setInterval(def()
runCmd("toggleChannel 0")
runCmd("toggleChannel 1")
runCmd("toggleChannel 2")
end, int(del))
else
print("Will stop interval")
cancel(g_handle)
g_handle = 0
end
end
autoexec.myShow= def(request)
poststr(request, "<h1>Hello Berry!</h1>")
poststr(request, "<h5>Interval ID is " + str(g_handle)+"</h1>")
end
addEventHandler("OnHTTP", "state", autoexec.myShow)
addEventHandler("OnCmd", "MyCmd", autoexec.myToggle)
return autoexec
Identyfikator interwału będzie wynosił 0, gdy będzie nieaktywny.
Dostęp do zmiennych OBK - pomiar mocy
OpenBeken ma kilka starszych zmiennych, które były używane przed wprowadzeniem Berry. Można je zobaczyć tutaj:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/constants.md
W Berry można uzyskać do nich dostęp za pomocą funkcji getVar.
Oto proste demo odczytu BL0942/BL0937:
autoexec = module('autoexec')
autoexec.myShow= def(request)
v = getVar("$voltage");
poststr(request, "<h3>Berry voltage " + str(v)+"</h3>")
c = getVar("$current");
poststr(request, "<h3>Berry current " + str(c)+"</h3>")
p = getVar("$power");
poststr(request, "<h3>Berry power " + str(p)+"</h3>")
end
addEventHandler("OnHTTP", "state", autoexec.myShow)
return autoexec
Wartości są poprawnie wyświetlane na stronie głównej:
Poniższy przykład można rozszerzyć o instrukcje warunkowe. Można użyć bloku if do sprawdzenia wartości napięcia.
autoexec = module('autoexec')
autoexec.myShow= def(request)
v = getVar("$voltage");
poststr(request, "<h3>Berry voltage " + str(v)+"</h3>")
if v > 245
poststr(request, "<h3 style='color:red'>OVERVOLTAGE ALARM</h3>")
elif v < 210
poststr(request, "<h3 style='color:red'>UNDERVOLTAGE ALARM</h3>");
end
c = getVar("$current");
poststr(request, "<h3>Berry current " + str(c)+"</h3>")
p = getVar("$power");
poststr(request, "<h3>Berry power " + str(p)+"</h3>")
end
addEventHandler("OnHTTP", "state", autoexec.myShow)
return autoexec
Teraz ustawmy napięcie na 260 i zobaczmy co się stanie:
Komunikat o błędzie jest wyświetlany poprawnie:
Extra sample - refresh counter
Poniższy skrypt zlicza liczbę automatycznych odświeżeń wykonanych przez segment strony stanu OBK:
autoexec = module("autoexec")
cnt = 0;
addEventHandler("OnHTTP", "state", def(request)
poststr(request, "<h3>Refresh counter " + str(cnt) + "</h3>")
cnt = cnt + 1
end)
return autoexec
Dodatkowa próbka - logika pętli i sprawdzanie zasilania
Poniższa próbka była wielokrotnie zgłaszana przez użytkowników. Jest to prosty mechanizm służący do wyłączania przekaźnika, gdy zużycie energii jest poniżej określonego progu przez określony czas. Można to wykorzystać do wykrywania zakończenia ładowania.
Aby to zaimplementować, stworzyłem prosty powtarzający się interwał o nazwie "my Logic", w którym uzyskuję dostęp do bieżącej wartości mocy i porównuję ją z wcześniej zdefiniowanym progiem, w tym przypadku 1W. Jeśli jest poniżej 1W, liczę liczbę pętli, a jeśli osiągnie 5 (5 sekund, ponieważ jedna pętla to jedna sekunda), wyłączam przekaźnik.
autoexec = module("autoexec")
loopsLowPower = 0;
def myLogic()
p = getVar("$power");
print("power is " +str(p));
if p < 1
loopsLowPower += 1
if loopsLowPower > 5
runCmd("POWER OFF");
end
else
loopsLowPower = 0;
end
end
setInterval(myLogic, 1000);
return autoexec
Poniższy przykład można rozszerzyć np. przenosząc stałe do pól tekstowych:
autoexec = module("autoexec")
loopsLowPower = 0;
def myLogic()
p = getVar("$power");
print("power is " +str(p));
minPower = getChannel(5);
if p < 1
loopsLowPower += 1
if loopsLowPower > 5
runCmd("POWER OFF");
end
else
loopsLowPower = 0;
end
end
runCmd("setChannelType 5 TextField")
runCmd("setChannelLabel 5 MinPower");
setInterval(myLogic, 1000);
return autoexec
Wynik:
Dostęp do zmiennych OBK - zmienne czasowe
Najpierw uruchom sterownik NTP. Po jego uruchomieniu będziesz mógł uzyskać dostęp do danych bieżącego czasu:
Wypróbuj następujący skrypt:
autoexec = module('autoexec')
autoexec.myShow= def(request)
h = getVar("$hour");
m = getVar("$minute");
poststr(request, "<h1>" + str(h)+":" + str(m)+"</h1>")
end
addEventHandler("OnHTTP", "state", autoexec.myShow)
return autoexec
Spowoduje to wyświetlenie godziny/minuty NTP na panelu głównym:
Niestandardowe pola HTML
Wywołanie zwrotne HTTP umożliwia również tworzenie niestandardowych pól HTML. Mogą one przechowywać dowolny rodzaj danych, które są później przetwarzane przez Berry. Możesz również użyć getVar, aby uzyskać dostęp do zmiennych GET. Pole wejściowe może być jednak trudne. Wynika to z faktu, że sekcja stanu jest odświeżana automatycznie, więc można stracić wpisane dane. Dlatego też istnieje inny callback - zwany "prestate", który działa przed state div. Tak więc pole jest tworzone w prestate i wyświetlane w state.
autoexec = module('autoexec')
name = "Unknown";
autoexec.myPre= def(request)
other = getVar("name");
if other != nil
name = other;
end
poststr(request, "<form method='GET'>Name: <input name='name'><input type='submit'></form>")
end
autoexec.myState= def(request)
poststr(request, "<h1> Hello, " + name+"!</h1>")
end
addEventHandler("OnHTTP", "prestate", autoexec.myPre)
addEventHandler("OnHTTP", "state", autoexec.myState)
return autoexec
Powiązane lektury
Aby uzyskać więcej informacji na temat zdarzeń OBK (obsługa przycisków itp.), zdarzeń zegara (NTP itp.), zobacz próbki autoexec.bat. Nie są one w Berry, ale nadal mogą dać pewien wgląd w możliwości OBK:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/autoexecExamples.md
To na razie wszystko .
W ten sposób można tworzyć bardziej zaawansowane skrypty w OBK. Daj mi znać, jeśli masz jakieś dalsze sugestie lub pomysły.
Wkrótce opublikuję część 2 samouczka, która obejmie bardziej zaawansowane rzeczy HTTP, integrację TuyaMCU i przetwarzanie danych.
Należy pamiętać, że integracja Berry była do tej pory testowana głównie za pomocą autotestów ( https://www.elektroda.com/rtvforum/topic4109775.html ) i w symulatorze, więc wszelkie testy są mile widziane. Daj mi znać, jeśli spróbujesz uruchomić niektóre z moich skryptów na fizycznych urządzeniach! Jacyś testerzy są dostępni - może @divadiow? Specjalne podziękowania dla @niterian za wstępne demo Berry.
Fajne? Ranking DIY Pomogłem? Kup mi kawę.