Всем привет, давно хотелось соорудить свое оконечное устройство на Zigbee, и оказалось это не сильно сложно. Тем более что основа в виде Home Assistant на Raspberry Pi 4 со свистком Zigbee 3 SONOFF USB Dongle Plus-E есть и работает. Правда до этого в нем были только фабричные zigbee устройства, в основном Aqara. Итак погнали.
Что нам нужно кроме вышеуказанного
Инфракрасный датчик движения HC-SR501. Стоит рублей 200 на маркетплейсах, я не покупал, у меня был, куплен лет 8 назад и раньше стоял в паре с обычной релюхой и рулил светом в коридоре.
ESP32-H2 SuperMini, 650 рублей на маркетплейсах, но быстро и в 3 раза дешевле на ali, но медленнее
Устанавливаем в Tools вот такие настройки

Коннектим плату и заливаем такой скетч
Скрытый текст
#include <FastLED.h> #include "Zigbee.h" #define LED_PIN 8 // Most ESP32 Mini boards #define NUM_LEDS 1 #define LED_TYPE WS2812B #define COLOR_ORDER GRB #ifndef ZIGBEE_MODE_ED #error "Zigbee end device mode is not selected in Tools->Zigbee mode" #endif CRGB leds[NUM_LEDS]; /* Zigbee occupancy sensor configuration */ #define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 #define TEMP_SENSOR_ENDPOINT_NUMBER 11 uint8_t button = BOOT_PIN; uint8_t sensor_pin = 10; ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); ZigbeeTempSensor zbTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); void setup() { Serial.begin(115200); FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS); FastLED.setBrightness(50); // Init button + PIR sensor pinMode(button, INPUT_PULLUP); pinMode(sensor_pin, INPUT); // Optional: set Zigbee device name and model zbOccupancySensor.setManufacturerAndModel("ESP32", "ESP32_Occupancy"); zbTempSensor.setManufacturerAndModel("ESP32", "ESP32_Occupancy"); // Add endpoint to Zigbee Core Zigbee.addEndpoint(&zbOccupancySensor); Zigbee.addEndpoint(&zbTempSensor); zbTempSensor.setMinMaxValue(10, 80); zbTempSensor.setDefaultValue(25.0); zbTempSensor.setTolerance(0.5); // 0.5°C Serial.println("Starting Zigbee..."); // When all EPs are registered, start Zigbee in End Device mode if (!Zigbee.begin()) { Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); ESP.restart(); } else { Serial.println("Zigbee started successfully!"); leds[0] = CRGB::Green; FastLED.show(); } Serial.println("Connecting to network"); while (!Zigbee.connected()) { Serial.print("."); delay(100); } Serial.println(); zbTempSensor.setReporting( 10, // min interval seconds 300, // max interval seconds 0.5 // delta °C (минимальное изменение для репорта) ); } void loop() { // Checking PIR sensor for occupancy change static bool occupancy = false; if (digitalRead(sensor_pin) == HIGH && !occupancy) { // Update occupancy sensor value zbOccupancySensor.setOccupancy(true); zbOccupancySensor.report(); occupancy = true; leds[0] = CRGB::Red; FastLED.show(); } else if (digitalRead(sensor_pin) == LOW && occupancy) { zbOccupancySensor.setOccupancy(false); zbOccupancySensor.report(); occupancy = false; leds[0] = CRGB::Green; FastLED.show(); } static uint32_t lastTempMs = 0; if (millis() - lastTempMs > 60000) { lastTempMs = millis(); float t = temperatureRead(); // °C (примерно) zbTempSensor.setTemperature(t); // или setTemperatureValue(...) Serial.printf("Chip temp: %.2f C\n", t); } // Checking button for factory reset if (digitalRead(button) == LOW) { // Push button pressed // Key debounce handling delay(100); int startTime = millis(); while (digitalRead(button) == LOW) { delay(50); if ((millis() - startTime) > 3000) { // If key pressed for more than 3secs, factory reset Zigbee and reboot Serial.println("Resetting Zigbee to factory and rebooting in 1s."); delay(1000); Zigbee.factoryReset(); } } } delay(100); }
Кроме работы в zigbee как датчика присутствия скетч еще выдает температуру платы, а так же меняет цвет светодида на плате, при обнаружении движения он становится красным, а при не обнаружении - зеленым.
Коннектим плату к сенсору: 3v3<->Vcc, GND<->GND, 10<->OUT

Собственно если вы сделали все правильно, то при махании рукой перед сенсором светодиод должен загораться красным, а через какое-то время, если ничего не происходит перед ним - зеленым. Чувствительность и длительности работы сенсора после определения движения выполняется регулировочными резисторами на сенсоре. На фото они спрятались под провода.
Так как у нас тут мультисенсор с температурой и движением надо подкрутить Zigbee2MQTT. Я для таких редактирований пользуюсь Studio Code Server. Создаем файл zigbee2mqtt/external_converters/esp32_occupancy.js cо следующим содержимым
Скрытый текст
const fz = require('zigbee-herdsman-converters/converters/fromZigbee'); const exposes = require('zigbee-herdsman-converters/lib/exposes'); const e = exposes.presets; module.exports = [{ fingerprint: [{modelID: 'ESP32_Occupancy', manufacturerName: 'ESP32'}], model: 'ESP32_Occupancy', vendor: 'ESP32', description: 'ESP32 occupancy + chip temperature', fromZigbee: [fz.occupancy, fz.temperature], toZigbee: [], exposes: [ e.occupancy('occ'), e.temperature().withEndpoint('temp'), ], endpoint: (device) => ({ occ: 10, temp: 11, }), meta: {multiEndpoint: true}, }];
Перегружаем Zigbee2MQTT, жмем в его интерфейсе Permit Join, и включаем esp32
Если вы все сделали правильно то должно стать так



Вы скажите, а нафига это все? датчик движения Aqara на Zigbee стоит немного дороже, но при этом имеет меньший размер и живет на одной батарейке год. И будете правы. Но таким же образом в HA можно рулить другими вещами которые изначально не умеют Zigbee.
Не переключайтесь, в следующей серии, если все получится, планирую описать сетап HomeAssistant (Matter, OpenThread )<-> ESP32-C5 <-> 802.15.4 with Thread <-> ESP32-H2 (как сенсор). Планируемые бенефиты - потрогать OpenThread и Thread через 802.15.4, а значит вполне себе реальную ipv6 mesh сетку. Так же, кажется, что практического смысла будет больше, датчики с Thread раза в 3 дороже Zigbee и выбор пока маленький.
