Всем привет, давно хотелось соорудить свое оконечное устройство на Zigbee, и оказалось это не сильно сложно. Тем более что основа в виде Home Assistant на Raspberry Pi 4 со свистком Zigbee 3 SONOFF USB Dongle Plus-E есть и работает. Правда до этого в нем были только фабричные zigbee устройства, в основном Aqara. Итак погнали.

Что нам нужно кроме вышеуказанного

  1. Инфракрасный датчик движения HC-SR501. Стоит рублей 200 на маркетплейсах, я не покупал, у меня был, куплен лет 8 назад и раньше стоял в паре с обычной релюхой и рулил светом в коридоре.

  2. ESP32-H2 SuperMini, 650 рублей на маркетплейсах, но быстро и в 3 раза дешевле на ali, но медленнее

Устанавливаем в Tools вот такие настройки

Arduino IDE, настройки в Tools
Arduino IDE, настройки в 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

Если вы все ��делали правильно то должно стать так

Такое должно появится в Zigbee2MQTT
Такое должно появится в Zigbee2MQTT
А внутри самого устройство должно быть так. И при махании рукой перед сенсором верхний статус должен менятся.
А внутри самого устройство должно быть так. И при махании рукой перед сенсором верхний статус должен менятся.
Помахал рукой + чип поработал немного, температура поднялась. У меня температура во время работы прыгает между 30.8 и 31.8
Помахал рукой + чип поработал немного, температура поднялась. У меня температура во время работы прыгает между 30.8 и 31.8

Вы скажите, а нафига это все? датчик движения 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 и выбор пока маленький.