logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531

p.kaczmarek2 01 Lip 2026 10:07 453 4

TL;DR

  • Termostat E25-230B do ogrzewania podłogowego i grzejnikowego został rozebrany, aby sprawdzić jego wnętrze i możliwość własnej obsługi Zigbee.
  • W środku są osobny MCU M307LM, moduł Zigbee Tuya ZTU, radiowy Holtek BC3601 oraz czujnik temperatury w rogu obudowy.
  • Płytka T1015-06ZA-V1-1 zasila przetwornica OB2222MCP, potem AMS1117-3.3; przekaźnik beznapięciowy ma obciążalność do 3 A.
  • Skrypt w Pythonie na CC2531 poprawnie odczytał ramki Zigbee z klastra 0xEF00 i zdekodował temperaturę 220 oraz 240, czyli 22,0°C i 24,0°C.
  • Zigbee2MQTT nie wspierał tego termostatu, więc potrzebny był własny parser ramek TuyaMCU zamiast gotowej integracji.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA
📢 Słuchaj (AI):
  • Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    E25-230B to programowalny regulator temperatury przeznaczony do ogrzewania podłogowego lub grzejnikowego. Montowany jest natynkowo i oferuje czytelny wyświetlacz LCD oraz przyciski, którymi można zmienić nastawę grzania. Dodatkowo posiada też komunikację radiową 868MHz oraz ZigBee i jest zgodny z bramką Tuya, co pozwala na zdalne sterowanie przez Internet z każdego miejsca na świecie. Może sterować aż 6 głowicami grzejnikowymi w jednym pomieszczeniu. Może pracować offline w trybie dobowym (bez harmonogramu).
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    W tym temacie przedstawię jego wnętrze a potem spróbuję samodzielnie go obsłużyć w języku Python poprzez użycie dongle CC2531.
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    W zestawie otrzymujemy samo urządzenie, ramkę montażową oraz śruby. Urządzenie z tyłu posiada zaciski śrubowe - zasilanie 230 V oraz beznapięciowy przekaźnik o obciążalności do 3 A. Dodatkowo importer załącza polskojęzyczną instrukcję, która szczegółowo opisuje konfigurację urządzenia:
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Wyświetlacz jest wyraźny i czytelny. Odpowiednio można wprowadzić urządzenie w tryb parowania. Chciałem je sparować z Home Assistant przy użyciu Zigbee2MQTT, ale okazało się, że nie jest wspierane.
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Stąd pomysł na eksperymenty z samodzielnym odczytem danych, ale o tym za chwilę.

    Najpierw - rzut oka do wnętrza. Gdzie jest czujnik temperatury?
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Środek wydaje się być dość bogaty. Nie mamy tu całkiem typowego przykładu miniaturyzacji. W środku jest osobno główny mikrokontroler, tutaj w obudowie TQFP, moduł Zigbee (ZTU od Tuya), oraz moduł RF.
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Oznaczenie płytki to T1015-06ZA-V1-1, 2024-12-12. Całość zasila malutka przetwornica obniżająca napięcie na OB2222MCP. Co ciekawe, nawet widzę tam filtry i warystor. Tym razem chyba producent nie oszczędzał.
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Za przetwornicą jest LDO 3.3 V AMS1117-3.3 a potem układy - MCU M307LM (rdzeń RM® CortexTM-M0), moduł od RF to Holtek BC3601 (CMOS RF FSK/GFSK transceiver), a i jakaś pamięć Flash (25D20ATIG) też się tam znajdzie. Ciekawe, do czego?
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531 Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Ciekawość była silniejsza, odlutowałem pamięć i zgrałem za pomocą CH341 (niby jest metoda na klips, ale tak rzadko mi ona działa, że nawet nie próbuję). Zawartość okazała się być pusta.Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Na koniec jeszcze pokażę czujnik temperatury - znajduje się w rogu obudowy:
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531

    Zostało jednak to, co najciekawsze. Spróbujemy odczytać dane z urządzenia bezpośrednio na komputerze, wykorzystując w tym celu prosty skrypt w języku Python oraz naszą powszechnie znaną "antenkę":
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Zacznijmy od ważnego faktu dotyczącego układu CC2531: w zależności od wgranego firmware, ten moduł może być widoczny w systemie operacyjnym jako standardowy wirtualny port szeregowy (tryb CDC - Communication Device Class). Daje nam to prostą i wygodną możliwość sterowania stosem Zigbee (Z-Stack) za pomocą precyzyjnych poleceń binarnych wysyłanych bezpośrednio przez interfejs UART.
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Szukając po Internecie, znalazłem dokument od Texas Instruments z opisem API Z-Stack na repozytorium Tasmoty:
    https://tasmota.github.io/docs/_media/zigbee/Z-Stack_API_1_2.pdf
    Całość jednak jest dość zawiła, więc pomocne okazało się być przeszukiwanie GitHuba pod kątem implementacji konkretnych komend i stałych (jak np. ZDO_STARTUP_FROM_APP). Pozwoliło to podejrzeć, jak szybko nawiązać komunikację z modułem:
    https://github.com/search?q=ZDO_STARTUP_FROM_APP&type=code
    W oparciu o powyższe materiały przygotowałem niewielki, testowy skrypt w języku Python. Inicjalizuje on CC2531 i rozpoczyna nasłuchiwanie nadchodzących ramek w sieci Zigbee:
    Kod: Python
    Zaloguj się, aby zobaczyć kod

    Pełen kod:
    https://github.com/openshwprojects/CC2531test/blob/main/test1.py
    Rezultat, po sparowaniu danych:
    
    [*] READY! The script is fully listening.
    [*] 1. If it's already paired, just press a button on the thermostat.
    [*] 2. If it's not paired, put it in PAIRING MODE now.
    [*] (Press Ctrl+C to stop)
    
    [ZNP] Cmd: 64:00 | Length: 1 | Data: 00
    [ZNP] Cmd: 65:40 | Length: 1 | Data: 00
    [ZNP] Cmd: 45:C0 | Length: 1 | Data: 09
    [ZNP] Cmd: 65:36 | Length: 1 | Data: 00
    [ZNP] Cmd: 45:B6 | Length: 3 | Data: 000000
    [ZNP] Cmd: 45:CA | Length: 12 | Data: ab32e10e39feff9d1c780000
    [ZNP] Cmd: 45:C1 | Length: 13 | Data: ab32ab32e10e39feff9d1c788e
    [ZNP] Cmd: 45:C4 | Length: 3 | Data: ab3200
    
    [inContentAd]
    
    ============================================================
    📦 INCOMING ZIGBEE PACKET!
    📍 Device Network Addr: 0x32AB
    🎯 Zigbee Cluster ID  : 0xEF00 (identifies if it's Temp, HVAC, etc.)
    📄 Raw Data (Hex)     : 0900240600
    ============================================================
    [ZNP] Cmd: 45:C4 | Length: 3 | Data: ab3200
    

    Urządzenie wykrywa tzw. klaster (typ?) 0xEF00. Szybkie poszukiwania pokazują, że to jest coś od Tuya. To by się zgadzało:
    https://github.com/zigbeefordomoticz/wiki/blob/master/en-eng/Technical/Tuya-0xEF00.md
    Cytat:

    Seems to be the foundation of a number of Tuya devices. The tuya Cluster 0xEF00 is more or less one tunnel for tuyas MQTT commands from there MCUs to there cloud MQTT servers.

    Trop wskazuje na protokół TuyaMCU, który już omawiałem.
    Protokół TuyaMCU - komunikacja pomiędzy mikrokontrolerem a modułem WiFi
    A więc ta ramka Zigbee niesie w sobie ramkę TuyaMCU, nawet zgadzają się rodzaje typów, 0x01 to boolean, 0x03 to string... można spróbować to parsować, najpierw filtr po 0xEF00:
    Kod: Python
    Zaloguj się, aby zobaczyć kod

    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Potem właściwy parsing (typu 0x01 i 0x02 z obrazka):
    Kod: Python
    Zaloguj się, aby zobaczyć kod

    Czy to wystarczy, by poprawnie odczytać jakiekolwiek zmienne? Sprawdzamy:
    
    
    ============================================================
    📦 INCOMING ZIGBEE PACKET!
    📍 Device Network Addr: 0x5362
    🎯 Zigbee Cluster ID  : 0xEF00
    📄 Raw Data (Hex)     : 095b02005f18020004000000cd
       -> [Tuya Data] DP ID: 24 | Type: 2 | Value: 205 (Raw Value)
    
    
    

    Sukces! Coś się złapało, i nawet pasuje do wskazanej ramki:
    
    095b
    02 - wersja
    005f - numer sekwencji
    18 - dpID (identyfikator) zmiennej
    02 - typ payload - integer (dpType)
    0004 - rozmiar payload
    000000cd - czterobajtowy payload - 220 
    

    Tak się też składa, że odkodowana liczba, to jest odczyt temperatury podany z dokładnością do 1 miejsca po przecinku, specjalnie przemnożony przez 10 by był typem całkowitym. Zgadza się to z odczytem.
    Pora na finalny test - nagrzewamy czujnik:
    Termostat E25-230B i eksperymenty z obsługą Zigbee w Pythonie przez CC2531
    Działa, oto ostateczne potwierdzenie. Temperatura wzrosła do 24°C a prosty program poprawnie to odczytał.
    
    📦 INCOMING ZIGBEE PACKET!
    📍 Device Network Addr: 0x5362
    🎯 Zigbee Cluster ID  : 0xEF00
    📄 Raw Data (Hex)     : 096502006418020004000000f0
       -> [Tuya Data] DP ID: 24 | Type: 2 | Value: 240 (Raw Value)
    ============================================================
    


    Podsumowując, Zigbee okazało się być znacznie bardziej zrozumiałe niż mogłoby się to na początku wydawać. Oczywiście, tu i tak większość pracy jest wykonywana przez firmware na CC2531, ale i tak nie stoi to na przeszkodzie by samodzielnie obsługiwać nowe urządzenia. Termostat Tuya komunikuje się pakietami bardzo podobnymi do tych, z których korzysta TuyaMCU w urządzeniach z Wi-Fi. Dane są przekazywane w formacie zmiennych o unikalnych identyfikatorach (dpID), typach (od 0x00 do 0x05) i odpowiednio kodowanej zawartość. Temperaturę z dokładnością do jednego miejsca po przecinku przesyłaną jako liczbę całkowitą to ja widziałem już kilka lat temu, nawet w moim firmware mam typ Temperature_div10.
    Pomysł własnego urządzenia obsługującego Zigbee można by rozwinąć, a nawet zrealizować bez komputera, przykładowo na samym ESP32. Spróbuję to pokazać w kolejnym temacie.
    Czy próbowaliście samodzielnie kiedyś obsłużyć urządzenia Zigbee, albo zmieniać im firmware?

    Fajne? Ranking DIY
    Pomogłem? Kup mi kawę.
    O autorze
    p.kaczmarek2
    Moderator Smart Home
    Offline 
    Inżynier programista z wieloletnim doświadczeniem embedded i full stack developer.
    Specjalizuje się w: embedded, Full-Stack Developer
    p.kaczmarek2 napisał 14684 postów o ocenie 12712, pomógł 656 razy. Jest z nami od 2014 roku.
  • REKLAMA
  • #2 21931083
    gulson
    Administrator Systemowy
    Posty: 29415
    Pomógł: 150
    Ocena: 6080
    Ciekawe, czyli można w zasadzie by było stworzyć od podstaw urządzenie Zigbee? Kiedyś komponenty do Zigbee były bardzo drogie.
    Teraz, biorąc pod uwagę koszty i formalności związane z certyfikacją produktów Matter, Zigbee wydaje się nadal bardzo praktycznym rozwiązaniem dla projektów DIY i prototypów?
  • REKLAMA
  • #3 21931092
    p.kaczmarek2
    Moderator Smart Home
    Posty: 14684
    Pomógł: 656
    Ocena: 12712
    Ogólnie to można zrobić własne urządzenie Zigbee, już na forum mieliśmy z tym jakieś eksperymenty w wykonaniu @DeDaMrAz i widziałem jakiś soft do tego, ale w tym temacie bardziej chodzi o to, że można łatwo obsługiwać urządzenie Zigbee tworząc własny soft dla bramki, bo po RF niesione są proste pakiety, tutaj w stylu TuyaMCU. Czyli jakby kontynuować ten wątek naszego eksperta @insmod :
    Konwersja bramek Zigbee WRG1 i TYZS3 do OpenBeken
    To zamiast łączyć się z taką bramką z poziomu Zigbee2MQTT, to można by zrobić 100% własną bramkę-kontroler działającą lokalnie, na tym samym urządzeniu.

    Czyli zamiast stawiać Home Assistant z CC2531, to flashujesz bramkę Tuya i z niej robisz centralkę z własnym firmware, i bezpośrednio na niej robisz np. skrypt że jak jeden włącznik Zigbee zostanie wciśnięty, to inny przekaźnik się przełącza. Bez chmury, bez HA.

    Ciekawie byłoby połączyć to też z tym eksperymentem:
    Malutki broker/serwer MQTT hostowany bezpośrednio na urządzeniu OBK/Beken/ESP32
    Można by zrobić malutką namiastkę HA na ESP (lub Beken lub na innej ze wspieranych platform).
    Pomogłem? Kup mi kawę.
  • REKLAMA
  • #4 21931214
    krzbor
    Poziom 29  
    Posty: 1767
    Pomógł: 41
    Ocena: 1065
    Możesz spróbować czegoś innego - napisanie definicji urządzenia do Z2M. Z tego co czytałem podstawowym zadaniem jest napisanie definicji urządzenia (device definition / converter), czyli mapowania między tym, co urządzenie wysyła/przyjmuje przez ZigBee, a przyjaznymi wartościami w MQTT.
    Na czym to polega krok po kroku (propozycja Claude)
    1. Identyfikacja urządzenia
    Z2M rozpoznaje urządzenie po manufacturerName i modelID (odczytywanych automatycznie przy parowaniu). Jeśli tych danych nie ma w bazie, urządzenie pojawia się jako "unsupported" i trzeba dodać dla niego definicję.
    2. Sprawdzenie, jakie klastry/atrybuty oferuje urządzenie
    Trzeba sprawdzić (np. w logach Z2M z włączonym debugiem albo narzędziem typu zigbee-herdsman) jakie endpointy i klastry (np. genOnOff, genLevelCtrl, msTemperatureMeasurement, manuSpecificXXX dla producentów z własnymi rozszerzeniami) urządzenie eksponuje.
    3. Napisanie definicji (w JS/TS)
    Definicja to obiekt opisujący:

    zigbeeModel / model / vendor / description — identyfikacja,
    fromZigbee — konwertery z urządzenia (odbierany raport/atrybut → wartość JSON w MQTT, np. temperatura, stan przełącznika),
    toZigbee — konwertery do urządzenia (komenda MQTT → odpowiednia komenda ZCL wysyłana do urządzenia),
    exposes — deklaracja, jakie funkcje/encje ma urządzenie (przełącznik, czujnik, jasność, kolor itd.) — to na tej podstawie Home Assistant czy inny system buduje UI,
    opcjonalnie configure — co zrobić przy parowaniu (np. skonfigurować raportowanie atrybutów, bindingi).

    4. Wykorzystanie gotowych konwerterów
    Biblioteka zigbee-herdsman-converters ma mnóstwo gotowych fromZigbee/toZigbee dla standardowych klastrów (on/off, poziom, temperatura, wilgotność, bateria itd.). W wielu przypadkach składasz definicję głównie z gotowych klocków — własny kod piszesz tylko dla nietypowych, producenckich rozszerzeń (manufacturerSpecific klastry).
    5. Testowanie
    Można dodać definicję jako external converter (plik lokalny, bez modyfikowania samego Z2M) i przetestować na żywym urządzeniu — patrzeć w logach, czy stany się poprawnie mapują.
  • #5 21931641
    tesla97
    Poziom 20  
    Posty: 510
    Pomógł: 22
    Ocena: 156
    p.kaczmarek2 napisał:
    Chciałem je sparować z Home Assistant przy użyciu Zigbee2MQTT, ale okazało się, że nie jest wspierane



    Jedno zdanie i przekreśla zastosowanie u dużej większości ludzi z bardziej budżetowymi systemami automatyki domowej.
📢 Słuchaj (AI):
REKLAMA