Jason
Published © MIT

A DIY Zigbee Air Pressure Sensor for My Home Assistant☁️

Using the XIAO ESP32C6, I connect an atmospheric pressure sensor via Zigbee, sending real-time data to Home Assistant for monitoring ☁️.

BeginnerFull instructions provided1 hour1,721
A DIY Zigbee Air Pressure Sensor for My Home Assistant☁️

Things used in this project

Story

Read more

Custom parts and enclosures

box_a

box_b

Code

Arduino Core Code

C/C++
#ifndef ZIGBEE_MODE_ED
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"
#include "Seeed_BME280.h"
#include <Wire.h>
#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

uint8_t HugoUI_Animation_EasyOut(float *a, float *a_trg, uint16_t n) {
  if (*a == *a_trg)
    return 0;

  float cz = fabs(*a - *a_trg);

  if (cz <= 1)
    *a = *a_trg;
  else {
    if (cz < 10)
      n = n * cz * 0.1f;
    if (n < 10)
      n = 10;
    *a += (*a_trg - *a) / (n * 0.1f);
  }
  return 1;
}

uint8_t HugoUI_Animation_EasyIn(float *a, float *a_trg, uint16_t n) {
  if (*a == *a_trg)
    return 0;

  float cz = fabs(*a - *a_trg);
  if (cz <= 1)
    *a = *a_trg;
  else if (cz > 20)
    n = n * 3;
  else if (cz > 15)
    n = n * 2;
  else if (cz > 5)
    n = n * 1;
  if (*a != *a_trg)
    *a += (*a_trg - *a) / (n * 0.1f);
  else
    return 0;
  return 1;
}

void Oled_DrawSlowBitmapResize(int x, int y, const uint8_t *bitmap, int w1, int h1, int w2, int h2) {
  uint8_t color = u8g2.getDrawColor();

  float mw = (float)w2 / w1;
  float mh = (float)h2 / h1;
  uint8_t cmw = ceil(mw);
  uint8_t cmh = ceil(mh);
  int xi, yi, byteWidth = (w1 + 7) / 8;
  for (yi = 0; yi < h1; yi++) {
    for (xi = 0; xi < w1; xi++) {

      if (*(uint8_t *)(bitmap + yi * byteWidth + xi / 8) & (1 << (xi & 7))) 
      {
        u8g2.drawBox(x + xi * mw, y + yi * mh, cmw, cmh);
      } else if (color != 2) {
        u8g2.setDrawColor(0);
        u8g2.drawBox(x + xi * mw, y + yi * mh, cmw, cmh);
        u8g2.setDrawColor(color);
      }
    }
  }
}

const unsigned char gImage_humidity[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xF0,
  0x07, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x7C, 0x3F, 0x00, 0x00, 0x3E, 0x7C, 0x00,
  0x00, 0x1F, 0xF8, 0x00, 0x80, 0x07, 0xF0, 0x01, 0xC0, 0x07, 0xE0, 0x01, 0xC0, 0x03,
  0xC0, 0x03, 0xE0, 0x81, 0x81, 0x07, 0xE0, 0xC1, 0x83, 0x07, 0xE0, 0xD0, 0x03, 0x07,
  0xF0, 0xF8, 0x03, 0x0F, 0xF0, 0xF8, 0x0B, 0x0F, 0xF0, 0xF0, 0x1F, 0x0F, 0xF0, 0xE0,
  0x1F, 0x0F, 0xE0, 0xC0, 0x0F, 0x07, 0xE0, 0xC0, 0x07, 0x07, 0xE0, 0xC1, 0x83, 0x07,
  0xC0, 0xC3, 0xC3, 0x03, 0xC0, 0xC7, 0xE3, 0x03, 0x80, 0x8F, 0xF3, 0x01, 0x00, 0xFF,
  0xFF, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0xC0, 0x03, 0x00,
  0x00, 0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00
};

const unsigned char gImage_homeassistant[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x07, 0x00,
  0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0xFC, 0xBF, 0x07, 0x00, 0xFE, 0xFF, 0x07,
  0x00, 0xFF, 0xFF, 0x07, 0x80, 0xFF, 0xFF, 0x07, 0xC0, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x07,
  0xF0, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFE, 0xF8, 0x1F, 0x7F,
  0x7F, 0xF7, 0xEF, 0xFE, 0x7F, 0xF7, 0xEF, 0xFE, 0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F,
  0xF8, 0xEF, 0xF7, 0x1F, 0xF8, 0xCF, 0xF3, 0x1F, 0xF8, 0x9F, 0xF9, 0x1F, 0xF8, 0x7F, 0xFE, 0x1F,
  0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F,
  0xF8, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};




