Zapraszam na analizę, inżynierię wsteczną i flashowanie ciekawej lampy Tuya, opierającej się o indywidualnie adresowalne LEDy potrafiące odtwarzać różnego rodzaju animacje, takie jak "wodospad", "ogień", itd. Celem tematu będzie uwolnienie tej lampy od chmury i zastąpienie oryginalnego oprogramowania naszym wciąż rozwijanym odpowiednikiem open source, który może działać 100% lokalnie i anonimowo.
Temat realizowałem wraz z kolegą z Serbii - @DeDaMrAz . Lampę zakupił kolega i on na niej operował, ja zająłem się stroną firmware.
Zakup urządzenia
Lampę zamówiliśmy na prośbę jednego użytkownika, który potrzebował pomocy z uwolnieniem jej od chmury, ale wyszukać ją można pod hasłem Smart Wall Light taya APP RGB Outdoor Porch Colored light Party intelligent remote control Decoration Lighting holiday Wall Lamp. Do wyboru jest wiele jej wersji, im dłuższy pasek, tym większa cena:
Za wybraną wersję zapłaciliśmy €49.02.
Budowa tej lampy jest dość specyficzna, pasek zamontowany jest wokół niej. Lepiej to przedstawia filmik od producenta:
Lampa ta jest sterowana przez WiFi (aplikacja Tuya) oraz przez pilota, w wersji którą zakupiliśmy jest to pilot RF.
Plan działania
Naszym celem jest uwolnienie omawianego urządzenia od chmury, a na to składają się poszczególne zadania:
- najpierw musimy zbadać jak te urządzenie jest zbudowane
- w tym przypadku musimy też przechwycić jego pakiety komunikacji TuyaMCU, gdyż tutaj te urządzenie składa się z osobno modułu WiFi (któremu zmienimy firmware) od komunikacji ze światem zewnętrznym oraz z MCU od kontroli adresowalnych LEDów i odbierania kodów IR z pilota
- musimy przeanalizować przechwycone pakiety tak aby wiedzieć jak które dpID (identyfikatory zmiennych TuyaMCU) za co odpowiadają, mamy do tego własne narzędzie
- następnie musimy na moduł WiFi wgrać OpenBeken poprzez nasz flasher
- potem musimy oskryptować OBK tak, aby emulować pakiety wysyłane przez TuyaMCU przez oryginalny soft Tuya oraz nadać temu jakiś sensowny interfejs użytkownika na panelu OBK
Tutaj warto polecić powiązane tematy, które wyjaśnią niektóre z używanych przeze mnie pojęć:
- Protokół TuyaMCU - komunikacja pomiędzy mikrokontrolerem a modułem WiFi
- Analizator TuyaMCU - dekoder pakietów UART dla urządzeń Tuya - dpID detektor
Pierwsze wrażenie
Urządzenie składa się osobno z frontu z LEDami, z zasilacza i z modułu kontrolera:
Do środka trzeba dostać się za pomocą odrobiny siły:
W opasce termokurczliwej kryje się główne PCB:
LEDy są na 12V, nie jest to WS2812B, lecz SM16703:
Po podłączeniu urządzenie mruga w trybie parowania:
Bez problemu można połączyć z aplikacją Tuya:
UWAGA: parowanie uruchamiamy poprzez wciśnięcie przycisku MUSIC na pilocie.
Po połączeniu urządzenia z Tuya wykonaliśmy przechwytywanie pakietów UART i jednocześnie notowaliśmy jaka operacja jest wtedy wykonywana. Czyli kolejno, np. włączamy przechwytywanie, włączamy lampkę, zapisujemy wyniki. Potem włączamy przechwytywanie, zmieniamy jasność, zapisujemy wyniki. I tak z każdą operacją.
Przechwycone pakiety komunikacji z TuyaMCU
Oto zebrane pakiety, można je łatwo przeanalizować we wspomnianym analizatorze:
https://www.elektroda.pl/rtvforum/topic3970199.html
https://github.com/openshwprojects/TuyaMCUAnalyzer
Reboot po parowaniu:
//S 09/03/23 20:46:41 WiFi sent:
55AA00000000FF
//R 09/03/23 20:46:42 WiFi received:
55AA030000010104
//R 09/03/23 20:46:44 WiFi received:
55AA030000010104
//S 09/03/23 20:46:44 WiFi sent:
55AA00000000FF
//S 09/03/23 20:46:58 WiFi sent:
55AA00000000FF
//R 09/03/23 20:46:58 WiFi received:
55AA030000010104
//S 09/03/23 20:46:59 WiFi sent:
55AA0001000000
//R 09/03/23 20:46:59 WiFi received:
55AA0301002A7B2270223A2263756F666E346863726F616D746E6833222C2276223A22312E302E30222C226D223A307D35
//S 09/03/23 20:47:00 WiFi sent:
55AA0002000001
//R 09/03/23 20:47:00 WiFi received:
55AA0302000004
//S 09/03/23 20:47:01 WiFi sent:
55AA0008000007
//R 09/03/23 20:47:01 WiFi received:
55AA03070005140100010125
//R 09/03/23 20:47:02 WiFi received:
55AA03070005150400010129
//R 09/03/23 20:47:02 WiFi received:
55AA030700081A02000400001F4090
//R 09/03/23 20:47:02 WiFi received:
55AA030700093300000500000101F440
//R 09/03/23 20:47:02 WiFi received:
55AA030700093400000500000101F441
//R 09/03/23 20:47:02 WiFi received:
55AA03070008350200040000012C79
//S 09/03/23 20:47:02 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:03 WiFi received:
55AA030000010104
//S 09/03/23 20:47:03 WiFi sent:
55AA000300010407
//R 09/03/23 20:47:04 WiFi received:
55AA0303000005
//S 09/03/23 20:47:06 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:07 WiFi received:
55AA030000010104
//S 09/03/23 20:47:10 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:11 WiFi received:
55AA030000010104
//S 09/03/23 20:47:14 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:15 WiFi received:
55AA030000010104
//S 09/03/23 20:47:18 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:19 WiFi received:
55AA030000010104
//S 09/03/23 20:47:22 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:23 WiFi received:
55AA030000010104
//S 09/03/23 20:47:26 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:27 WiFi received:
55AA030000010104
//S 09/03/23 20:47:30 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:31 WiFi received:
55AA030000010104
//S 09/03/23 20:47:34 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:35 WiFi received:
55AA030000010104
//S 09/03/23 20:47:38 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:39 WiFi received:
55AA030000010104
//S 09/03/23 20:47:42 WiFi sent:
55AA00000000FF
//R 09/03/23 20:47:43 WiFi received:
55AA030000010104
Tutaj zasadniczo mamy pierwsze "zapoznanie się" modułów, zgłoszenie wersji urządzenia, stanu WiFi, itd. Dodatkowo przesłane są też początkowe wartości zmiennych, ale na razie ciężko odgadnąć co oznaczają, tym zajmiemy się za chwilę:
Niebieski kolor LED:
//S 09/03/23 19:13:29 WiFi sent:
55AA000600191C030015313030643330336330303365383030303030303030F0
//S 09/03/23 19:13:29 WiFi sent:
55AA00060005150400010125
//R 09/03/23 19:13:29 WiFi received:
55AA030700191C030015313030643330336330303365383030303030303030F4
//S 09/03/23 19:13:29 WiFi sent:
55AA000600101803000C30306433303363303033653829
//R 09/03/23 19:13:29 WiFi received:
55AA03070005150400010129
//R 09/03/23 19:13:29 WiFi received:
55AA030700101803000C3030643330336330303365382D
Analizator już pokazuje, że dpID 24 odpowiada za kolor, choć to jest typ string. Wiele urządzeń Tuya ma kolor tak zakodowany i też właśnie w dpID 24:
Dodatkowo analizator poprawnie odczytuje kolor i pokazuje go w formie kolorowego kwadracika.
Zmiana jasności animacji chase:
//R 09/03/23 21:52:04 WiFi received:55AA0307000515040001022A//R 09/03/23 21:52:04 WiFi received:55AA030700201903001C3032306430643030303031343033653830336538303030303030303090//R 09/03/23 21:52:07 WiFi received:55AA030000010104//R 09/03/23 21:52:08 WiFi received:55AA0307000515040001022A//R 09/03/23 21:52:08 WiFi received:55AA030700201903001C3032306430643030303031343033653830303061303030303030303081
100-0
//R 09/03/23 21:52:33 WiFi received:55AA0307000515040001022A//R 09/03/23 21:52:34 WiFi received:55AA030700201903001C3032306430643030303031343033653830303061303030303030303081//R 09/03/23 21:52:37 WiFi received:55AA030000010104//R 09/03/23 21:52:38 WiFi received:55AA0307000515040001022A//R 09/03/23 21:52:39 WiFi received:55AA030700201903001C30323064306430303030313430336538303063633030303030303030B6
0-20
//R 09/03/23 21:53:15 WiFi received:55AA0307000515040001022A//R 09/03/23 21:53:15 WiFi received:55AA030700201903001C3032306430643030303031343033653830306333303030303030303086//R 09/03/23 21:53:19 WiFi received:55AA0307000515040001022A//R 09/03/23 21:53:19 WiFi received:55AA030700201903001C303230643064303030303134303365383031386630303030303030308F//R 09/03/23 21:53:22 WiFi received:55AA030000010104
20-40
//R 09/03/23 21:53:44 WiFi received:55AA0307000515040001022A//R 09/03/23 21:53:44 WiFi received:55AA030700201903001C303230643064303030303134303365383031386630303030303030308F//R 09/03/23 21:53:49 WiFi received:55AA0307000515040001022A//R 09/03/23 21:53:49 WiFi received:55AA030700201903001C303230643064303030303134303365383032356430303030303030308B//R 09/03/23 21:53:52 WiFi received:55AA030000010104
40-60
//R 09/03/23 21:54:06 WiFi received:55AA0307000515040001022A//R 09/03/23 21:54:06 WiFi received:55AA030700201903001C303230643064303030303134303365383032356430303030303030308B//R 09/03/23 21:54:07 WiFi received:55AA030000010104//R 09/03/23 21:54:10 WiFi received:55AA0307000515040001022A//R 09/03/23 21:54:10 WiFi received:55AA030700201903001C3032306430643030303031343033653830333231303030303030303056
60-80
//R 09/03/23 21:54:28 WiFi received:55AA0307000515040001022A//R 09/03/23 21:54:28 WiFi received:55AA030700201903001C3032306430643030303031343033653830333231303030303030303056//R 09/03/23 21:54:31 WiFi received:55AA0307000515040001022A//R 09/03/23 21:54:31 WiFi received:55AA030700201903001C3032306430643030303031343033653830336538303030303030303090
80-100
Tu widzimy, że o dziwo nie ma osobnego dpID odpowiedzialnego za jasność, jest to zakodowane w kolorze... ten dpID 21 tutaj to tryb pracy.
Czyli dpID 25 to jest animacja opisana jako string, jego długość może być różna. Wcześniej widzieliśmy, że zwykły kolor to dpID 24
Animacja chase:
//R 09/03/23 18:29:16 WiFi received:
55AA0307000515040001022A
//S 09/03/23 18:29:16 WiFi sent:
55AA00060005150400010226
//S 09/03/23 18:29:16 WiFi sent:
55AA000600201903001C303230653064303030303134303365383033653830303030303030308D
//R 09/03/23 18:29:16 WiFi received:
55AA030700201903001C3032306530643030303031343033653830336538303030303030303091
//S 09/03/23 18:29:17 WiFi sent:
55AA00000000FF
//R 09/03/23 18:29:18 WiFi received:
55AA030000010104
Tu znowu widać, że ustawiany jest tryb pracy (dpID 21) oraz w dpID 25 przesyłana jest animacja:
Animacja collision:
//S 09/03/23 18:33:07 WiFi sent:
55AA00060005150400010226
//R 09/03/23 18:33:07 WiFi received:
55AA0307000515040001022A
//S 09/03/23 18:33:07 WiFi sent:
55AA000600A21903009E303734363436303230303030303365383033653830303030303030303436343630323030373830336538303365383030303030303030343634363032303066303033653830336538303030303030303034363436303230303364303365383033653830303030303030303436343630323030616530336538303365383030303030303030343634363032303131333033653830336538303030303030303073
//R 09/03/23 18:33:07 WiFi received:
55AA030700A21903009E303734363436303230303030303365383033653830303030303030303436343630323030373830336538303365383030303030303030343634363032303066303033653830336538303030303030303034363436303230303364303365383033653830303030303030303436343630323030616530336538303365383030303030303030343634363032303131333033653830336538303030303030303077
Zasadniczo jak wyżej, już bez komentarza, animacje wszystkie idą przez dpID 25.
Animacja draw curtain:
//S 09/03/23 18:28:42 WiFi sent:
55AA00060005150400010226
//R 09/03/23 18:28:42 WiFi received:
55AA0307000515040001022A
//S 09/03/23 18:28:42 WiFi sent:
55AA000600201903001C30303065306430303030326530336538303263633030303030303030E5
//R 09/03/23 18:28:42 WiFi received:
55AA030700201903001C30303065306430303030326530336538303263633030303030303030E9
//S 09/03/23 18:28:47 WiFi sent:
55AA00000000FF
//R 09/03/23 18:28:47 WiFi received:
55AA030000010104
Zmiana jasności animacji fireworks:
//R 09/03/23 22:04:53 WiFi received:
55AA030000010104
//R 09/03/23 22:04:56 WiFi received:
55AA0307000515040001022A
//R 09/03/23 22:04:56 WiFi received:
55AA030700A21903009E30353436343630313030303030336538303365383030303030303030343634363031303037383033653830336538303030303030303034363436303130306630303365383033653830303030303030303436343630313030336430336538303365383030303030303030343634363031303061653033653830336538303030303030303034363436303130313133303365383033653830303030303030306F
//R 09/03/23 22:05:02 WiFi received:
55AA0307000515040001022A
//R 09/03/23 22:05:02 WiFi received:
55AA030700A21903009E303534363436303130303030303365383030306130303030303030303436343630313030373830336538303030613030303030303030343634363031303066303033653830303061303030303030303034363436303130303364303365383030306130303030303030303436343630313030616530336538303030613030303030303030343634363031303131333033653830303061303030303030303015
//R 09/03/23 22:05:08 WiFi received:
55AA030000010104
//R 09/03/23 22:05:09 WiFi received:
55AA0307000515040001022A
//R 09/03/23 22:05:09 WiFi received:
55AA030700A21903009E303534363436303130303030303365383031323930303030303030303436343630313030373830336538303132393030303030303030343634363031303066303033653830313239303030303030303034363436303130303364303365383031323930303030303030303436343630313030616530336538303132393030303030303030343634363031303131333033653830313239303030303030303037
//R 09/03/23 22:05:13 WiFi received:
55AA0307000515040001022A
//R 09/03/23 22:05:13 WiFi received:
55AA030700A21903009E303534363436303130303030303365383032353730303030303030303436343630313030373830336538303235373030303030303030343634363031303066303033653830323537303030303030303034363436303130303364303365383032353730303030303030303436343630313030616530336538303235373030303030303030343634363031303131333033653830323537303030303030303043
//R 09/03/23 22:05:16 WiFi received:
55AA0307000515040001022A
//R 09/03/23 22:05:16 WiFi received:
55AA030700A21903009E303534363436303130303030303365383033316530303030303030303436343630313030373830336538303331653030303030303030343634363031303066303033653830333165303030303030303034363436303130303364303365383033316530303030303030303436343630313030616530336538303331653030303030303030343634363031303131333033653830333165303030303030303045
//R 09/03/23 22:05:18 WiFi received:
55AA0307000515040001022A
//R 09/03/23 22:05:18 WiFi received:
55AA030700A21903009E30353436343630313030303030336538303365383030303030303030343634363031303037383033653830336538303030303030303034363436303130306630303365383033653830303030303030303436343630313030336430336538303365383030303030303030343634363031303061653033653830336538303030303030303034363436303130313133303365383033653830303030303030306F
//R 09/03/23 22:05:23 WiFi received:
55AA030000010104
fireworks scene 100-0-30-60-85-100
Animacja fireworks:
//S 09/03/23 18:32:41 WiFi sent:
55AA00060005150400010226
//R 09/03/23 18:32:41 WiFi received:
55AA0307000515040001022A
//S 09/03/23 18:32:41 WiFi sent:
55AA000600A21903009E30353436343630313030303030336538303365383030303030303030343634363031303037383033653830336538303030303030303034363436303130306630303365383033653830303030303030303436343630313030336430336538303365383030303030303030343634363031303061653033653830336538303030303030303034363436303130313133303365383033653830303030303030306B
//R 09/03/23 18:32:41 WiFi received:
55AA030700A21903009E30353436343630313030303030336538303365383030303030303030343634363031303037383033653830336538303030303030303034363436303130306630303365383033653830303030303030303436343630313030336430336538303365383030303030303030343634363031303061653033653830336538303030303030303034363436303130313133303365383033653830303030303030306F
Ustawienie koloru zielonego:
//S 09/03/23 19:13:02 WiFi sent:
55AA000600191C030015313030366430333932303365383030303030303030CB
//R 09/03/23 19:13:02 WiFi received:
55AA030700191C030015313030366430333932303365383030303030303030CF
//S 09/03/23 19:13:02 WiFi sent:
55AA00060005150400010125
//S 09/03/23 19:13:02 WiFi sent:
55AA000600101803000C30303664303339323033653804
//R 09/03/23 19:13:02 WiFi received:
55AA03070005150400010129
//R 09/03/23 19:13:02 WiFi received:
55AA030700101803000C30303664303339323033653808
//S 09/03/23 19:13:03 WiFi sent:
55AA00000000FF
//R 09/03/23 19:13:03 WiFi received:
55AA030000010104
Animacja pile up:
//S 09/03/23 18:32:02 WiFi sent:
55AA00000000FF
//R 09/03/23 18:32:03 WiFi received:
55AA030000010104
//S 09/03/23 18:32:03 WiFi sent:
55AA00060005150400010226
//S 09/03/23 18:32:03 WiFi sent:
55AA000600201903001C3031306530643030303038343030303030336538303030303030303053
//R 09/03/23 18:32:03 WiFi received:
55AA0307000515040001022A
//R 09/03/23 18:32:03 WiFi received:
55AA030700201903001C3031306530643030303038343030303030336538303030303030303057
Animacja rainbow:
//R 09/03/23 18:30:20 WiFi received:
55AA0307000515040001022A
//S 09/03/23 18:30:20 WiFi sent:
55AA00060005150400010226
//S 09/03/23 18:30:20 WiFi sent:
55AA00060054190300503036343634363031303030303033653830336538303030303030303034363436303130303738303365383033653830303030303030303436343630313030663030336538303365383030303030303030CF
//R 09/03/23 18:30:20 WiFi received:
55AA03070054190300503036343634363031303030303033653830336538303030303030303034363436303130303738303365383033653830303030303030303436343630313030663030336538303365383030303030303030D3
Animacja water:
//S 09/03/23 18:32:20 WiFi sent:
55AA00060005150400010226
//S 09/03/23 18:32:20 WiFi sent:
55AA000600201903001C303330653064303030306538303338333033316330303030303030308B
//R 09/03/23 18:32:20 WiFi received:
55AA0307000515040001022A
//R 09/03/23 18:32:20 WiFi received:
55AA030700201903001C303330653064303030306538303338333033316330303030303030308F
Kolor biały, zmiana jasności od 0 do 100:
//S 09/03/23 19:17:26 WiFi sent:
55AA00060005150400010125
//R 09/03/23 19:17:26 WiFi received:
55AA03070005150400010129
//S 09/03/23 19:17:26 WiFi sent:
55AA000600101803000C303033643030333030336538F6
//R 09/03/23 19:17:26 WiFi received:
55AA030700101803000C303033643030333030336538FA
Tak jak pisałem wcześniej, jasność jest zakodowana w kolorze, dpID 21 to tryb pracy (1 to czysty kolor):
Kolor biały, zmiana jasności od 100 do 0:
//S 09/03/23 19:16:48 WiFi sent:
55AA00000000FF
//R 09/03/23 19:16:48 WiFi received:
55AA030000010104
//S 09/03/23 19:16:50 WiFi sent:
55AA00060005150400010125
//S 09/03/23 19:16:50 WiFi sent:
55AA000600101803000C303033643030333030303061E7
//R 09/03/23 19:16:50 WiFi received:
55AA03070005150400010129
//R 09/03/23 19:16:50 WiFi received:
55AA030700101803000C303033643030333030303061EB
Tak jak pisałem wcześniej, jasność jest zakodowana w kolorze, dpID 21 to tryb pracy (1 to czysty kolor):
Kolor biały:
//S 09/03/23 19:16:15 WiFi sent:
55AA000600191C030015313030336430303330303365383030303030303030BD
//S 09/03/23 19:16:15 WiFi sent:
55AA00060005150400010125
//R 09/03/23 19:16:15 WiFi received:
55AA030700191C030015313030336430303330303365383030303030303030C1
//S 09/03/23 19:16:15 WiFi sent:
55AA000600101803000C303033643030333030336538F6
//R 09/03/23 19:16:15 WiFi received:
55AA03070005150400010129
//R 09/03/23 19:16:16 WiFi received:
55AA030700101803000C303033643030333030336538FA
//S 09/03/23 19:16:18 WiFi sent:
55AA00000000FF
//R 09/03/23 19:16:18 WiFi received:
55AA030000010104
Kolor żółty:
//S 09/03/23 19:05:59 WiFi sent:
55AA000600191C03001531303033633033626230336538303030303030303020
//R 09/03/23 19:05:59 WiFi received:
55AA030700191C03001531303033633033626230336538303030303030303024
//S 09/03/23 19:05:59 WiFi sent:
55AA00060005150400010125
//S 09/03/23 19:05:59 WiFi sent:
55AA000600101803000C30303363303362623033653859
//R 09/03/23 19:05:59 WiFi received:
55AA03070005150400010129
//R 09/03/23 19:05:59 WiFi received:
55AA030700101803000C3030336330336262303365385D
//S 09/03/23 19:06:03 WiFi sent:
55AA00000000FF
//R 09/03/23 19:06:03 WiFi received:
55AA030000010104
Raczej bez niespodzianek:
Rezultaty analizy pakietów
Po analizie zebranych danych dotarliśmy do następujących wniosków:
- dpID 24 - kolor w formacie Tuya, jako string, HSV, a dokładniej w formacie 12 znaków, gdzie kolejno mamy wartość H, S i V, H w zakresie od 0 do 360, pozostałe od 0 do 1000, wszystko jako ASCII hex, czyli generowane jak poniżej:
Kod: C / C++
- dpID 25 - string o różnej długości, w jakiś sposób zakodowana animacja bądź jej ID (trudno nam na ten moment powiedzieć)
- dpID 21 - tryb pracy, albo clear color, albo animacja, 1 to kolor, 2 to animacja, z tego co wiem wartość 0 to byłoby CW (temperatura bieli)
- dpID 20 - on lub off, włączenie lub wyłączenie LEDów
Konfiguracja OpenBeken
OpenBeken już wcześniej wspierał podstawę TuyaMCU:
OpenBeken i ściemniacz na TuyaMCU - konfiguracja i demonstracja
Radar z WiFi - TuyaMCU, OpenBeken, własna strona konfiguracyjna hostowana na urządzeniu
Większość była już zatem zaimplementowana. W zasadzie to nawet nie musieliśmy pisać kodu C by dodać wsparcie tego urządzenia, tylko wystarczyło oskryptować już wewnątrz w OBK role dpID.
W związku z tym przygotowaliśmy skrypt autoexec.bat, tutaj po po kolei omówię:
startDriver TuyaMCU
tuyaMcu_defWiFiState 4
tuyaMcu_setBaudRate 115200
Powyższa sekcja skryptu OBK włącza sterownik TuyaMCU, ustawia domyślny stan WiFI na 4 (zgodnie z dokumentacją Tuya to jest "connected to cloud", by MCU myślało, że jest sparowane w pełni oraz ustawia baud rate komunikacji TuyaMCU.
tuyaMCU_setupLED 24 1
Powyższy fragment kodu uruchamia sterownik LED TuyaMCU na dpID 24, pierwszy format koloru.
startDriver httpButtons
setButtonEnabled 0 1
setButtonLabel 0 "Music mode"
setButtonCommand 0 "tuyaMcu_sendState 21 4 3"
startDriver httpButtons
setButtonEnabled 1 1
setButtonLabel 1 "Light mode"
setButtonCommand 1 "tuyaMcu_sendState 21 4 1"
setButtonEnabled 2 1
setButtonLabel 2 "Curtain"
setButtonCommand 2 "startScript autoexec.bat do_cur"
setButtonEnabled 3 1
setButtonLabel 3 "Collision"
setButtonCommand 3 "startScript autoexec.bat do_col"
setButtonEnabled 4 1
setButtonLabel 4 "Rainbow"
setButtonCommand 4 "startScript autoexec.bat do_rai"
setButtonEnabled 5 1
setButtonLabel 5 "Pile"
setButtonCommand 5 "startScript autoexec.bat do_pil"
setButtonEnabled 6 1
setButtonLabel 6 "Firework"
setButtonCommand 6 "startScript autoexec.bat do_fir"
setButtonEnabled 7 1
setButtonLabel 7 "Chase"
setButtonCommand 7 "startScript autoexec.bat do_chase"
// stop execution
return
Powyższy fragment wykorzystuje skryptowalny sterownik przycisków OpenBeken do utworzenia przycisków wyzwalających animacje, a dokładniej skrypty odtwarzające animacje, które dopiero pokażę. OpenBeken jest w dużym stopniu skryptowalny, więc dodanie przycisku nie wymaga w ogóle rekompilacji firmware.
do_chase:
tuyaMcu_sendState 21 4 2
delay_s 0.1
tuyaMcu_sendState 25 3 020e0d00001403e803e800000000
return
do_cur:
tuyaMcu_sendState 21 4 2
delay_s 0.1
tuyaMcu_sendState 25 3 000e0d00002e03e802cc00000000
return
do_col:
tuyaMcu_sendState 21 4 2
delay_s 0.1
tuyaMcu_sendState 25 3 07464602000003e803e800000000464602007803e803e80000000046460200f003e803e800000000464602003d03e803e80000000046460200ae03e803e800000000464602011303e803e800000000
return
do_rai:
tuyaMcu_sendState 21 4 2
delay_s 0.1
tuyaMcu_sendState 25 3 06464601000003e803e800000000464601007803e803e80000000046460100f003e803e800000000
return
do_pil:
tuyaMcu_sendState 21 4 2
delay_s 0.1
tuyaMcu_sendState 25 3 010e0d000084000003e800000000
return
do_fir:
tuyaMcu_sendState 21 4 2
delay_s 0.1
tuyaMcu_sendState 25 3 05464601000003e803e800000000464601007803e803e80000000046460100f003e803e800000000464601003d03e803e80000000046460100ae03e803e800000000464601011303e803e800000000
return
Powyższy fragment kodu to sama implementacja animacji po stronie OBK, tutaj w zasadzie tylko wysyłamy na sztywno do MCU pakiety wyzwalające daną animację. To są dokładnie te same pakiety, które przechwyciliśmy wcześniej. Dodatkowo mamy tutaj jeszcze wysłanie wartości dpID 21, wartość 2, czyli tryb animacji.
W razie pytań czym są poszczególne komendy odsyłam do:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/commands.md
Modyfikacja - dodanie pomiaru temperatury i fizycznych przycisków
Zmiana firmware nie musi tylko odzwierciedlać oryginalnych funkcjonalności urządzenia. Może ona też dodawać nowe. W związku z tym zdecydowaliśmy się nieco rozwinąć tę lampkę, a mianowicie dodać przyciski oraz czujnik temperatury.
Jako czujnik temperatury użyliśmy MCP9808 :
// startDriver MCP9808 [ClkPin] [DatPin] [OptionalTargetChannel]
startDriver MCP9808 7 8 1
MCP9808_Adr 0x30
MCP9808_Cycle 1
Powyższy fragment kodu konfiguruje ten czujnik na danych pinach GPIO oraz ustawia jego adres. Komunikacja odbywa się przez I2C. Cykl to 1 sekunda, co sekundę pomiar. Tak skonfigurowany czujnik jest też potem widoczny w Home Assistant po wykonaniu Home Assistant Discovery.
Dodatkowo podłączyliśmy też zwykłe fizyczne przyciski na wolne GPIO, a dokładniej między GPIO a masą.
W OBK, w panelu konfiguracji GPIO, po prostu wybraliśmy im pasujące nam role:
- Button - by przełączać stan zasilania
- Button_NextDimmer - kontrola poziomu jasności
- Button_NextColor - zmiana koloru
Można by też użyć jedno przycisku o wielu funkcjach (pod dwuklikiem i przyciśnięciem dłuższym): SmartButtonForLEDs
Dodatkowo też oskryptowaliśmy przycisk od zmiany animacji, nadaliśmy mu rolę Btn_ScriptOnly oraz przygotowaliśmy następujący skrypt:
// use choice to choose effect by index stored in $CH10
alias do_chosen_effect Choice $CH10 cmd_cur cmd_col cmd_rai cmd_pil cmd_fir cmd_chase
// when click on Btn_ScriptOnly on P24 happens, add 1 to $CH10 (wrap to 0-5) and do effect
addEventHandler OnClick 24 backlog addChannel 10 1 0 4 1; do_chosen_effect
Powyższy skrypt wykorzystuje kanał 10 jako zmienną reprezentującą bieżący indeks animacji, przewija go i zapętla (patrz dokumentacja addChannel) a potem wykorzystuje komendę Choice do odpalenia wybranej animacji.
O przyciskach (zarówno ogólnego zastosowania, jak i "specjalistycznych" typu zmiana koloru) w OBK można poczytać tutaj:
https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/ioRoles.md
Ostatecznie, tak wygląda panel OBK tego urządzenia:
Widać tu odczyt temperatury z MCP9808 oraz wspomniane oskryptowane przyciski od animacji.
A przyciski fizyczne działają jak na filmiku:
Podsumowanie
Sterownik tego urządzenia składa się osobno z modułu WiFi który komunikuje się ze światem zewnętrznym, oraz z MCU który steruje diodami oraz obsługuje odbiornik RF od pilota. Moduł WiFi komunikuje się z MCU poprzez protokół TuyaMCU na porcie UART 1. Aby uwolnić te urządzenie od chmury, wystarczy zmienić firmware modułu WiFi na OBK i odpowiednio je oskryptować. MCU wcale nie flashowaliśmy. Zmiana firmware tez pozwoliła nam na rozwinięcie funkcjonalności urządzenia o pomiar temperatury oraz o przyciski fizyczne, które uważam za niezbędne, po co nam pasek LED który można sterować tylko przez telefon?
Po naszych zmianach urządzenie działa w pełni lokalnie, nie łączy się z serwerami producenta i da się je sterować z Home Assistant, aczkolwiek na ten moment wyzwalanie animacji należy napisać ręcznie w yaml, wysyłając na MQTT odpowiednią komendę. Reszta działa przez Home Assistant Discovery w OBK.
To na razie tyle, na koniec jeszcze dodam, żę pracujemy też nad innym urządzeniem, które też opiera się o indywidualnie adresowalne LEDy, ale w jego przypadku pasek jest podłączony bezpośrednio do BK7231, nie ma użytego tam TuyaMCU. To oznacza, że będziemy wkrótce uruchamiali sterownik WS2812B na BK, najprawdopobniej w oparciu o SPI, ale o tym innym razem...
Fajne? Ranking DIY Pomogłem? Kup mi kawę.
