main.cpp
// src/main.cpp
#ifndef ZIGBEE_MODE_ED
#error "Build flag -D ZIGBEE_MODE_ED missing"
#endif
 
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_BME680.h>
#include <Adafruit_NeoPixel.h>
#include <cmath>
#include "Zigbee.h"              // part of Arduino-ESP32 core Zigbee library
 
constexpr uint8_t SDA_PIN = 21;
constexpr uint8_t SCL_PIN = 22;
constexpr uint8_t BOOT = 9;
constexpr uint8_t NEOPIXEL_PIN = 3;
constexpr uint8_t NEOPIXEL_COUNT = 1;
constexpr uint8_t BME680_ADDRESS = 0x76;
constexpr uint16_t SENSOR_PERIOD_MS = 5000;
constexpr uint32_t BOOT_HOLD_MS = 3000;
constexpr uint32_t IDENTIFY_DURATION_MS = 5000;
constexpr uint32_t IDENTIFY_BLINK_INTERVAL_MS = 200;
 
// Use endpoint 1 for simplicity
ZigbeeTempSensor tempEp(1);
ZigbeePressureSensor pressureEp(2);
Adafruit_BME680 bme;
Adafruit_NeoPixel statusPixel(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
static bool bmeReady = false;
static volatile bool identifyBlinkActive = false;
static volatile bool identifyBlinkReset = false;
static volatile uint32_t identifyBlinkDeadline = 0;
 
static void sensor_task(void *arg) {
  bool bmeWarned = false;
  for (;;) {
    if (bmeReady) {
      if (bme.performReading()) {
        float tC = bme.temperature;
        float humidity = bme.humidity;
        float pressure_hPa = bme.pressure / 100.0f;
 
        tempEp.setTemperature(tC);
        tempEp.setHumidity(humidity);
        tempEp.report();                     // report temp (and humidity)
 
        int16_t pressureValue = static_cast<int16_t>(roundf(pressure_hPa));
        pressureEp.setPressure(pressureValue);
        pressureEp.report();
 
        Serial.printf("Env: %.2f °C, %.2f %%RH, %.2f hPa\n", tC, humidity, pressure_hPa);
      } else {
        Serial.println("BME680 read failed");
      }
    } else {
      if (!bmeWarned) {
        Serial.println("BME680 not initialized");
        bmeWarned = true;
      }
    }
    vTaskDelay(pdMS_TO_TICKS(SENSOR_PERIOD_MS));
  }
}
 
static void handleIdentifyCallback(uint16_t seconds) {
  if (seconds == 0) {
    identifyBlinkActive = false;
    identifyBlinkReset = true;
    return;
  }
  identifyBlinkDeadline = millis() + IDENTIFY_DURATION_MS;
  identifyBlinkReset = true;
  identifyBlinkActive = true;
}
 
void setup() {
  Serial.begin(115200);
  pinMode(BOOT, INPUT_PULLUP);
  Wire.begin(SDA_PIN, SCL_PIN);
  statusPixel.begin();
  statusPixel.setBrightness(32);
  statusPixel.clear();
  statusPixel.show();
 
  if (bme.begin(BME680_ADDRESS)) {
    bmeReady = true;
    bme.setTemperatureOversampling(BME680_OS_8X);
    bme.setHumidityOversampling(BME680_OS_2X);
    bme.setPressureOversampling(BME680_OS_4X);
    bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
    bme.setGasHeater(0, 0); // disable gas heater to reduce power draw
    Serial.println("BME680 initialized");
  } else {
    Serial.println("BME680 not found");
  }
 
  // (Optional) identify string shown by many hubs
  tempEp.setManufacturerAndModel("Sparrow", "C6-Temp");
  pressureEp.setManufacturerAndModel("Sparrow", "C6-Pressure");
 
  // Reasonable range/tolerance and reporting policy
  tempEp.setMinMaxValue(-40, 125);
  tempEp.setTolerance(0.1);                  // 0.1 °C tolerance
  tempEp.addHumiditySensor(0.0f, 100.0f, 1.0f);
  pressureEp.setMinMaxValue(300, 1100);
  pressureEp.setTolerance(1);
  tempEp.onIdentify(handleIdentifyCallback);
  pressureEp.onIdentify(handleIdentifyCallback);
 
  // Register endpoint and start Zigbee stack as End Device
  Zigbee.addEndpoint(&tempEp);
  Zigbee.addEndpoint(&pressureEp);
  Serial.println("Starting Zigbee…");
  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start, restarting…");
    delay(1000);
    ESP.restart();
  }
 
  Serial.print("Joining network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(200);
  }
  Serial.println("\nJoined!");
 
  // min=0, max=30 → periodic every 30s or when delta triggers (delta in 0.1°C units here)
  tempEp.setReporting(0, 30, 1);
  tempEp.setHumidityReporting(0, 60, 1.0f);
  pressureEp.setReporting(0, 60, 1);
 
  // Start periodic temperature task
  xTaskCreate(sensor_task, "sensor_task", 4096, nullptr, 10, nullptr);
}
 
void loop() {
  static uint32_t lastBlinkToggle = 0;
  static bool pixelOn = false;
  static uint32_t bootPressStart = 0;
  static bool bootResetIssued = false;
 
  if (identifyBlinkReset) {
    identifyBlinkReset = false;
    lastBlinkToggle = 0;
    pixelOn = false;
    statusPixel.clear();
    statusPixel.show();
  }
 
  bool blinkActive = identifyBlinkActive;
  if (blinkActive) {
    uint32_t now = millis();
    if ((int32_t)(identifyBlinkDeadline - now) <= 0) {
      identifyBlinkActive = false;
      blinkActive = false;
    } else if (now - lastBlinkToggle >= IDENTIFY_BLINK_INTERVAL_MS) {
      lastBlinkToggle = now;
      pixelOn = !pixelOn;
      if (pixelOn) {
        statusPixel.setPixelColor(0, statusPixel.Color(0, 0, 255));
      } else {
        statusPixel.clear();
      }
      statusPixel.show();
    }
  }
 
  if (!blinkActive && pixelOn) {
    pixelOn = false;
    statusPixel.clear();
    statusPixel.show();
  }
 
  // Hold BOOT button ~3s to factory-reset Zigbee if you need to re-pair
  bool bootLow = digitalRead(BOOT) == LOW;
  if (bootLow) {
    uint32_t now = millis();
    if (bootPressStart == 0) {
      bootPressStart = now;
    } else if (!bootResetIssued && (now - bootPressStart) >= BOOT_HOLD_MS) {
      bootResetIssued = true;
      identifyBlinkActive = false;
      identifyBlinkReset = true;
      statusPixel.clear();
      statusPixel.show();
      Serial.println("Factory reset Zigbee…");
      Zigbee.factoryReset(true); // resets and restarts
    }
  } else {
    bootPressStart = 0;
    bootResetIssued = false;
  }
  delay(50);
}
iothings/laboratoare/2025_code/lab5_1.txt · Last modified: 2025/10/22 10:00 by dan.tudose
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0