Przedstawię tu wnętrze czujnika otwarcia drzwi/okna Tuya WiFi zrealizowanego w oparciu o dwa osobne układy - mikrokontroler (zasilany cały czas) i moduł WiFi (tutaj: CB3S/BK7231N; zasilany tylko gdy trzeba wysłać informacje przez WiFi) komunikujące się poprzez UART (protokół TuyaMCU, ale w wersji 0x00, nie 0x03). Spróbuję też zmierzyć jego pobór prądu w trybie snu. Będzie to nieco inny rodzaj czujnika niż poprzednio recenzowany wykonany na samym module WiFi XR809/XR3:
W tym temacie skupię się na działaniu czujnika DS06 i na jego protokole komunikacji TuyaMCU z modułem WiFi.
Zakup czujnika
Produkt kupiłem na bezpośrednią prośbę jednego z użytkowników. Można go znaleźć w sieci pod nazwą "AVATTO Tuya WiFi Door Sensor, Smart Door Open/Closed Detectors, Smart Life APP Wifi Window Sensor Work with Alexa,Google Home", jak również pod nazwą modelu: D06/DS06. Kosztuje około 40 zł.
Produkt reklamowany jest (zgodnie z prawdą) jako kompatybilny z aplikacjami Tuya i SmartLife:
Zawartość zestawu
Znów na paczkę czekałem kilka tygodni. Przyniósł ją Pocztex, choć nadana była przez "Sinotrans w imieniu i na rzecz Cainiao".
Opakowanie jest w niebieskiej kolorystyce SmartLife (Tuya ma pomarańczową), ale to wszystko to jest ten sam ekosystem:
W zestawie jest instrukcja i śruby oraz taśma do mocowania:
Instrukcja (w tryb parowania wchodzi się poprzez wciśnięcie RESET dłużej niż 7 sekund):
Sensor wymaga dwóch baterii AAA:
Test z aplikacją Tuya
Sensor przemalowany jest na SmartLife i kod QR prowadzi do aplikacji SmartLife, ale też jest kompatybilny z oryginalną, "pomarańczową" aplikacją Tuya:
Można w niej tworzyć automatyzację, ale to było już omawiane na forum kilka razy.
Wnętrze D06
Wystarczy podważyć obudowę nożykiem:
W środku jest moduł WiFi CB3S (BK7231N) i mikrokontroler (bez oznaczenia):
Wyprowadzenia CB3S - z dokumentacji Tuya:
| Pin number | Symbol | I/O type | Function | 1 | RST | I | Low-level reset, high level active (the pin has been pulled high internally), correspond to CEN of the IC | 2 | ADC3 | AI | ADC pin, which corresponds to P23 of the IC | 3 | CEN | I | Enabling pin, which is pulled high internally to be compatible with other modules | 4 | P14 | I/O | A common GPIO interface, which corresponds to P14 of the IC | 5 | P26 | I/O | GPIOP_26, which corresponds to P26 of the IC, PWM 5 | 6 | P24 | I/O | GPIOP_24, which corresponds to P24 of the IC, PWM 4 | 7 | P6 | I/O | GPIOP_6, which corresponds to P6 of the IC, PWM 0 | 8 | VCC | P | Power supply pin (3.3V) | 9 | GND | P | Power supply reference ground | 10 | P9 | I/O | GPIOP_9, which corresponds to P9 of the IC, PWM 3 | 11 | TXD2 | I/O | UART2_TXD (used to display the module internal information), which corresponds to P0 of the IC | 12 | CSN | I/O | Production test control pin. If it is used as a common I/O pin, it must be connected to the VCC externally. Do not connect it to the ground before the module is powered on. | 13 | P8 | I/O | GPIOP_8, which corresponds to P8 of the IC, PWM 2 | 14 | P7 | I/O | GPIOP_7, which corresponds to P7 of the IC, PWM 1 | 15 | RXD1 | I/O | UART1_RXD (user serial interface), which corresponds to P10 of the IC. Do not connect it to the VCC. By default, the MCU serial port should be in low-level or high-impedance state. | 16 | TXD1 | I/O | UART1_TXD (user serial interface), which corresponds to P11 of the IC. Do not connect it to the VCC. By default, the MCU serial port should be in low-level or high-impedance state. | 17 | ADC3 | AI | (Not recommended. If needed, please use Pin 2) ADC port, which corresponds to P23 of the IC. Programmed SPI | 18 | P22 | I/O | (Not recommended ) GPIOP_22, which corresponds to P22 of the IC. Programmed SPI | 19 | CSN | I/O | The pull-up resistor is needed during usage of customers. Do not connect it to the ground before the module is powered on. Correspond to P21 of the IC. | 20 | P20 | I/O | (Not recommended. ) GPIOP_20, which corresponds to P20 of the IC. Programmed SPI | 21 | NC | - | - | 22 | NC | - | - |
W celu dokładniejszego przeanalizowania płytki najpierw usunąłem spoiwo plecionką a potem zdjąłem ją z plastikowej bazy:
Na spodzie nie ma jednak dużo:
Na bazie zebranej wiedzy przygotowałem szkic połączeń:
Ten czujnik otwarcia drzwi/okna działa całkiem inaczej niż opisywany przeze mnie kiedyś czujnik zrealizowany na XR809 (XR3). Tutaj moduł WiFi jest normalnie wyłączony - pracuje ciągle tylko mikrokontroler. Mikrokontroler może tylko załączyć zasilanie CB3S poprzez tranzystor MOSFET z kanałem typu P A19T gdy zajdzie taka potrzeba. Mikrokontroler ten komunikuje się z CB3S poprzez protokół TuyaMCU, ale w wersji dla urządzeń zasilanych bateryjnie, czyli 0x00 a nie 0x03.
W dużym uproszczeniu, połączenie wygląda tak:
Grafika pochodzi z oficjalnej dokumentacji Tuya.
Sposób raportowania danych przez sensor obrazuje natomiast ten algorytm:
Moduł WiFi pracuje naprawdę przez krótki okres czasu, normalnie tylko mikrokontroler w trybie niskiego zużycia energii nasłuchuje zmian na czujniku.
Zmiany wsadu CB3S już tu nie opisuję, bo było to omawiane np. dla CB2S, ale jedynie podkreślę, że linie RX/TX są zajęte przez TuyaMCU, więc jak chcemy programować to trzeba je odciąć lub odlutować tamten układ scalony...
Bliźniaczy produkt - czujnik zalania W06
Podobnie jak w przypadku omawianego kiedyś czujnika otwarcia/drzwi okna opartego o moduł XR809 (ale bez TuyaMCU), ten produkt też sprzedawany jest w formie czujnika zalania - jest to po prostu to samo PCB, te same układy, ale zamiast kontaktrona są właśnie wyprowadzone styki czujnika wilgoci:
Testy poniżej wykonywałem na obu urządzeniach - działają analogicznie.
Różnica jest tylko taka, że my jako użytkownik wiemy, że czujnik otwarcia drzwi raportuje otwarte/zamknięte a czujnik wilgoci raportuje mokro/sucho. Same pakiety są identyczne.
Przechwycone pakiety TuyaMCU na UART
Przechwytywania dokonałem przy baud 9600. Pakiety zostawiam tutaj m. in. dla siebie na przyszłość, gdy będę implementować/finalizować wsparcie tej wersji TuyaMCU w OpenBeken .
Podstawy TuyaMCU opisywałem tutaj (to była nieco inna wersja ale większość zasadniczo pasuje):
Protokół TuyaMCU - komunikacja pomiędzy mikrokontrolerem a modułem WiFi.
Przy analizie pakietów polecam korzystać z oficjalnej dokumentacji:
Serial Communication Protocol
Uruchomienie.
CB3S wysyła:
Cytat:
55 AA 00 01 00 00 00
Mamy tu (zapis hex):
- nagłówek - 55 AA
- wersję - 00
- kod komendy - 01
- długość danych - 00 00
- sumę kontrolną - 00
Kod komendy 0x01 to pobranie danych o produkcie - Query Product Information.
TuyaMCu odpowiada:
Cytat:
55 AA 00 01 00 24 7B 22 70 22 3A 22 65 37 64 6E 79 38 7A 76 6D 69 79 68 71 65 72 77 22 2C 22 76 22 3A 22 31 2E 30 2E 30 22 7D 24
Zawartość tego pakietu (o długości 0x24 bajty czyli dziesiętnie 36 bajtów) to tekst ASCII:
Cytat:
55 AA 00 01 00 24 {"p":"e7dny8zvmiyhqerw","v":"1.0.0"}$
Identyfikator urządzenia + wersja.
Już sparowane, kontakt zamknięty w momencie podłączenia zasilania.
(w poniższych cytatach nie podzieliłem osobnych par request-reply tylko w postaci jednego bloku dałem najpierw to co wysyła CB3S a potem co odpowiada mikrokontroler)
CB3S wysyła:
Cytat:
00 00
55 AA 00 01 00 00 00
55 AA 00 02 00 01 04 06
55 AA 00 08 00 01 00 08
55 AA 00 08 00 01 00 08 00
TuyaMCu odpowiada:
Cytat:
00
55 AA 00 01 00 24 7B 22 70 22 3A 22 65 37 64 6E 79 38 7A 76 6D 69 79 68 71 65 72 77 22 2C 22 76 22 3A 22 31 2E 30 2E 30 22 7D 24
55 AA 00 02 00 00 01
55 AA 00 02 00 00 01
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 01 00 01 01 23
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23 00
Typ wiadomości 0x02 to ustawienie statusu pracy WiFi, a 0x08 to już dane o sensorach, ale o tym za chwilę. Najpierw jeszcze kilka przykładów.
Już sparowane, urządzenie w trybie snu, zbudziłem je zamykając kontakt.
CB3S wysyła:
Cytat:
00
55 AA 00 01 00 24 7B 22 70 22 3A 22 65 37 64 6E 79 38 7A 76 6D 69 79 68 71 65 72 77 22 2C 22 76 22 3A 22 31 2E 30 2E 30 22 7D 24
55 AA 00 02 00 00 01
55 AA 00 02 00 00 01
head vr id size FL YY MM DD HH MM SS ID TP SIZE VL CK
55AA 00 08 000C 00 02 02 02 02 02 02 01 01 0001 00 22
head vr id size FL YY MM DD HH MM SS ID TP SIZE VL CK
55AA 00 08 000C 00 01 01 01 01 01 01 03 04 0001 02 23
Pod pakietem naniosłem informację co jest co - kolejno head (nagłówek), vr (version), id (identyfikator pakietu), size (rozmiar), FL (flaga), potem wartości daty, potem ID (dpID/fnID, czyli nazwa zmiennej), TP (typ), SIZE (rozmiar wartości zmiennej), VL (value - jej wartość), CK - checksum, suma kontrolna.
Już sparowane, urządzenie w trybie snu, zbudziłem je otwierając kontakt.
CB3S wysyła:
Cytat:
00
55 AA 00 01 00 24 7B 22 70 22 3A 22 65 37 64 6E 79 38 7A 76 6D 69 79 68 71 65 72 77 22 2C 22 76 22 3A 22 31 2E 30 2E 30 22 7D 24
55 AA 00 02 00 00 01
55 AA 00 02 00 00 01
head vr id size FL YY MM DD HH MM SS ID TP SIZE VL CK
55AA 00 08 000C 00 02 02 02 02 02 02 01 01 0001 01 23
head vr id size FL YY MM DD HH MM SS ID TP SIZE VL CK
55AA 00 08 000C 00 01 01 01 01 01 01 03 04 0001 02 23
00
Pakiety typu 0x08 (dane) zawierają datę/godzinę (tutaj niepoprawną), przeze mnie oznaczoną jako YY MM DD HH MM SS, flagę określającą poprawność daty (moje oznaczenie FL) oraz dodatkowe dane, tzw. data point, ID (id zmiennej), TP (jej typ), SIZE (jej rozmiar) oraz VL (jej wartość).
To wartość VL określa stan czujnika drzwi.
Poniżej zrzuty ekranu opisujące strukturę tego pakietu z dokumentacji:
Już sparowane, urządzenie w trybie snu, zbudziłem je wciskając przycisk RESET.
CB3S wysyła:
Cytat:
00
55 AA 00 01 00 00 00 (01=Query Product Information)
55 AA 00 02 00 01 03 05 (02=MCU Conf)
55 AA 00 02 00 01 04 06 (02=MCU Conf)
55 AA 00 08 00 01 00 08 00 (08=Query State)
TuyaMCU odpowiada:
Cytat:
00
55 AA 00 01 00 24 7B 22 70 22 3A 22 65 37 64 6E 79 38 7A 76 6D 69 79 68 71 65 72 77 22 2C 22 76 22 3A 22 31 2E 30 2E 30 22 7D 24 (01=Query Product Information)
55 AA 00 02 00 00 01 (02=MCU Conf)
55 AA 00 02 00 00 01 (02=MCU Conf)
head vr id size FL YY MM DD HH MM SS ID TP SIZE VL CK
55AA 00 08 000C 00 01 01 01 01 01 01 03 04 0001 02 23 00 (08=Query State)
Eksperyment: co wysyła sam CB2S jak odetniemy ścieżki RX i TX i wykonamy reboot?
Tylko dla zasady - to powinno być jasne.
55AA0001000000F8
Rozdzielmy treść pakietu:
55AA 00 0100 00 00 F8
Przypomnę, mamy kolejno:
- 55AA - nagłówek
- 00 - wersja
- 0100 - długość 1 bajt
- 00 - dane
- 00 - checksum
Powtarzające się F8/F9 wygląda jak zakłócenie, nie jest ono częścią pakietu.
Eksperyment: co wysyła sam TuyaMCU po odcięciu TX i RX?
O dziwo jednak coś wysyła - chyba by utrzymać połączenie:
Co kilka sekund zerowy bajt. Albo to zakłócenie.
A co jak po uruchomieniu zasilania wyślemy do TuyaMCU zapytanie o identyfikację:
Cytat:
0x55 0xAA 0x00 0x01 0x00 0x00 0x00
Odpowiedź:
Cytat:
55 AA 00 01 00 24 7B 22 70 22 3A 22 6A 35 33 72 6B
64 75 35 35 79 64 63 30 66 6B 71 22 2C 22 76 22 3A 22 31 2E 30 2E 30 22
7D 43
Tak - to jest już ten omawiany pakiet z wartością ASCII typu {“p”:“vHXEcqntLpkAl***”, “v”:“1.0.0”};
Zrzut ekranu:
A jak spróbujemy zapytać go o stan?
0x55 0xAA 0x00 0x08 0x00 0x01 0x00 0x08
Brak odpowiedzi.
Trzeba najpierw wysłać konfigurację, potem dopiero można 0x08 o Data Points pytać:
0x55 0xAA 0x00 0x02 0x00 0x01 0x04 0x06
Poniżej cała transakcja:
Rozbite odpowiedzi:
55 AA 00 02 00 00 01
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 02 00 01 04 06
55 AA 00 02 00 00 01
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 02 00 01 04 06
55 AA 00 02 00 00 01
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 08 00 0C 00 01 01 01 01 01 01 ID TP LENG VL CH
55 AA 00 02 00 00 01
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 08 00 0C 00 01 01 01 01 01 01 ID TP LENG VL CH
Pakiety zebrane na bliźniaczym czujniku zalania (identyczny układ i protokół, tylko inny sensor).
Mokro (a właściwie włożenie czujnika do wody):
55 AA 00 02 00 01 04 06
55 AA 00 02 00 00 01
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 08 00 0C 00 01 01 01 01 01 01 ID TP LENG VL CH
55 AA 00 02 00 01 04 06
55 AA 00 02 00 00 01
(widać zmianę zmiennej o ID=01 z VL 01 na VL 00)
Sucho:
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
55 AA 00 08 00 0C 00 01 01 01 01 01 01 ID TP LENG VL CH
Widzicie różnicę?
Na ostatnią wartość proszę nie zwracać uwagi, to suma kontrolna, wiadomo, że się zmienia.
Mokro:
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25
55 AA 00 08 00 0C 00 01 01 01 01 01 01 ID TP LENG VL CH
Sucho:
55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 01 26
55 AA 00 08 00 0C 00 01 01 01 01 01 01 ID TP LENG VL CH
Pakiet o ID 0x01 (dpID albo fnID 0x01) zmienia wartość z 1 (VL, Value) na 0.
Mamy też ID 0x03:
55 AA 00 08 00 0C 00 01 01 01 01 01 01 03 04 00 01 02 23
... ale to jest stan baterii (wartość, VL, 02).
Na koniec wykonałem test w OpenBeken - oba układy zasilane osobno z 3.3V, mikrokontroler wybudzony, te dziwne 00 00 00 w buforze tuyaMCU się pojawiają gdy mikrokontroler śpi (ma wyłączony UART) a moduł WiFi w sztuczny sposób działa (przez nas zasilony dodatkowo):
OpenBeken zdolny jest odebrać pakiet identyfikacji MCU.
Natomiast jeśli sami wyślemy pakiet konfiguracji 0x02 (na zrzucie ekranu przez komendę uartSendHex), to CB3S też nam wyśle pakiet 0x08 ze stanami zmiennych:
Podsumowując, powyższe dane pokazują, że używane są w tych sensorach dwie zmienne TuyaMCU (data points) w pakiecie 0x08:
- dpID 1 - stan czujnika, 0 lub 1 (dla czujnika drzwi to otwarcie/zamknięcie, dla czujnika wilgoci to mokro/sucho)
- dpID 3 - stan baterii, od 3 (pełna) do 0 (albo 1 - nie sprawdzane).
Dane te raportowane są przez TuyaMCU po zidentyfikowaniu się modułu WiFi.
Konfiguracja w OpenBeken
Mój OpenBeken wspiera już ten czujnik, ale jeszcze nie testowałem w pełni całej funkcjonalności.
Obsługa tego czujnika wymaga włączenia dwóch "driverów", jeden TuyaMCU, a drugi tmSensor. TuyaMCU obsługuję podstawę komunikacji UART, a tmSensor sam wysyła pakiety odpytujące o stan (przypominam - to moduł WiFi pierwszy odzywa się po UART do TuyaMCU).
Oto linia komend OpenBeken (wpisałem to w startup command by się wykonywało na starcie):
backlog startDriver tuyaMCU; startDriver tmSensor; linkTuyaMCUOutputToChannel 1 val 1; setChannelType 1 ReadOnly; linkTuyaMCUOutputToChannel 3 val 3; setChannelType 3 ReadOnly;
Kanały/dpID tak jak wyżej - 1 i 3. Jeden to stan sensoru, drugi baterii.
Konfiguracja Yaml w Home Assistant (ten przykład jest dla czujnika wody, ale tak jak pisałem, to ten sam układ, tylko inny sensor, czujnik otwarcia drzwi działa analogicznie):
Kod: YAML
Odczytu baterii jeszcze nie robiłem - pełną wersję umieszczę w następnym temacie.
Zrzut ekranu z panelu:
Widok w HA:
Pobór prądu w trybie uśpienia i wysyłania danych
Mikrokontroler uruchamia moduł WiFi tylko gdy trzeba wysłać dane, ale ile oszczędza to prądu? Tryb uśpienia:
Wysyłanie danych (tu pływa prąd o około 70mA)
Podsumowanie
Ten czujnik otwarcia drzwi/okna rzeczywiście różni się od czujnika omawianego wcześniej, opartego na XR809. Dodanie mikrokontrolera załączającego moduł WiFi kiedy tylko trzeba wysłać nowe informacje do serwera z pewnością pozwala w jakimś stopniu zaoszczędzić energię i wydłuża czas pracy baterii, ale też komplikuje sam układ i utrudnia dodanie jego wsparcia do mojego firmware.
Z moich pomiarów wynika, że w trybie snu MCU pobór prądu wynosi około 5µA. Warto nadmienić, że wtedy MCU nawet wyłącza swój UART (sprawdzałem - nie odpowiada) i tylko czeka na sygnał od sensora bądź czujnika.
W momencie gdy sygnał jest odebrany, moduł WiFi jest włączony i zużycie prądu sięga do 70mA lub więcej, zależy od tego co robi WiFi.
Te 5µA to raczej dobry wynik - zajrzałem do noty katalogowej ESP8266 (tu nie ma ESP tylko BK7231N, ale myślę, że warto porównać) i w zależności od trybu snu ESP8266 pobiera następujące prądy:
czyli rzeczywiście producent mógł coś ugrać na tym dodaniu MCU.
Co ciekawe, wynik 5µA przypomina pobór prądu ESP32 w trybie hibernacji (bazując na jego nocie katalogowej):
Rzecz jasna na zużycie energii wpływa też pobór prądu przy działaniu modułu WiFi - tylko że też trudno ocenić jak duży to wpływ, bo nie wiemy jak często będą otwierane drzwi.
Ten sam produkt występuje też jako czujnik zalania - układ i protokół ma identyczny, różni się jedynie tym, że przylutowany jest inny sensor.
Sam czujnik przerobiłem już wstępnie pod mój OpenBeken (dodałem jego wsparcie w moim firmware), ale nie jest to finalna wersja, więc opiszę to szczegółowo innym razem.
Czy ktoś korzysta z tego typu czujników a jeśli tak, to na ile starcza bateria? Zapraszam do dyskusji.
Fajne? Ranking DIY Pomogłem? Kup mi kawę.
