Przedstawię tutaj ciekawy sterownik lampy RGBCW o protokole komunikacji bardzo podobnym do diod WS2812B. Tematem zainteresowałem się na prośbę czytelnika z Niemiec, który nawet przesłał mi "smart" lampę z tym właśnie sterownikiem abym mógł spróbować go odszyfrować i uruchomić w swoim środowisku. Celem oczywiście było uwolnienie jej od chmury. Przygodę zaczęliśmy od inżynierii wstecznej, chociaż już po odszyfrowaniu części komunikacji ktoś inny z czytelników podzielił się notą katalogową, więc sprawa też się uprościła. Ale po kolei...
Ten temat stanowi rezultat wątku z Elektroda.com:
OpenBeken Driver Connection Issues with RGBIC SM15155E and BK7231N in Smart Wall Lamp
SM15155 używany jest co najmniej w jednej z lamp Tuya dostępnej do kupienia w Internecie:
Znaleźć ją można pod hasłem LYTLM Smart Alexa LED Wandleuchte Aussen & Innen, Dimmbare RGB Bunt Farbwechsel Aussenleuchten IP65 wasserdichte, CCT WiFi APP Steuerung Kompatibel Google Home, Up Down Modern Garten Wandlampe,1 Pack. Marka to rzekomo LYTLM.
Sama lampa prezentuje się dość nieźle, jest o co powalczyć:
Etap 0 - wywiad sprzętowy
Czytelnik początkowo już zgłosił, że SM15155 jest używany w lampie z modułem BK7231N. Dodatkowo zauważył, że podłączony jest on do P16 BK7231N, ten pin jest znany z tego, że jest wyjściem danych sprzętowego portu SPI:
Pozostałe dwa piny na zdjęciu to masa i zasilanie.
To już mi zapaliło zieloną lampkę - to pewnie jest kontroler w stylu WS2812B. WS2812B też korzysta z P16, gdyż też jest sterowany jednym sygnałem, który wymaga bardzo precyzyjnych timingów. Ciężko jest takie timingi uzyskać w software, więc często wykorzystuje się do tego sprytnie port SPI - tak dobiera się bity wysyłanych bajtów, aby tworzyły oczekiwany przez WS2812B sygnał:
Kiedyś tym temat też się osobno zajmę.
Etap 1 - przechwytywanie danych z analizatorem logicznym
Następnie czytelnik podzielił się z nami tylko wsadem z modułu WiFi ze środka. Był tam BK7231N. Po prostu wgraliśmy ten wsad na jeden z naszych modułów z wyprowadzonym P16:
Jak uzyskać dostęp do sprzętowego portu SPI w CB2S? P16 (MOSI) lutujemy do QFN
Użyliśmy do tego naszej płytki developerskiej BK7231:
[Youtube] Jak zrobić płytkę rozwojową BK7231 - konwersja NodeMCU ESP8266
Udało nam się to sparować z Tuya:
Zaczęliśmy sterować "lampą" przez aplikację Tuya, ustawiać różne kolory i jednocześnie przechwytywać dane na P16 naszym analizatorem Sigrok:
Inżynieria wsteczna nieznanego protokołu I2C z analizatorem Sigrok na przykładzie kontrolera LED
Rzut oka oscyloskopem pokazuje już timingi:
Stan wysoki 340ns, niski 1.16us, przypomina to WS2812B. Nie jest idealnie, ale może...
Analizator PulseView natomiast pokazał, że choć timingi przypominają WS2812B, to ilość bajtów zdaje się być inna. Również samo znaczenie bajtów zdaje się nie zgadzać.
Etap 2 - pierwsze wrażenia co do protokołu
W związku z podejrzeniem, że jest to zasadniczo ten sam sposób komunikacji co WS2812B (podobne timingi) ale inne znaczenie bajtów, zmodyfikowałem skrypt dekodera WS2812B PulseView tak aby dekodował osobne bajty:
Kod: C / C++
Od razu lepiej:
Widać, że ramka ma 14 bajtów.
Teraz można pozbierać trochę danych...
Etap 3 - analiza zebranych danych
Porównałem dane zebrane dla różnych ustawień kolorów. Ta lampa jest typu RGBCW, czyli może pracować w trybie kolorów (czerwony, zielony, niebieski) lub barw bieli (zimna i ciepła biel). Analiza danych to potwierdzała. Przykładowy pakiet dla barwy czerwonej to:
FA000000000000000000739CE71F
Dla zielonej z kolei zapalają się inne bity:
00006200000000000000739CE71F
Zaobserwowałem, że gdy zmieniamy wartość danej barwy to zmienia się odpowiednia para bajtów. Można więc dojść do wniosku, że podział jest następujący:
0000 0000 0000 0000 0000 739CE71F
Najpierw mamy pięć 16-bitowych wartości kolorów, a potem są jeszcze jakieś dodatkowe 4 bajty (być może konfiguracja trybu pracy albo limity prądu).
Teraz pozostało to jeszcze sprawdzić w praktyce...
Swoją drogą żadnej sumy kontrolnej tu nie wykryłem, a już kiedyś jedna suma przy innym sterowniku LED sprawiała mi problem:
Inżynieria wsteczna nieznanego protokołu I2C z analizatorem Sigrok na przykładzie kontrolera LED
Etap 4 - lampa w praktyce, moduł WiFi
Na tym etapie przydałoby się mieć tę lampę fizycznie u siebie. Zdalnie jest ciężko to testować. Na szczęście tu też była taka opcja - po prostu czytelnik mi tę lampę wysłał. Ze względu na koszty transportu, otrzymałem samą podstawę, bez klosza:
Szybko wziąłem się za demontaż całości, też w celu sprawdzenia co to za moduł WiFi tam siedzi. Żadna z obu płytek z LEDami nie była mocno przyklejona do reszty lampy, moduł też udało się łatwo wylutować:
Moduł WiFi to FL_M129_V3 (BK7231N), datowany na 2021-12-17. Warto było go wylutować, bo od spodu ma podpisane wyprowadzenia:
Zacząłem od zmiany wsadu. Wgrałem tam mój OpenBeken:
https://github.com/openshwprojects/OpenBK7231T_App
Zgodnie z instrukcją flashera:
https://github.com/openshwprojects/BK7231GUIFlashTool
Na zdjęciu powyżej widać gdzie jest zasilanie (3.3V), masa, RX i TX.
Flashujemy:
Układ złożony na próbę, bez chłodzenia (trzeba z tym uważać, by nie przegrzać LEDów):
Etap 5 - praktyczny test na sterowniku WS2812B
Na poprzednim etapie ustaliłem, że sam sposób wysyłania bajtów jest zgodny z WS2812B, a więc też z np. wspieranym przez mój soft SM16703P. Tylko ilość i znaczenie bajtów jest inne. Oznacza to, że mogę użyć mojego istniejącego sterownika WS2812B opartego o SPI do wysłania sztucznie przygotowanej ramki dla SM15155.
OpenBeken wspiera skryptowanie, więc w oparciu o moją wcześniejszą analizę przygotowałem skrypt, który wysyła pakiety które wedle moich podejrzeń będą ustawiać kolejne kolory LED.
Miałem nadzieję, że nie ma w tym pakiecie sumy kontrolnej, mimo iż znaczenia ostatnich bajtów nie znam...
Oto mój skrypt:
startDriver SM16703P
SM16703P_Init 5
again:
SM16703P_SetRaw 1 0 FF000000000000000000739CE71F00
delay_s 1
SM16703P_SetRaw 1 0 0000FF00000000000000739CE71F00
delay_s 1
SM16703P_SetRaw 1 0 00000000FF0000000000739CE71F00
delay_s 1
SM16703P_SetRaw 1 0 000000000000FF000000739CE71F00
delay_s 1
SM16703P_SetRaw 1 0 0000000000000000FF00739CE71F00
// offf
delay_s 1
SM16703P_SetRaw 1 0 00000000000000000000739CE71F00
goto again
Komenda SM16703P_SetRaw od zawsze miała po prostu wysyłać na ślepo bajty do WS2812B w celu szybkiego ustawiania kolorów, ale tu też okazała się być jak znalazł. Ten zerowy bajt na końcu można zignorować.
Rezultat:
Sukces! Wszystko działa, teraz pora na dedykowany sterownik pod SM15155.
Etap 6 - integracja z kodem
Ten akapit nie jest już taki ważny. Po prostu dopisałem tutaj do mojego softu sterownik dla SM15155 oparty o wydzieloną komunikację przez SPI dla WS2812B i podpiąłem go do pozostałych sterowników RGBCW takich jak SM2135, BP5758, itd. Ta lampa nie ma kolorów "per pixel", tylko globalnie ustawia się jeden kolor, więc logika pasuje do SM2135 i podobnych.
Oto rzut oka na mój kod:
Kod: C / C++
Moje testy pokazały, że ten konkretny produkt jednak odbiera wartości 8-bitowe, nie wiem do czego służy drugie 8 bitów z każdej lampy. Będę musiał jeszcze to potestować.
Etap 7 - końcowy test
Skoro podstawa działa, to można lampę złożyć w całość. Skorzystałem z okazji i dodałem pasty między płytki z LED a metalową obudowę:
Krótki test i wszystko działa:
Teraz lampa poprawnie wyświetla panel kontrolny na głównej stronie OBK oraz można ją sparować z Home Assistant.
Dodatek - zasilacz
Przy okazji zainteresowałem się modułem zasilacza:
Zasilacz najpierw tworzy napięcie dla LEDów, a potem ma osobno po stronie wtórnej przetwornicę step down generującą 3.3V dla modułu WiFi. Jaki dokładnie kontroler przetwornicy flyback tam jest, tego nie wiem.
Dodatek - nota katalogowa
Nie było tej noty katalogowej dostępnej w sieci gdy szukaliśmy z kolegą @DeDaMrAz, ale potem ktoś u nas na forum specjalnie się zarejestrował by się nią z nami podzielić. To może nam wyjaśnić znaczenie ostatnich bajtów.
Pierwsza strona - informacje ogólne. Ten protokół nazywa się "1-wire, return-to-zero", nawet nie wiedziałem. Praca na napięciach od 5 do 40V. 16 bitów rozdzielczości kolorów (to dziwne, myślałem, że jednak 8, sprawdzę to):
I jednak można kaskadować SM15155.
Budowa wewnętrzna:
W środku jest pięć stałoprądowych sterowników LED.
Timingi, protokół komunikacji - w miarę zgodne z WS2812B:
Czyli jednak jest po 16 bitów na kanał, 5 kanałów, a potem pięć razy po 5 bitów (ustawienia prądu), 2 bity standby enable oraz 5 nieużywanych bitów.
Tak wygląda kaskadowanie SM15155:
Dodatek - to jak ostatecznie uruchomić ten sterownik w OpenBeken?
Aby uruchomić SM15155 w OpenBeken należy po prostu dopisać do autostartu komendę:
startDriver SM15155
Ewentualnie można też wykonać mapowanie kolorów komendą LED_Map. Nic więcej nie potrzeba. Reszta zadziała automatycznie, parowanie z HA też zadziała samo tak jak w przypadku innych urządzeń.
Podsumowanie
Lampę udało się uruchomić i mój sterownik SM15155 (choć niekompletny) jest chyba pierwszym sterownikiem open source dla tego układu. W ogóle noty katalogowej nie mogliśmy wcale znaleźć, dopiero pojawiła się gdy jeden z jej posiadaczy się zlitował i zgodził się z nami nią podzielić... podstawę już mieliśmy wtedy odszyfrowaną, ale znaczenie ostatnich bajtów nam to jednak wyjaśniło. Mimo wszystko, pewnie i bez tego byśmy to odgadli - osobno poziomy jasności i osobno limity prądowe są analogicznie wysyłane np. w układzie BP5758D, więc taki podział nie jest dla mnie zaskoczeniem. Bit enable też bym metodą prób i błędów odkrył, a w bieżącym sterowniku nawet z niego nie korzystam (choć pewnie powinienem - przerobię to).
Podsumowując - operacja się udała, pacjent zaświecił. Kolejne urządzenie IoT już może współpracować z moim oprogramowaniem open source i przy okazji też mamy kolejnego zadowolonego (mam nadzieję) czytelnika z Niemiec.
@HalliHalo - dzięki za wysłanie lampy, bez Twojej paczki opracowanie tego tematu nie byłoby możliwe.
Fajne? Ranking DIY Pomogłem? Kup mi kawę.