#define PRESSURE_SENSOR_ENDPOINT_NUMBER 11

uint8_t button = BOOT_PIN;

ZigbeePressureSensor zbPressureSensor = ZigbeePressureSensor(PRESSURE_SENSOR_ENDPOINT_NUMBER);
BME280 bme280;

static float img_a = 4, img_a_trg = 24;
static float img_b = -2, img_b_trg = 24;
static float img_c = -10, img_c_trg = 13;
static float img_d = 5, img_d_trg = 90;
uint16_t pressure_value;

static void pressure_sensor_update(void *arg) {
  static uint32_t timeCounter = 0;
  for (;;) {

    if (!(timeCounter++ % 20)) {
      pressure_value = (uint16_t)(bme280.getPressure() / 100.0);
      Serial.printf("Updating pressure sensor value to %d hPa\r\n", pressure_value);
      zbPressureSensor.setPressure(pressure_value);
    }

    delay(3000);
  }
}

void setup() {
  Serial.begin(115200);
  u8g2.begin();

  pinMode(WIFI_ENABLE, OUTPUT);  
  digitalWrite(WIFI_ENABLE, LOW);

  delay(100);

  pinMode(WIFI_ANT_CONFIG, OUTPUT);   
  digitalWrite(WIFI_ANT_CONFIG, LOW); 


  if (!bme280.init()) {
    Serial.println("Device error!");
  }

  pinMode(button, INPUT_PULLUP);


  zbPressureSensor.setManufacturerAndModel("Espressif", "ZigbeePressureSensor");


  zbPressureSensor.setMinMaxValue(0, 10000);


  zbPressureSensor.setTolerance(1);


  Zigbee.addEndpoint(&zbPressureSensor);

  Serial.println("Starting Zigbee...");

  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB08_tr);
  u8g2.drawStr(0, 30, "Connecting to Zigbee...");
  u8g2.sendBuffer();


  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  } else {
    Serial.println("Zigbee started successfully!");
  }
  Serial.println("Connecting to network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(100);
  }
  Serial.println();

  u8g2.clearBuffer();
  u8g2.drawStr(0, 30, "Successfully connect");
  u8g2.drawStr(0, 50, "Zigbee network!");
  u8g2.sendBuffer();
  Serial.println();

  delay(5000);


  xTaskCreate(pressure_sensor_update, "pressure_sensor_update", 2048, NULL, 10, NULL);


  zbPressureSensor.setReporting(0, 30, 1);
}

void loop() {

  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB08_tr);

  u8g2.drawXBM(0, 0, 32, 32, gImage_homeassistant);

  u8g2.drawStr(43, img_b, " Air Monitor");

  u8g2.setDrawColor(2);
  u8g2.drawRBox(36, img_c, img_d, 15, 1);
  u8g2.setDrawColor(1);

  u8g2.drawStr(0, 45, "Pressure: ");
  u8g2.setCursor(50, 45);
  u8g2.print(pressure_value);
  u8g2.drawStr(80, 45, "hPa");




  if (img_a == img_a_trg) {
    if (img_a == 4) {
      img_a_trg = 24;
    } else if (img_a == 24)
      img_a_trg = 4;
  }

  HugoUI_Animation_EasyOut(&img_b, &img_b_trg, 100);
  HugoUI_Animation_EasyIn(&img_a, &img_a_trg, 115);
  HugoUI_Animation_EasyOut(&img_c, &img_c_trg, 100);
  HugoUI_Animation_EasyOut(&img_d, &img_d_trg, 100);

  Oled_DrawSlowBitmapResize(118 - img_a / 2, 50 - img_a / 4, gImage_humidity, 32, 32, img_a, img_a);

  u8g2.sendBuffer();


  if (digitalRead(button) == LOW) {

    delay(100);
    int startTime = millis();
    while (digitalRead(button) == LOW) {
      delay(50);
      if ((millis() - startTime) > 3000) {

        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
        delay(1000);
        Zigbee.factoryReset();
      }
    }
    zbPressureSensor.report();
  }
}

Credits

Jason
2 projects • 5 followers
I'm an Application Engineer specializing in smart home solutions with ESP32. I enjoy developing demos.
Contact

Comments

Please log in or sign up to comment.