commit 59defedb8e2a3d0361cde3f05781008a45a62a69 Author: Bora Date: Sun Dec 28 20:38:58 2025 +0100 Initial commit of existing code diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c1bef2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.hex +build/ +.DS_Store diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/.theia/launch.json b/DFRobot_mmWave_Radar_ESP32_tes2/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/DFRobot_mmWave_Radar_ESP32_tes2.ino b/DFRobot_mmWave_Radar_ESP32_tes2/DFRobot_mmWave_Radar_ESP32_tes2.ino new file mode 100644 index 0000000..14b4802 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/DFRobot_mmWave_Radar_ESP32_tes2.ino @@ -0,0 +1,53 @@ +#include + +HardwareSerial mySerial(1); + +void sendPacket(const uint8_t *packet, size_t length) { + Serial.print("TX: "); + for (size_t i = 0; i < length; i++) { + Serial.printf("%02X ", packet[i]); + mySerial.write(packet[i]); + } + Serial.println(); + mySerial.flush(); +} + +void setup() { + Serial.begin(115200); + delay(500); + Serial.println("Starting HS2xx3A test (Binary mode only)..."); + + // RX=17, TX=16 for ESP32-C6, 115200 baud + mySerial.begin(115200, SERIAL_8N1, 17, 16); + + delay(500); + + // Try turning LED OFF + // const uint8_t ledOffPacket[] = { 0x53, 0x59, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // Serial.println("Turning LED OFF..."); + // sendPacket(ledOffPacket, sizeof(ledOffPacket)); +} + +void loop() { + // Read data from sensor + while (mySerial.available()) { + String line = mySerial.readStringUntil('\n'); + Serial.print("RX: "); + Serial.println(line); + + if (line.startsWith("$JYBSS")) { + if (line.indexOf(",1") >= 0) { + Serial.println("Presence Detected: YES"); + } else { + Serial.println("Presence Detected: NO"); + } + } + if (line.startsWith("$JYRPO")) { + if (line.indexOf(",1") >= 0) { + Serial.println("JYRPO Detected: YES"); + } else { + Serial.println("JYRPO Detected: NO"); + } + } + } +} diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/LeapmmwRadar.cpp b/DFRobot_mmWave_Radar_ESP32_tes2/LeapmmwRadar.cpp new file mode 100644 index 0000000..5ccfcf3 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/LeapmmwRadar.cpp @@ -0,0 +1,67 @@ +#include "LeapmmwRadar.h" + +LeapmmwRadar::LeapmmwRadar(HardwareSerial* serial, Stream* debugStream) { + _serial = serial; + _debug = debugStream; +} + +void LeapmmwRadar::begin(uint32_t baudrate) { + _serial->begin(baudrate); + if (_debug) _debug->println("[Leapmmw] Serial started"); +} + +// LED ON command (factory: 0x55 0xAA 0x03 0x03 0x01 0x00) +void LeapmmwRadar::ledOn() { + const uint8_t cmd[] = { 0x55, 0xAA, 0x03, 0x03, 0x01, 0x00 }; + sendCommand(cmd, sizeof(cmd)); +} + +// LED OFF command (factory: 0x55 0xAA 0x03 0x03 0x00 0x00) +void LeapmmwRadar::ledOff() { + const uint8_t cmd[] = { 0x55, 0xAA, 0x03, 0x03, 0x00, 0x00 }; + sendCommand(cmd, sizeof(cmd)); +} + +void LeapmmwRadar::sendCommand(const uint8_t* cmd, size_t len) { + if (_debug) { + _debug->print("[TX] "); + for (size_t i = 0; i < len; i++) { + _debug->printf("0x%02X ", cmd[i]); + } + _debug->println(); + } + _serial->write(cmd, len); +} + +// Parse presence detection from response +int LeapmmwRadar::readPresence() { + static uint8_t buffer[32]; + static size_t index = 0; + + while (_serial->available()) { + uint8_t b = _serial->read(); + if (_debug) { + _debug->printf("[RX] 0x%02X\n", b); + } + + if (index == 0 && b != 0x55) continue; + if (index == 1 && b != 0xAA) { + index = 0; + continue; + } + + buffer[index++] = b; + + // Minimum valid frame: 8 bytes for presence data + if (index >= 8) { + if (buffer[0] == 0x55 && buffer[1] == 0xAA && buffer[2] == 0x03 && buffer[3] == 0x01) { + int presence = buffer[4]; // 0x00 = no movement, 0x01 = movement + index = 0; + return presence; + } else { + index = 0; // unrecognized frame + } + } + } + return -1; // no new data +} diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/LeapmmwRadar.h b/DFRobot_mmWave_Radar_ESP32_tes2/LeapmmwRadar.h new file mode 100644 index 0000000..5288088 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/LeapmmwRadar.h @@ -0,0 +1,20 @@ +#ifndef LEAPMMW_RADAR_H +#define LEAPMMW_RADAR_H + +#include + +class LeapmmwRadar { +public: + LeapmmwRadar(HardwareSerial* serial, Stream* debugStream = nullptr); + void begin(uint32_t baudrate = 115200); + void ledOn(); + void ledOff(); + int readPresence(); // returns 1 = movement, 0 = no movement, -1 = nothing new + +private: + HardwareSerial* _serial; + Stream* _debug; + void sendCommand(const uint8_t* cmd, size_t len); +}; + +#endif diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/hs2xx3a.cpp b/DFRobot_mmWave_Radar_ESP32_tes2/hs2xx3a.cpp new file mode 100644 index 0000000..d321293 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/hs2xx3a.cpp @@ -0,0 +1,63 @@ + +// hs2xx3a.cpp +#include "hs2xx3a.h" + +HS2xx3A::HS2xx3A(HardwareSerial &serial) : serial_(serial) {} + +void HS2xx3A::begin() { + serial_.begin(115200); +} + +void HS2xx3A::sendCommand(const uint8_t *cmd, size_t len) { + Serial.print("TX: "); + for (size_t i = 0; i < len; ++i) { + Serial.printf("%02X ", cmd[i]); + } + Serial.println(); + + serial_.write(cmd, len); + serial_.flush(); +} + +bool HS2xx3A::readResponse(uint8_t *buffer, size_t expected_len) { + unsigned long start = millis(); + size_t index = 0; + while (millis() - start < 200 && index < expected_len) { + if (serial_.available()) { + buffer[index++] = serial_.read(); + } + } + + if (index == expected_len) { + Serial.print("RX: "); + for (size_t i = 0; i < expected_len; ++i) { + Serial.printf("%02X ", buffer[i]); + } + Serial.println(); + return true; + } + Serial.println("RX Timeout or incomplete response"); + return false; +} + +void HS2xx3A::setLED(bool enable) { + const uint8_t cmd_on[] = {0x53, 0x59, 0x0A, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00}; + const uint8_t cmd_off[] = {0x53, 0x59, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; + sendCommand(enable ? cmd_on : cmd_off, sizeof(cmd_on)); + // Optional: read back ACK if needed + uint8_t buffer[8]; + readResponse(buffer, 8); +} + +bool HS2xx3A::checkForPresence() { + const uint8_t cmd_presence[] = {0x53, 0x59, 0x01, 0x00}; + sendCommand(cmd_presence, sizeof(cmd_presence)); + uint8_t response[8] = {0}; + if (readResponse(response, 8)) { + // Validate packet header + if (response[0] == 0x53 && response[1] == 0x59 && response[2] == 0x01) { + return response[4] == 1; // response[4] == 1 means presence detected + } + } + return false; +} diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/hs2xx3a.h b/DFRobot_mmWave_Radar_ESP32_tes2/hs2xx3a.h new file mode 100644 index 0000000..11b64f0 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/hs2xx3a.h @@ -0,0 +1,17 @@ +// hs2xx3a.h +#pragma once +#include + +class HS2xx3A { +public: + HS2xx3A(HardwareSerial &serial); + + void begin(); + bool checkForPresence(); + void setLED(bool enable); + +private: + HardwareSerial &serial_; + void sendCommand(const uint8_t *cmd, size_t len); + bool readResponse(uint8_t *buffer, size_t expected_len); +}; \ No newline at end of file diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/mmWaveRadarCustom.cpp b/DFRobot_mmWave_Radar_ESP32_tes2/mmWaveRadarCustom.cpp new file mode 100644 index 0000000..1d1e8c1 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/mmWaveRadarCustom.cpp @@ -0,0 +1,64 @@ +#include "mmWaveRadarCustom.h" + +mmWaveRadarCustom::mmWaveRadarCustom(HardwareSerial* serial, Stream* debugStream) { + _serial = serial; + _debug = debugStream; +} + +void mmWaveRadarCustom::begin(uint32_t baudrate) { + _serial->begin(baudrate); + if (_debug) _debug->println("[Radar] Serial started"); +} + +void mmWaveRadarCustom::ledOn() { + const uint8_t cmd[] = { 0xFD, 0xFC, 0x05, 0x00, 0x01, 0x01, 0x00 }; + sendCommand(cmd, sizeof(cmd)); +} + +void mmWaveRadarCustom::ledOff() { + const uint8_t cmd[] = { 0xFD, 0xFC, 0x05, 0x00, 0x01, 0x00, 0x00 }; + sendCommand(cmd, sizeof(cmd)); +} + +void mmWaveRadarCustom::sendCommand(const uint8_t* cmd, size_t len) { + if (_debug) { + _debug->print("[Radar] TX: "); + for (size_t i = 0; i < len; i++) { + _debug->print("0x"); + if (cmd[i] < 0x10) _debug->print("0"); + _debug->print(cmd[i], HEX); + _debug->print(" "); + } + _debug->println(); + } + _serial->write(cmd, len); +} + +int mmWaveRadarCustom::readPresence() { + if (_serial->available()) { + uint8_t header = _serial->read(); + if (header == 0xAA) { + delay(2); // wait for more bytes + if (_serial->available() >= 4) { + uint8_t type = _serial->read(); // e.g., 0x01 + uint8_t len = _serial->read(); // e.g., 0x01 + uint8_t data = _serial->read(); // 0x00 = no motion, 0x01 = motion + uint8_t checksum = _serial->read(); // discard or validate + + if (_debug) { + _debug->print("[Radar] RX: 0xAA 0x"); + _debug->print(type, HEX); + _debug->print(" 0x"); + _debug->print(len, HEX); + _debug->print(" 0x"); + _debug->print(data, HEX); + _debug->print(" 0x"); + _debug->println(checksum, HEX); + } + + return (data == 0x01) ? 1 : 0; + } + } + } + return -1; // nothing to read +} diff --git a/DFRobot_mmWave_Radar_ESP32_tes2/mmWaveRadarCustom.h b/DFRobot_mmWave_Radar_ESP32_tes2/mmWaveRadarCustom.h new file mode 100644 index 0000000..4af78bf --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_tes2/mmWaveRadarCustom.h @@ -0,0 +1,20 @@ +#ifndef MMWAVE_RADAR_CUSTOM_H +#define MMWAVE_RADAR_CUSTOM_H + +#include + +class mmWaveRadarCustom { +public: + mmWaveRadarCustom(HardwareSerial* serial, Stream* debugStream = nullptr); + void begin(uint32_t baudrate = 115200); + void ledOn(); + void ledOff(); + int readPresence(); // 1 = movement, 0 = no movement + +private: + HardwareSerial* _serial; + Stream* _debug; + void sendCommand(const uint8_t* cmd, size_t len); +}; + +#endif diff --git a/DFRobot_mmWave_Radar_ESP32_test1/DFRobot_mmWave_Radar_ESP32_test1.ino b/DFRobot_mmWave_Radar_ESP32_test1/DFRobot_mmWave_Radar_ESP32_test1.ino new file mode 100644 index 0000000..5574225 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_test1/DFRobot_mmWave_Radar_ESP32_test1.ino @@ -0,0 +1,71 @@ +/* + +https://wiki.dfrobot.com/mmWave_Radar_Human_Presence_Detection_SKU_SEN0395#Tutorial%20for%20FireBeetle%20ESP32 + +https://www.reddit.com/r/homeassistant/comments/y0bk16/how_to_reliable_room_presence_sensor_using/ + +SEN0395 (Leapmmw HS2xx3A series) +https://community.home-assistant.io/t/mmwave-presence-detection-esphome-style/382778 +https://github.com/hjmcnew/esphome-hs2xx3a-custom-component/tree/main + + +It's just a rebranded LeapMMW +https://www.reddit.com/r/homeassistant/comments/wvug41/any_alternative_to_the_dfrobot_sen0395_mmwave/ + + + + +https://www.youtube.com/watch?v=Viqvx7hMMJs +https://www.youtube.com/watch?v=pTYclnk9W4M +https://www.youtube.com/watch?v=uXrYwfS0Pqw + + +*/ + + + +/*! + @file DFRobot_mmWave_Radar.ino + @ Read whether there is people or object moving in the detection range of the sensor. + @ The sensor detection range and output delay time can be configured. Also you can restore the sensor to factory default settings. + @n Experimental phenomenon: When the sensor starts successfully, 0 or 1 will be printed on the serial monitor. + @ 0 means that there is no human or object moving in sensing area, 1 means the oppposite. + @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) + @licence The MIT License (MIT) + @author [huyujie](yujie.hu@dfrobot.com) + @version V1.0 + @date 2020-3-25 + @https://github.com/DFRobot +*/ + + +#include + +HardwareSerial mySerial(1); +DFRobot_mmWave_Radar sensor(&mySerial); + +int ledPin = 0; + +void setup() +{ + Serial.begin(115200); + delay(100); + Serial.println("Tutoduino Zigbee temperature sensor start!"); + + mySerial.begin(115200, SERIAL_8N1, 17, 16);//RX,TX + pinMode(ledPin, OUTPUT); + + sensor.factoryReset(); //Restore to the factory settings + sensor.DetRangeCfg(0, 1); //The detection range is as far as 9m + sensor.OutputLatency(0, 0); + +} + +void loop() +{ + int val = sensor.readPresenceDetection(); + digitalWrite(ledPin, val); + Serial.println(val); + + +} diff --git a/DFRobot_mmWave_Radar_ESP32_test3/.theia/launch.json b/DFRobot_mmWave_Radar_ESP32_test3/.theia/launch.json new file mode 100644 index 0000000..9a49ac9 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_test3/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/DFRobot_mmWave_Radar_ESP32_test3/DFRobot_mmWave_Radar_ESP32_test3.ino b/DFRobot_mmWave_Radar_ESP32_test3/DFRobot_mmWave_Radar_ESP32_test3.ino new file mode 100644 index 0000000..ba4abb3 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_test3/DFRobot_mmWave_Radar_ESP32_test3.ino @@ -0,0 +1,167 @@ +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX + +HardwareSerial mmWaveSerial(1); // UART2 + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + + +void setRange(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setRange 0 3"); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setSensitivity(int sensitivity){ + Serial.println("setSensitivity"); + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setSensitivity " + String(sensitivity)); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setLatency(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setLatency 0.5 1"); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setLedMode(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setLedMode 1 1"); // turn off LED + // mmWaveSerial.println("setLedMode 1 0"); // turn on LED + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setUartOutput(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setUartOutput 2 1 1 2"); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void turnOnSensor(){ + Serial.println("turnOnSensor"); + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setUartOutput 1 0"); + delay(20); + mmWaveSerial.println("setUartOutput 2 1 1 2"); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void readOutput(){ + String line = mmWaveSerial.readStringUntil('\n'); + Serial.println(""); + Serial.print("RX: "); + Serial.println(line); + + if (line.startsWith("$JYBSS")) { + if (line.indexOf(",1") >= 0) { + Serial.println("Presence Detected: YES"); + } else { + Serial.println("Presence Detected: NO"); + } + } +} + + + + +void setup() { + + Serial.println(" -------------------------- Starting mmWave Presence + Distance --------------------------"); + + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + + delay(1000); // Give sensor time to boot + + // turnOnSensor(); + + delay(1000); // Give sensor time to boot + + setSensitivity(3); + + setUartOutput(); + + + delay(200); +} + + +void loop() { + for (int i = 0; i < numCommands; i++) { + const char* cmd = commands[i]; + + // Send command string via UART + mmWaveSerial.println(cmd); + Serial.println(""); + Serial.print("Sent: "); + Serial.println(cmd); + + unsigned long startTime = millis(); + // Wait for 1 second while reading any available response + while (millis() - startTime < 1000) { + if (mmWaveSerial.available()) { + char c = mmWaveSerial.read(); + Serial.write(c); // Print response to Serial Monitor + } + } + + readOutput(); + + delay(10); // small delay before next command (optional) + } +} + + diff --git a/DFRobot_mmWave_Radar_ESP32_test4/.theia/launch.json b/DFRobot_mmWave_Radar_ESP32_test4/.theia/launch.json new file mode 100644 index 0000000..9a49ac9 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_test4/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/DFRobot_mmWave_Radar_ESP32_test4/DFRobot_mmWave_Radar_ESP32_test4.ino b/DFRobot_mmWave_Radar_ESP32_test4/DFRobot_mmWave_Radar_ESP32_test4.ino new file mode 100644 index 0000000..943a0d2 --- /dev/null +++ b/DFRobot_mmWave_Radar_ESP32_test4/DFRobot_mmWave_Radar_ESP32_test4.ino @@ -0,0 +1,333 @@ +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX + +HardwareSerial mmWaveSerial(1); // UART2 + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + +void setRange(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setRange 0 3"); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setSensitivity(int sensitivity){ + Serial.println("setSensitivity"); + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setSensitivity " + String(sensitivity)); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); + Serial.println("setSensitivity finished"); +} + +void setLatency(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setLatency 0.5 1"); + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setLedMode(){ + mmWaveSerial.println("sensorStop"); + delay(20); + mmWaveSerial.println("setLedMode 1 1"); // turn off LED + // mmWaveSerial.println("setLedMode 1 0"); // turn on LED + delay(20); + mmWaveSerial.println("saveConfig"); + delay(20); + mmWaveSerial.println("sensorStart"); + delay(20); +} + +void setUartOutput(){ + // setUartOutput [ ] + // Parameter Description + // par1 Data/Message Type: + // 1 = Detection result ($JYBSS) + // 2 = Point cloud target ($JYRPO) + // par2 Enable/Disable Output: + // 0 = Disable this message type + // 1 = Enable this message type + // par3 Output Trigger Mode: + // 0 = Periodic output based on par4 + // 1 = Output immediately when data changes, otherwise output per par4 + // par4 Output Interval or Passive Mode Trigger: + // 0.025–1500 = Time interval (seconds) for active output + // >1500 = Passive mode (no auto-output; only on getOutput command) + // Note: If par3 and par4 are omitted, only par1 and par2 will be set. + + // $JYBSS,,,,* + // Parameter Description + // par1 Detection result: + // 0 = No presence + // 1 = Presence detected (includes still, motion, micro-motion) + // par2 Placeholder (reserved, empty space) + // par3 Placeholder (reserved, empty space) + // par4 Placeholder (reserved, empty space) + // $JYBSS,1, , ,* → Human presence detected + // $JYBSS,0, , ,* → No presence detected + + // $JYRPO,,,,,,,* + // Parameter Description + // par1 Total number of detected targets (1–8) + // par2 Current target index (1 to par1) + // par3 Distance of current target (in meters) + // par4 Placeholder (reserved, empty space) + // par5 Signal-to-noise ratio (SNR) of the target (float, higher = more reliable) + // par6 Placeholder (reserved, empty space) + // par7 Placeholder (reserved, empty space) + // $JYRPO,4,1,0.882, ,1.562, ,* + // $JYRPO,4,2,1.773, ,0.718, ,* + // $JYRPO,4,3,3.687, ,1.468, ,* + // $JYRPO,4,4,4.281, ,0.687, ,* + + + Serial.println("setUartOutput started"); + // mmWaveSerial.println("sensorStop"); + // delay(100); + // mmWaveSerial.println("setUartOutput 1 1 1 2"); // Enable presence detection output, send immediately when changed, otherwise every 2 seconds: + // mmWaveSerial.println("setUartOutput 1 1 0 1600"); // Disable periodic output, switch to passive mode (query only) + mmWaveSerial.println("setUartOutput 1 0"); // Disable presence detection output + delay(100); + line = mmWaveSerial.readStringUntil('\n'); + Serial.println("RX: " + line); + mmWaveSerial.println("setUartOutput 2 1"); // Enable point cloud data output ($JYRPO): + delay(100); + line = mmWaveSerial.readStringUntil('\n'); + Serial.println("RX: " + line); + mmWaveSerial.println("saveConfig"); + delay(100); + mmWaveSerial.println("sensorStart"); + delay(100); + Serial.println("setUartOutput finished"); +} + +void turnOnSensor_old(int sensitivity){ + Serial.println("turnOnSensor"); + mmWaveSerial.println("sensorStop"); + delay(100); + mmWaveSerial.println("resetCfg"); + delay(100); + mmWaveSerial.println("setUartOutput 1 0"); // Disable presence detection output + delay(100); + mmWaveSerial.println("setUartOutput 2 1"); // Enable point cloud data output ($JYRPO): + delay(100); + mmWaveSerial.println("setSensitivity " + String(sensitivity)); + delay(100); + mmWaveSerial.println("setRange 0 3"); + delay(100); + mmWaveSerial.println("setLedMode 1 1"); // turn off LED + // mmWaveSerial.println("setLedMode 1 0"); // turn on LED + delay(100); + mmWaveSerial.println("setGpioMode 2 1"); // HIGH when someone is present + delay(100); + mmWaveSerial.println("saveConfig"); + delay(100); + mmWaveSerial.println("sensorStart"); + delay(100); +} + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Disable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Enable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); + + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + + +void readOutput(){ + String line = mmWaveSerial.readStringUntil('\n'); + Serial.println(""); + Serial.print("RX: "); + Serial.println(line); + + if (line.startsWith("$JYBSS")) { + if (line.indexOf(",1") >= 0) { + Serial.println("Presence Detected: YES"); + } else { + Serial.println("Presence Detected: NO"); + } + } +} + + + +#define SERIAL_BAUD 115200 +#define SENSOR_SERIAL Serial1 // Adjust depending on your board (e.g. Serial2) + +enum MessageType { NONE, JYBSS, JYRPO }; + +struct PresenceResult { + bool presence; // true if someone is detected +}; + +struct PointCloudTarget { + int totalTargets; + int targetIndex; + float distance; + float snr; +}; + +// --- FUNCTION DECLARATION --- +MessageType parseSensorMessage(String input, PresenceResult &presence, PointCloudTarget &target); + +void setup() { + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + Serial.println(" -------------------------- Starting mmWave Presence + Distance --------------------------"); + + + // delay(1000); // Give sensor time to boot + + turnOnSensor(7); + + delay(1000); // Give sensor time to boot + + // setUartOutput(); + + // setSensitivity(7); + + // String cmd = "getUartOutput" + // mmWaveSerial.println(cmd); + + pinMode(23, INPUT_PULLDOWN); // connected to GPIO2 of the sensor; HIGH in case of presence detection + + delay(200); +} + + +unsigned long startTime = millis(); + +void loop() { + // Read data from sensor + while (mmWaveSerial.available()) { + String line = mmWaveSerial.readStringUntil('\n'); + line.trim(); // Remove whitespace and newline chars + + if (line.length() == 0) { + Serial.println("RX empty."); + return; + } + + Serial.print("RX: "); + Serial.println(line); + + // Check for presence detection + // if (line.startsWith("$JYBSS")) { + // int presence = line.charAt(8) - '0'; // Fast access to value + // Serial.print("Presence Detected: "); + // Serial.println(presence == 1 ? "YES" : "NO"); + // } + if (line.startsWith("$JYBSS")) { + if (line.indexOf(",1") >= 0) { + Serial.println("Presence Detected: YES"); + } else { + Serial.println("Presence Detected: NO"); + } + } + + // Check for point cloud detection + else if (line.startsWith("$JYRPO")) { + int comma1 = line.indexOf(',', 7); + int comma2 = line.indexOf(',', comma1 + 1); + int targetIndex = line.substring(comma1 + 1, comma2).toInt(); + Serial.print("JYRPO Target Index: "); + Serial.println(targetIndex); + } + } + // Wait for 1 second while reading any available response + if (millis() - startTime > 1000) { + int sensorVal = digitalRead(23); + Serial.print("GPIO2 state: "); + Serial.println(sensorVal); + startTime = millis(); + } +} diff --git a/I2C_diagnostic_v1/I2C_diagnostic_v1.ino b/I2C_diagnostic_v1/I2C_diagnostic_v1.ino new file mode 100644 index 0000000..8e833d2 --- /dev/null +++ b/I2C_diagnostic_v1/I2C_diagnostic_v1.ino @@ -0,0 +1,142 @@ +/* + * DFRobot Beetle ESP32-C6 I2C Diagnostic Tool + * Tests ALL possible I2C pin combinations + pullup detection + * For BME680(0x76/77), SHT40(0x44/45), SGP40(0x59), T6713(0x15) + */ + +#include "Wire.h" + +/* + * DFRobot Beetle ESP32-C6 I2C Diagnostic Tool (Fixed) + * Tests ALL possible I2C pin combinations + pullup detection + */ + +void setup() { + Serial.begin(115200); + delay(2000); + Serial.println("\n=== DFRobot Beetle ESP32-C6 I2C DIAGNOSTIC v1.1 ==="); + Serial.println("Expected devices: BME680(0x76/77), SHT40(0x44/45), SGP40(0x59), T6713(0x15)"); + Serial.println(); + + testAllI2CPinCombinations(); + testPullupsAndClock(); + printPinoutGuide(); +} + +void loop() { + // Continuous scan on button press (BOOT_PIN) + if (digitalRead(BOOT_PIN) == LOW) { + delay(200); + if (digitalRead(BOOT_PIN) == LOW) { + Serial.println("\n=== RE-SCAN ALL PINS ==="); + testAllI2CPinCombinations(); + Serial.println("=== END RE-SCAN ===\n"); + } + } + delay(100); +} + +void testAllI2CPinCombinations() { + // Common DFRobot Beetle C6 pinouts + struct PinTest { + int sda, scl; + const char* name; + }; + + PinTest tests[] = { + {21, 22, "GPIO21/22 (Main code)"}, + {22, 21, "GPIO22/21 (SWAPPED)"}, + {19, 20, "GPIO19/9 (Alternate)"}, + {20, 19, "GPIO20/19 (Node11 style)"}, + {-1, -1, "DEFAULT (GPIO8/9)"} // Wire.begin() only + }; + + for (int i = 0; i < 5; i++) { + Serial.printf("\n--- %s ---\n", tests[i].name); + + if (tests[i].sda == -1) { + Wire.begin(); // Default pins + } else { + Wire.begin(tests[i].sda, tests[i].scl); + } + + Wire.setClock(100000); // 100kHz + scanBusAndReport(tests[i].sda, tests[i].scl); + } +} + +void scanBusAndReport(int sdaPin, int sclPin) { + Serial.printf("Clock: %lu Hz | Testing SDA=GPIO%d SCL=GPIO%d\n", Wire.getClock(), sdaPin, sclPin); + + int deviceCount = 0; + for (byte addr = 1; addr < 127; addr++) { + Wire.beginTransmission(addr); + byte error = Wire.endTransmission(); + + if (error == 0) { + Serial.printf(" ✓ 0x%02X ", addr); + deviceCount++; + + // Known sensors + switch(addr) { + case 0x15: Serial.print("(T6713)"); break; + case 0x44: Serial.print("(SHT40)"); break; + case 0x45: Serial.print("(SHT40 alt)"); break; + case 0x59: Serial.print("(SGP40)"); break; + case 0x76: Serial.print("(BME680)"); break; + case 0x77: Serial.print("(BME680 alt)"); break; + default: Serial.print("(Unknown)"); + } + Serial.println(); + } + } + + Serial.printf(" Total devices: %d\n", deviceCount); + if (deviceCount == 0) { + Serial.println(" ⚠️ NO DEVICES - Check power/pullups/wiring!"); + } + delay(500); // Stabilize bus +} + +void testPullupsAndClock() { + Serial.println("\n--- PULLUP & CLOCK TEST ---"); + Wire.begin(6, 20); // Most likely pins + + // Test clock speeds + uint32_t clocks[] = {100000, 400000, 1000000}; + for (int i = 0; i < 3; i++) { + Wire.setClock(clocks[i]); + Serial.printf("Clock %lu Hz: ", Wire.getClock()); + + // Quick scan for 0x59 (SGP40) + Wire.beginTransmission(0x59); + if (Wire.endTransmission() == 0) { + Serial.println("✓ SGP40 OK"); + } else { + Serial.println("✗ No ACK"); + } + } +} + +void printPinoutGuide() { + Serial.println("\n=== WIRING GUIDE ==="); + Serial.println("ESP32-C6 → Sensors"); + Serial.println("GPIO6 → SDA (all sensors)"); + Serial.println("GPIO20 → SCL (all sensors)"); + Serial.println("3.3V → VCC (NOT 5V!)"); + Serial.println("GND → GND"); + Serial.println(""); + Serial.println("REQUIRED: 4.7kΩ pullups"); + Serial.println("SDA ───┬── 4.7kΩ ─── 3.3V"); + Serial.println(" │"); + Serial.println(" Sensors"); + Serial.println("SCL ───┬── 4.7kΩ ─── 3.3V"); + Serial.println(""); + Serial.println("=== TROUBLESHOOTING ==="); + Serial.println("1. Measure 3.3V at sensor VCC pins"); + Serial.println("2. Check SDA/SCL continuity with multimeter"); + Serial.println("3. Add 4.7kΩ pullups if missing"); + Serial.println("4. Press BOOT button to re-scan"); + Serial.println("5. Verify NO 5V power (sensors damaged!)"); + Serial.println("=======================\n"); +} diff --git a/I2C_diagnostic_v2.ino/I2C_diagnostic_v2.ino.ino b/I2C_diagnostic_v2.ino/I2C_diagnostic_v2.ino.ino new file mode 100644 index 0000000..4f9ea02 --- /dev/null +++ b/I2C_diagnostic_v2.ino/I2C_diagnostic_v2.ino.ino @@ -0,0 +1,44 @@ + +#include + +int I2C_SDA = 20; +int I2C_SCL = 18; + +void setup() { + Wire.begin(I2C_SDA, I2C_SCL); + Serial.begin(115200); + Serial.println("\nI2C Scanner"); +} + +void loop() { + byte error, address; + int nDevices; + Serial.println("Scanning..."); + nDevices = 0; + for(address = 1; address < 127; address++ ) { + Wire.beginTransmission(address); + error = Wire.endTransmission(); + if (error == 0) { + Serial.print("I2C device found at address 0x"); + if (address<16) { + Serial.print("0"); + } + Serial.println(address,HEX); + nDevices++; + } + else if (error==4) { + Serial.print("Unknow error at address 0x"); + if (address<16) { + Serial.print("0"); + } + Serial.println(address,HEX); + } + } + if (nDevices == 0) { + Serial.println("No I2C devices found\n"); + } + else { + Serial.println("done\n"); + } + delay(5000); +} \ No newline at end of file diff --git a/Node11_bme680_sgp40_sht40_router_v2/Node11_bme680_sgp40_sht40_router_v2.ino b/Node11_bme680_sgp40_sht40_router_v2/Node11_bme680_sgp40_sht40_router_v2.ino new file mode 100644 index 0000000..a72490e --- /dev/null +++ b/Node11_bme680_sgp40_sht40_router_v2/Node11_bme680_sgp40_sht40_router_v2.ino @@ -0,0 +1,414 @@ + +/* + Seeed Xiao ESP32-C6 + + LED: LED_BUILTIN, on when LOW + + Partition Scheme: Zigbee ZCZR 4MB with spiffs + Zigbee Mode: Zigbee ZR/ZC (coordinator,router) + #define LEDPIN LED_BUILTIN + #define I2CSDAPIN 20 + #define I2CSCLPIN 18 +*/ + +#ifndef ZIGBEE_MODE_ZCZR +#error Zigbee coordinator/router mode is not selected in Tools->Zigbee mode +#endif + +#define DEBUG_TRACE // Comment out DEBUG_TRACE to reduce normal-path logging + +#include "Zigbee.h" +#include "Wire.h" +#include "bme68xLibrary.h" +#include "Adafruit_SHT4x.h" +#include "Adafruit_SGP40.h" + +// ----------------------------------------------------------------------------- +// Hardware definitions (shared I2C bus) +// ----------------------------------------------------------------------------- +#define LED_PIN LED_BUILTIN +#define I2C_SDA_PIN 20 +#define I2C_SCL_PIN 18 + +// Endpoint numbers reassigned for new sensors +#define BME_TEMP_ENDPOINT 10 +#define BME_ANALOG_ENDPOINT 11 +#define SHT_SGP_TEMP_ENDPOINT 12 +#define SGP_ANALOG_ENDPOINT 13 + +// Sensor objects +Bme68x bme; +Adafruit_SHT4x sht4; +Adafruit_SGP40 sgp; + +// Zigbee sensor objects +ZigbeeTempSensor zbTempSensorBME(BME_TEMP_ENDPOINT); +ZigbeeAnalog zbAnalogBME(BME_ANALOG_ENDPOINT); +ZigbeeTempSensor zbTempSensorSHTSGP(SHT_SGP_TEMP_ENDPOINT); +ZigbeeAnalog zbAnalogSGP(SGP_ANALOG_ENDPOINT); + +// ----------------------------------------------------------------------------- +// Health watchdog globals updated for new sensors +// ----------------------------------------------------------------------------- +SemaphoreHandle_t i2cMutex; + +bool bmeFirstOk = false; +bool shtsgpFirstOk = false; + +// Last-change tracking +float lastTempBme = NAN, lastHumBme = NAN, lastGasRes = NAN; +unsigned long lastTempBmeChangeMs = 0, lastHumBmeChangeMs = 0, lastGasResChangeMs = 0; +float lastTempSht = NAN, lastHumSht = NAN, lastRawSgp = NAN; +unsigned long lastTempShtChangeMs = 0, lastHumShtChangeMs = 0, lastRawSgpChangeMs = 0; +unsigned long lastZigbeeOkMs = 0; + +// Error counters +int bmeErrorCount = 0, shtsgpErrorCount = 0; +const int maxI2cErrors = 10; + +// Watchdog thresholds +const unsigned long WATCHDOG_PERIOD_MS = 10000; // 10s +const unsigned long SENSORS_STUCK_TIMEOUT_MS = 30UL * 60UL * 1000UL; // 30min +const unsigned long ZIGBEE_DOWN_TIMEOUT_MS = 10UL * 60UL * 1000UL; // 10min + +// ----------------------------------------------------------------------------- +// Zigbee health touch after successful reports +// ----------------------------------------------------------------------------- +inline void zigbeeHealthTouch() { + if (Zigbee.connected()) lastZigbeeOkMs = millis(); +} + +// ----------------------------------------------------------------------------- +// Helper: I2C guarded execution (use mutex) +// ----------------------------------------------------------------------------- +#include + +bool withI2C(std::function fn, uint32_t timeoutMs = 100) { + if (xSemaphoreTake(i2cMutex, pdMS_TO_TICKS(timeoutMs)) == pdTRUE) { + bool ok = fn(); + xSemaphoreGive(i2cMutex); + return ok; + } + return false; +} + +// ----------------------------------------------------------------------------- +// BME68x task adapted, endpoint 10/11 +// ----------------------------------------------------------------------------- +static void bme680sensorvalueupdate(void *arg) { + for (;;) { + float temperature = NAN, humidity = NAN, gasResistance = NAN; + bme68xData data; + + bool ok = withI2C([&]() { + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; + humidity = data.humidity; + gasResistance = data.gas_resistance; + return true; + } + return false; + }); + + if (ok) { + bmeErrorCount = 0; + unsigned long now = millis(); + + if (!bmeFirstOk) { + bmeFirstOk = true; + lastTempBme = temperature; + lastHumBme = humidity; + lastGasRes = gasResistance; + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = now; + } else { + if (temperature != lastTempBme) { + lastTempBme = temperature; + lastTempBmeChangeMs = now; + } + if (humidity != lastHumBme) { + lastHumBme = humidity; + lastHumBmeChangeMs = now; + } + if (gasResistance != lastGasRes) { + lastGasRes = gasResistance; + lastGasResChangeMs = now; + } + } + + zbTempSensorBME.setTemperature(temperature); + zbTempSensorBME.setHumidity(humidity); + // zbTempSensorBME.report(); + zigbeeHealthTouch(); + + zbAnalogBME.setAnalogInput(round(gasResistance)); + // zbAnalogBME.reportAnalogInput(); + zigbeeHealthTouch(); + +#ifdef DEBUG_TRACE + Serial.printf("BME68x T:%.2fC H:%.2f Gas:%.2f ohm\n", temperature, humidity, gasResistance); +#endif + } else { + bmeErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("BME68x read error or I2C busy."); +#endif + if (bmeErrorCount >= maxI2cErrors) { + Serial.println("BME68x too many errors, restarting..."); + delay(200); + ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// SHT40SGP40 task from Node11, endpoint 12/13 +// ----------------------------------------------------------------------------- +static void sgp40sht40sensorvalueupdate(void *arg) { + for (;;) { + float currentTemp = NAN, currentHum = NAN; + uint16_t currentRaw = NAN; + + bool ok = withI2C([&]() { + sensors_event_t humidity, temp; + if (!sht4.getEvent(&humidity, &temp)) return false; + currentTemp = temp.temperature; + currentHum = humidity.relative_humidity; + currentRaw = sgp.measureRaw(currentTemp, currentHum); + return true; + }); + + if (ok) { + shtsgpErrorCount = 0; + unsigned long now = millis(); + + if (!shtsgpFirstOk) { + shtsgpFirstOk = true; + lastTempSht = currentTemp; + lastHumSht = currentHum; + lastRawSgp = currentRaw; + lastTempShtChangeMs = lastHumShtChangeMs = lastRawSgpChangeMs = now; + } else { + if (currentTemp != lastTempSht) { + lastTempSht = currentTemp; + lastTempShtChangeMs = now; + } + if (currentHum != lastHumSht) { + lastHumSht = currentHum; + lastHumShtChangeMs = now; + } + if (currentRaw != lastRawSgp) { + lastRawSgp = currentRaw; + lastRawSgpChangeMs = now; + } + } + + zbTempSensorSHTSGP.setTemperature(currentTemp); + zbTempSensorSHTSGP.setHumidity(currentHum); + // zbTempSensorSHTSGP.report(); + zigbeeHealthTouch(); + + zbAnalogSGP.setAnalogInput(round(currentRaw)); + // zbAnalogSGP.reportAnalogInput(); + zigbeeHealthTouch(); + +#ifdef DEBUG_TRACE + Serial.printf("SHT40SGP40 T:%.2fC H:%.2f Raw:%d\n", currentTemp, currentHum, currentRaw); +#endif + } else { + shtsgpErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("SHT40SGP40 read error or I2C busy."); +#endif + if (shtsgpErrorCount >= maxI2cErrors) { + Serial.println("SHT40SGP40 too many errors, restarting..."); + delay(200); + ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// Watchdog task updated checks for new sensors +// ----------------------------------------------------------------------------- +void watchdogTask(void *param) { + for (;;) { +#ifdef DEBUG_TRACE + Serial.println("Watchdog ran."); +#endif + unsigned long now = millis(); + + bool zigbeeBad = !Zigbee.connected() || (now - lastZigbeeOkMs > ZIGBEE_DOWN_TIMEOUT_MS); + bool bmeStuck = bmeFirstOk && + (now - lastTempBmeChangeMs > SENSORS_STUCK_TIMEOUT_MS || + now - lastHumBmeChangeMs > SENSORS_STUCK_TIMEOUT_MS || + now - lastGasResChangeMs > SENSORS_STUCK_TIMEOUT_MS); + bool shtsgpStuck = shtsgpFirstOk && + (now - lastTempShtChangeMs > SENSORS_STUCK_TIMEOUT_MS || + now - lastHumShtChangeMs > SENSORS_STUCK_TIMEOUT_MS || + now - lastRawSgpChangeMs > SENSORS_STUCK_TIMEOUT_MS); + + if (zigbeeBad || bmeStuck || shtsgpStuck) { + Serial.println("Watchdog fault detected, restarting..."); + delay(500); + ESP.restart(); + } + vTaskDelay(pdMS_TO_TICKS(WATCHDOG_PERIOD_MS)); + } +} + +// ----------------------------------------------------------------------------- +// setup +// ----------------------------------------------------------------------------- +void setup() { + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + delay(100); + + // Global manufacturer/model + // Zigbee.setManufacturer("Espressif"); + // Zigbee.setModel("NodeNewBME680SHT40SGP40v1"); + + // I2C init + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + i2cMutex = xSemaphoreCreateMutex(); + + // BME680 init + Serial.println("Connecting to BME680..."); + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); + + // Step-by-step status checks + if (bme.checkStatus() == BME68X_ERROR) { + Serial.println("❌ BME68X_ERROR: " + bme.statusString()); + } else if (bme.checkStatus() == BME68X_WARNING) { + Serial.println("⚠️ BME68X_WARNING: " + bme.statusString()); + } else { + Serial.println("✓ BME68X status OK"); + } + + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + bme.setHeaterProf(300, 100); + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensorBME.setManufacturerAndModel("Espressif", "Node11bme680th"); + zbTempSensorBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorBME.setMinMaxValue(-20, 80); + zbTempSensorBME.setTolerance(1); + zbTempSensorBME.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorBME); + + zbAnalogBME.setManufacturerAndModel("Espressif", "Node11bme680r"); + zbAnalogBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogBME.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogBME); + + // SHT40SGP40 init + Serial.println("Initializing SHT40..."); + if (!sht4.begin(&Wire)) { + Serial.println("SHT40 not found! Check wiring."); + while (1) delay(10); + } + sht4.setPrecision(SHT4X_HIGH_PRECISION); + sht4.setHeater(SHT4X_NO_HEATER); // SHT4X_NO_HEATER, SHT4X_MED_HEATER_100MS + + Serial.println("Initializing SGP40..."); + if (!sgp.begin(&Wire)) { + Serial.println("SGP40 not found! Check wiring."); + while (1) delay(10); + } + + zbTempSensorSHTSGP.setManufacturerAndModel("Espressif", "Node11sht40sgp40th"); + zbTempSensorSHTSGP.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorSHTSGP.setMinMaxValue(-20, 80); + zbTempSensorSHTSGP.setTolerance(1); + zbTempSensorSHTSGP.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorSHTSGP); + + zbAnalogSGP.setManufacturerAndModel("Espressif", "Node11sgp40raw"); + zbAnalogSGP.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogSGP.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogSGP); + + // Start Zigbee as router + Serial.println("Starting Zigbee..."); + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start! Rebooting..."); + ESP.restart(); + } + Serial.println("Zigbee started successfully! Connecting to network..."); + + bool ledState = false; + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + if (millis() - startTime > timeoutMs) { + Serial.println(" timed out 60s. Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, HIGH); + Serial.println(" connected!"); + lastZigbeeOkMs = millis(); + + // Create sensor tasks + xTaskCreate(bme680sensorvalueupdate, "bme task", 4096, NULL, 10, NULL); + xTaskCreate(sgp40sht40sensorvalueupdate, "shtsgp task", 4096, NULL, 10, NULL); + xTaskCreate(watchdogTask, "watchdog", 4096, NULL, 5, NULL); + + // Reporting configuration after Zigbee.begin + zbTempSensorBME.setReporting(60, 0, 0.5); + zbAnalogBME.setAnalogInputReporting(60, 600, 10); + zbTempSensorSHTSGP.setReporting(60, 0, 0.5); + zbAnalogSGP.setAnalogInputReporting(60, 600, 10); +} + +// ----------------------------------------------------------------------------- +// loop light - button reset test commands +// ----------------------------------------------------------------------------- +void loop() { + // Test commands via Serial + if (Serial.available()) { + char cmd = Serial.read(); + switch (cmd) { + case 'Z': // Force Zigbee failure watchdog test + Serial.println("SIM Zigbee disconnect test"); + lastZigbeeOkMs = 0; // Watchdog sees Zigbee down + break; + case 'E': // Force stuck sensor detection + Serial.println("SIM Stuck sensor test"); + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = 0; + lastTempShtChangeMs = lastHumShtChangeMs = lastRawSgpChangeMs = 0; + break; + case 'R': // Manual restart + Serial.println("SIM Manual restart"); + ESP.restart(); + break; + } + } + + // Factory reset on long button press + static uint8_t button = BOOT_PIN; + if (digitalRead(button) == LOW) { // push button pressed + delay(100); // debounce + 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(); + ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(50)); +} diff --git a/Node11_bme680_sht40_sgp40_router_v1/.theia/launch.json b/Node11_bme680_sht40_sgp40_router_v1/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node11_bme680_sht40_sgp40_router_v1/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node11_bme680_sht40_sgp40_router_v1/Node11_bme680_sht40_sgp40_router_v1.ino b/Node11_bme680_sht40_sgp40_router_v1/Node11_bme680_sht40_sgp40_router_v1.ino new file mode 100644 index 0000000..c3fe1ff --- /dev/null +++ b/Node11_bme680_sht40_sgp40_router_v1/Node11_bme680_sht40_sgp40_router_v1.ino @@ -0,0 +1,869 @@ +// Xiao ESP32-C6 + +// uploading new script +// Zigbee connection establishment --> ....... +// force remove deivce from Z2M with permit join OFF +// swich permit JOIN ON +// restart ESP32 +// leave permit jion on until configuration finished + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" +// #include + +// #define SENSOR_RX 17 // ESP32 RX connected to sensor TX +// #define SENSOR_TX 16 // ESP32 TX connected to sensor RX +// HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +// #define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +// uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +// ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 18 +#define SDA_PIN 20 + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +// #define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +// ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 11 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + +/************************ Temp sensor *****************************/ +static void bme680_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_BME68X.setTemperature(temperature); + zbTempSensor_BME68X.setHumidity(humidity); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + // zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance / 1000.0)); + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("BME680: Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + + + +// #include +#include "Adafruit_SHT4x.h" +#include "Adafruit_SGP40.h" + +// --- Hardware Config --- +// #define I2C_SDA_PIN 6 // Default C6 SDA (Adjust if using a specific board like Seeed Xiao) +// #define I2C_SCL_PIN 7 // Default C6 SCL +// If using standard DevKit, you can often just use Wire.begin() without pins + +// --- Objects --- +Adafruit_SHT4x sht4; +Adafruit_SGP40 sgp; + +// Define a Zigbee Endpoint for Environmental Data +#define ENDPOINT_ENV 12 +// ZigbeeTempSensor zbEnvSensor_sgp40_sht40(ENDPOINT_ENV); +ZigbeeTempSensor zbEnvSensor_sgp40_sht40 = ZigbeeTempSensor(ENDPOINT_ENV); + + +#define SGP_ANALOG_DEVICE_ENDPOINT_NUMBER 13 +ZigbeeAnalog zbAnalogDevice_sgp40_sht40 = ZigbeeAnalog(SGP_ANALOG_DEVICE_ENDPOINT_NUMBER); + + + +static void sgp40_sht40_sensor_value_update(void *arg) { + for (;;) { + + float currentTemp(NAN), currentHum(NAN); + uint16_t currentRaw(NAN); + int32_t currentVOC(NAN); + // uint8_t percentage; + + // Prepare the BME680 for measurement + // bme68xData data; + // int8_t rslt; + + // bme.setOpMode(BME68X_FORCED_MODE); + // delayMicroseconds(bme.getMeasDur()); + + // if (bme.fetchData()) { + // bme.getData(data); + // temperature = data.temperature; // Temperature in °C + // humidity = data.humidity; // Humidity in % + // pressure = data.pressure; // Pressure in hPa + // gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + // } else { + // //Serial.println("Failed to read data from BME680!"); + // //return; // Exit if reading failed + + // errorCount++; + // Serial.println("Failed to read data from BME680!"); + // if (errorCount >= maxErrors) { + // Serial.println("Too many errors! Restarting..."); + // ESP.restart(); // Restart the ESP32 after too many errors + // } + // } + Serial.println("Starting readout of SHT40"); + + // --- 1. Read SHT40 (Temp/Hum) --- + sensors_event_t humidity, temp; + sht4.getEvent(&humidity, &temp); // Populate temp and humidity objects + + currentTemp = temp.temperature; + currentHum = humidity.relative_humidity; + + Serial.print("Temperature: "); Serial.print(currentTemp); Serial.println(" degrees C"); + Serial.print("Humidity: "); Serial.print(currentHum); Serial.println("% rH"); + + + Serial.println("Starting readout of SGP40"); + // --- 2. Read SGP40 (VOC) --- + // SGP40 requires precise Temp/Hum for accurate compensation. + // We pass the raw SHT40 values directly to the SGP40 algorithm. + currentRaw = sgp.measureRaw(currentTemp, currentHum); + currentVOC = sgp.measureVocIndex(currentTemp, currentHum); + + Serial.print("Raw measurement: "); + Serial.println(currentRaw); + Serial.print("Voc Index: "); + Serial.println(currentVOC); + + + // // Temp: Cluster 0x0402, Attribute 0x0000 (MeasuredValue), Type INT16, Value = Temp * 100 + // int16_t zigbeeTemp = (int16_t)(currentTemp * 100); + // zbEnvSensor_sgp40_sht40.reportAttribute(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, + // ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + // ESP_ZB_ZCL_ATTR_TYPE_S16, + // &zigbeeTemp); + + // // Humidity: Cluster 0x0405, Attribute 0x0000 (MeasuredValue), Type UINT16, Value = Hum * 100 + // uint16_t zigbeeHum = (uint16_t)(currentHum * 100); + // zbEnvSensor_sgp40_sht40.reportAttribute(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY, + // ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, + // ESP_ZB_ZCL_ATTR_TYPE_U16, + // &zigbeeHum); + + // // VOC (Analog Input): Cluster 0x000C, Attribute 0x0055 (PresentValue), Type SINGLE (Float) + // // Using Analog Input Present Value for VOC + // float zigbeeVOC = (float)currentVOC; + // zbEnvSensor_sgp40_sht40.reportAttribute(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, + // ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, + // ESP_ZB_ZCL_ATTR_TYPE_SINGLE, + // &zigbeeVOC); + + // Serial.printf("T: %.2f C | H: %.2f %% | VOC Index: %d\n", zigbeeTemp, zigbeeHum, zigbeeVOC); + + Serial.println("finished readout of SGP40"); + + // // Update temperature and humidity values in Temperature sensor EP + zbEnvSensor_sgp40_sht40.setTemperature(currentTemp); + zbEnvSensor_sgp40_sht40.setHumidity(currentHum); + + // // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + // zbAnalogDevice_sgp40_sht40.setAnalogInput(round(currentRaw / 1000.0)); + zbAnalogDevice_sgp40_sht40.setAnalogInput(round(currentRaw)); + // // zbAnalogDevice_BME68X.reportAnalogInput(); + + Serial.println("finished setting values"); + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", currentTemp, currentHum, currentVOC); + // Serial.printf("SGP/SHT: T: %.2f C | H: %.2f %% | Raw SGP: %d | VOC Index: %d\n", currentTemp, currentHum, currentRaw, currentVOC); + + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + + + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + +// #define ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT 9 +// uint8_t illuminance_sensor_pin = 1; // Insert the analog pin to which the sensor (e.g. photoresistor) is connected + +// ZigbeeIlluminanceSensor zbIlluminanceSensor = ZigbeeIlluminanceSensor(ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT); + +// /********************* Illuminance sensor **************************/ +// static void illuminance_sensor_value_update(void *arg) { +// for (;;) { +// // read the raw analog value from the sensor +// int lsens_analog_raw = analogRead(illuminance_sensor_pin); +// Serial.printf("[Illuminance Sensor] raw analog value: %d\r\n", lsens_analog_raw); + +// // conversion into zigbee raw illuminance value (typically between 0 in darkness and 50000 in direct sunlight) +// // depends on the value range of the raw analog sensor values and will need calibration for correct lux values +// // for demonstration purpose map the 12-bit ADC value (0-4095) to Zigbee illuminance range (0-50000) +// int lsens_illuminance_raw = map(lsens_analog_raw, 0, 4095, 0, 50000); +// Serial.printf("[Illuminance Sensor] raw illuminance value: %d\r\n", lsens_illuminance_raw); + +// // according to zigbee documentation the formular 10^(lsens_illuminance_raw/10000)-1 can be used to calculate lux value from raw illuminance value +// // Note: Zigbee2MQTT seems to be using the formular 10^(lsens_illuminance_raw/10000) instead (without -1) +// int lsens_illuminance_lux = round(pow(10, (lsens_illuminance_raw / 10000.0)) - 1); +// Serial.printf("[Illuminance Sensor] lux value: %d lux\r\n", lsens_illuminance_lux); + +// // Update illuminance in illuminance sensor EP +// zbIlluminanceSensor.setIlluminance(lsens_illuminance_raw); // use raw illuminance here! + +// delay(10000); // reduce delay (in ms), if you want your device to react more quickly to changes in illuminance +// } +// } + + + + + + +// // 1. Define the task function (Global scope, outside setup/loop) +// void pirTask(void * parameter) { +// // Move the static variable here. It doesn't need to be 'static' anymore +// // because this function only runs once and stays in the loop below. +// bool occupancy = false; + +// // 2. Infinite Loop: Tasks must never return! +// for(;;) { +// // --- Your Original Logic Start --- +// if (digitalRead(sensor_pin) == HIGH && !occupancy) { +// zbOccupancySensor.setOccupancy(true); +// zbOccupancySensor.report(); +// occupancy = true; +// analogWrite(ledPin, 0); +// Serial.println("GPIO2 HIGH"); +// } else if (digitalRead(sensor_pin) == LOW && occupancy) { +// zbOccupancySensor.setOccupancy(false); +// zbOccupancySensor.report(); +// occupancy = false; +// analogWrite(ledPin, 255); +// Serial.println("GPIO2 LOW"); +// } +// // --- Your Original Logic End --- + +// // 3. CRITICAL: Delay to yield control +// // Polling a PIR every 50ms is plenty fast and saves CPU. +// vTaskDelay(50 / portTICK_PERIOD_MS); +// } +// } + + +// const char* commands[] = { +// "getRange", +// "getSensitivity", +// "getLatency", +// "getUart", +// "getGpioMode 2", +// "getLedMode 1", +// "getEcho", +// "getUartOutput 1", +// "getUartOutput 2", +// // "sensorStop", +// // "sensorStart", +// // "saveConfig", +// // "resetCfg", +// // "resetSystem", +// "getHWV", +// "getSWV", +// "getOutput" +// }; + +// const int numCommands = sizeof(commands) / sizeof(commands[0]); + +// String line = ""; + + +// bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { +// // Send the command +// sensorSerial.println(command); +// Serial.print("Sending: "); +// Serial.println(command); + +// // Wait for "Done" response +// unsigned long startTime = millis(); +// String response; + +// while (millis() - startTime < timeout) { +// while (sensorSerial.available()) { +// char c = sensorSerial.read(); +// Serial.write(c); // Print response to Serial Monitor +// response += c; + +// // If "Done" is found in the response, return success +// if (response.indexOf("Done") >= 0) { +// Serial.println("✓ Done received."); +// return true; +// } + +// // Optional: detect "Error" for debugging +// if (response.indexOf("Error") >= 0) { +// Serial.println("✗ Error received."); +// return false; +// } +// } +// } + +// Serial.println("✗ Timeout waiting for Done."); +// return false; +// } + +// void turnOnSensor(int sensitivity) { +// Serial.println("=== Turning On Sensor ==="); + +// sendCommandAndWaitForDone("sensorStop", mmWaveSerial); +// sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + +// // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS +// // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO +// sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS +// sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + +// sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); +// sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); +// sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + +// sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). +// sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off +// sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + +// sendCommandAndWaitForDone("saveConfig", mmWaveSerial); +// sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +// } + + + + + + + + + +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + // mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + // delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + + // turnOnSensor(5); // initialization of mmwave sensor + + // for (int i = 0; i < numCommands; i++) { + // const char* cmd = commands[i]; + // sendCommandAndWaitForDone(cmd, mmWaveSerial); + // delay(10); // small delay before next command (optional) + // } + + + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + + + // // Init button + PIR sensor + // pinMode(button, INPUT_PULLUP); + // pinMode(sensor_pin, INPUT_PULLUP); + // pinMode(ledPin, OUTPUT); + + // analogWrite(ledPin, 255); // pin, dutyCycle + + // // Optional: set Zigbee device name and model + // zbOccupancySensor.setManufacturerAndModel("Espressif", "Node11_bme680_sht40_sgp40"); + + // // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + // zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + // Optional: set Zigbee device name and model + zbTempSensor_BME68X.setManufacturerAndModel("Espressif", "Node11_bme680_sht40_sgp40"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbTempSensor_BME68X.setPowerSource(ZB_POWER_SOURCE_MAINS); + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_BME68X.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_BME68X.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + + + + // // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + // zbTempSensor2.setMinMaxValue(10, 50); + + // // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + // zbTempSensor2.setTolerance(1); + + // // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // // Add humidity cluster to the temperature sensor device with min, max and tolerance values + // zbTempSensor2.addHumiditySensor(0, 100, 1); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbTempSensor2); + + + + + + + // // Set minimum and maximum carbon dioxide measurement value in ppm + // zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + // // Add endpoints to Zigbee Core + // Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + // // Set minimum and maximum for raw illuminance value (0 min and 50000 max equals to 0 lux - 100,000 lux) + // zbIlluminanceSensor.setMinMaxValue(0, 50000); + + // // Optional: Set tolerance for raw illuminance value + // zbIlluminanceSensor.setTolerance(1); + + // // Add endpoint to Zigbee Core + // Serial.println("Adding Zigbee illuminance sensor endpoint to Zigbee Core"); + // Zigbee.addEndpoint(&zbIlluminanceSensor); + + + + + + + Serial.println("Initializing SHT40..."); + if (!sht4.begin(&Wire)) { + Serial.println("SHT40 not found! Check wiring."); + while (1) delay(10); + } + sht4.setPrecision(SHT4X_HIGH_PRECISION); + sht4.setHeater(SHT4X_NO_HEATER); + + Serial.println("Initializing SGP40..."); + if (!sgp.begin(&Wire)) { + Serial.println("SGP40 not found! Check wiring."); + while (1) delay(10); + } + + // --- 2. Configure Zigbee Endpoint --- + + // Set Manufacturer/Model + // zbEnvSensor.setManufacturerAndModel("Espressif", "ESP32C6-Env-Sensor"); + + // // A. Add Temperature Cluster (Standard) + // zbEnvSensor_sgp40_sht40.addCluster(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT); + + // // B. Add Humidity Cluster + // // We manually add this cluster to the endpoint + // zbEnvSensor_sgp40_sht40.addCluster(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY); + + // // C. Add Analog Input Cluster (for VOC Index) + // // We use Analog Input (0x000C) as a generic container for the VOC value (0-500) + // zbEnvSensor_sgp40_sht40.addCluster(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbEnvSensor_sgp40_sht40.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbEnvSensor_sgp40_sht40.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbEnvSensor_sgp40_sht40.addHumiditySensor(0, 100, 1); + + // Register the endpoint + Zigbee.addEndpoint(&zbEnvSensor_sgp40_sht40); + + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_sgp40_sht40.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_sgp40_sht40); + + + + + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin(ZIGBEE_ROUTER)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + + + + + // // 4. Create the task + // xTaskCreate( + // pirTask, // Function to call + // "PIR_Check", // Name for debugging + // 4096, // Stack size (bytes) - Zigbee operations need space! + // NULL, // Parameter to pass + // 1, // Priority (1 is standard, higher numbers = higher priority) + // NULL // Task handle + // ); + + + + // Start Temperature sensor reading task + xTaskCreate(bme680_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(0, 15, 1); + // zbTempSensor2.setReporting(0, 15, 0); + + + // zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbAnalogDevice_BME68X.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + + // Start illuminance sensor reading task + // xTaskCreate(illuminance_sensor_value_update, "illuminance_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting schedule for illuminance value measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta + // if min = 1 and max = 0, delta = 1000, reporting is sent when raw illuminance value changes by 1000, but at most once per second + // if min = 0 and max = 10, delta = 1000, reporting is sent every 10 seconds or if raw illuminance value changes by 1000 + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of illuminance change + // Note: On pairing with Zigbee Home Automation or Zigbee2MQTT the reporting schedule will most likely be overwritten with their default settings + // zbIlluminanceSensor.setReporting(1, 0, 1); + + + + xTaskCreate(sgp40_sht40_sensor_value_update, "sgp40_sht40_sensor_value_update", 2048, NULL, 10, NULL); + zbEnvSensor_sgp40_sht40.setReporting(0, 15, 1); + + zbAnalogDevice_sgp40_sht40.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + +} + +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; + // analogWrite(ledPin, 0); + // Serial.println("GPIO2 HIGH"); + // } else if (digitalRead(sensor_pin) == LOW && occupancy) { + // zbOccupancySensor.setOccupancy(false); + // zbOccupancySensor.report(); + // occupancy = false; + // analogWrite(ledPin, 255); + // Serial.println("GPIO2 LOW"); + // } + + // 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(); + } + } + // force report of illuminance when button is pressed + // zbIlluminanceSensor.report(); + zbTempSensor_BME68X.report(); + // zbCarbonDioxideSensor.report(); + zbAnalogDevice_BME68X.reportAnalogInput(); + // zbEnvSensor_sgp40_sht40.report(); + + } + delay(100); +} diff --git a/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2/.theia/launch.json b/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2/.theia/launch.json new file mode 100644 index 0000000..fef7b06 --- /dev/null +++ b/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2/.theia/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + }, + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + } + ] +} diff --git a/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2.ino b/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2.ino new file mode 100644 index 0000000..1a6132d --- /dev/null +++ b/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2/Node14_Zigbee_Temp_Hum_Sensor_Sleepy_DHT11_v2.ino @@ -0,0 +1,259 @@ +// DFRobot Beetle ESP32-C6 + + + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE +#include "Zigbee.h" + +#include "DHT.h" +#define DHTPIN 17 // Digital pin connected to the DHT sensor +#define DHTPOWER 4 // GPIO pin to power the sensor +//https://github.com/adafruit/DHT-sensor-library/blob/master/examples/DHTtester/DHTtester.ino +#define DHTTYPE DHT11 // DHT 11 +DHT dht(DHTPIN, DHTTYPE); + + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 295 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +const int batteryPin = 0; // A0 +#define BAT_ADC_PIN 0 // ADC input pin +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.0; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float val; + val = (x - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(BAT_ADC_PIN); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature * 2; + + // Use DHT11 sensor + // Read temperature as Celsius (the default) + float temperature = dht.readTemperature(); + // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) + float humidity = dht.readHumidity(); + //float humidity = 43; + + // Check if any reads failed and exit early (to try again). + if (isnan(humidity) || isnan(temperature)) { + Serial.println(F("Failed to read from DHT sensor!")); + delay(100); + return; + } + + delay(100); + + digitalWrite(DHTPOWER, LOW); // Power off sensor + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + + delay(1000); + + + // // read the analog / millivolts value for pin 0: + // int analogValue = analogRead(batteryPin); + // int analogVolts = analogReadMilliVolts(batteryPin); + // uint8_t percentage = mapFloat(analogVolts * 2 / 1000, minVoltage, maxVoltage); + // print out the values you read: + // Serial.print("ADC analog value = "); + // Serial.println(analogValue); + // Serial.print("ADC millivolts value = "); + // Serial.print(analogVolts); + // Serial.println(" mV"); + // // Please adjust the calculation coefficient according to the actual measurement. + // Serial.print("BAT millivolts value = "); + // Serial.print(analogVolts * 2); + // Serial.println(" mV"); + // Serial.print("BAT percentage value = "); + // Serial.print(percentage); + // Serial.println(" %"); + // Serial.println("--------------"); + uint8_t percentage; + float vBat; + vBat = getVbatt(); + percentage = mapFloat(vBat, minVoltage, maxVoltage); +#ifdef DEBUG_TRACE + Serial.printf("Battery: %.2fV (%d%%)\n", vBat, percentage); +#endif + + zbTempSensor.setBatteryPercentage(percentage); + zbTempSensor.reportBatteryPercentage(); + + + // Add small delay to allow the data to be sent before going to sleep + //delay(1000); + + digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) + delay(200); // wait for a second + digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW + //delay(100); // wait for a second + + // Put device to deep sleep + Serial.println("Going to sleep now"); + delay(100); + esp_deep_sleep_start(); + // delay(1000); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + pinMode(DHTPOWER, OUTPUT); + digitalWrite(DHTPOWER, HIGH); // Power on the sensor + + delay(1000); // Wait for a second to allow the Serial Monitor to open and DHT11 to stabilize + + Serial.println("Starting setup..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor_Node14"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 99); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 3000; + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + dht.begin(); + Serial.println(F("DHTxx test!")); + + + //set the resolution to 12 bits (0-4096) + analogReadResolution(12); + + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BUILTIN, OUTPUT); + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); +} + +void loop() { + // 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(); + } + } + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); +} diff --git a/Node14_bme680_sgp40_sht40_t6713_router_v3/Node14_bme680_sgp40_sht40_t6713_router_v3.ino b/Node14_bme680_sgp40_sht40_t6713_router_v3/Node14_bme680_sgp40_sht40_t6713_router_v3.ino new file mode 100644 index 0000000..a8695bb --- /dev/null +++ b/Node14_bme680_sgp40_sht40_t6713_router_v3/Node14_bme680_sgp40_sht40_t6713_router_v3.ino @@ -0,0 +1,494 @@ +// DFRobot Beetle ESP32-C6 Partition Scheme: Zigbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZR/ZC (coordinator,router) +// LED: GPIO15, on when HIGH + + + +#ifndef ZIGBEE_MODE_ZCZR +#error Zigbee coordinator/router mode is not selected in Tools->Zigbee mode +#endif + +#define DEBUG_TRACE // Comment out DEBUG_TRACE to reduce normal-path logging + +#include "Zigbee.h" +#include "Wire.h" +#include "bme68xLibrary.h" +#include "Adafruit_SHT4x.h" +#include "Adafruit_SGP40.h" + +// ----------------------------------------------------------------------------- +// Hardware definitions (shared I2C bus) +// ----------------------------------------------------------------------------- +#define LED_PIN 15 +#define I2C_SDA_PIN 22 +#define I2C_SCL_PIN 21 + +// T6713 I2C address and registers +#define T6713_ADDR 0x15 +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +// Endpoint numbers (reassigned for new sensors) +#define BME_TEMP_ENDPOINT 10 +#define BME_ANALOG_ENDPOINT 11 +#define SHT_SGP_TEMP_ENDPOINT 12 +#define SGP_ANALOG_ENDPOINT 13 +#define T6713_CO2_ENDPOINT 15 + +// Sensor objects +Bme68x bme; +Adafruit_SHT4x sht4; +Adafruit_SGP40 sgp; +ZigbeeTempSensor zbTempSensorBME(BME_TEMP_ENDPOINT); +ZigbeeAnalog zbAnalogBME(BME_ANALOG_ENDPOINT); +ZigbeeTempSensor zbTempSensorSHTSGP(SHT_SGP_TEMP_ENDPOINT); +ZigbeeAnalog zbAnalogSGP(SGP_ANALOG_ENDPOINT); +ZigbeeCarbonDioxideSensor zbCo2T6713(T6713_CO2_ENDPOINT); + +// ----------------------------------------------------------------------------- +// Health watchdog globals (updated for new sensors) +// ----------------------------------------------------------------------------- +SemaphoreHandle_t i2cMutex; +bool bmeFirstOk = false; +bool shtsgpFirstOk = false; +bool t6713FirstOk = false; + +// Last-change tracking +float lastTempBme = NAN, lastHumBme = NAN, lastGasRes = NAN; +unsigned long lastTempBmeChangeMs = 0, lastHumBmeChangeMs = 0, lastGasResChangeMs = 0; +float lastTempSht = NAN, lastHumSht = NAN, lastRawSgp = NAN; +unsigned long lastTempShtChangeMs = 0, lastHumShtChangeMs = 0, lastRawSgpChangeMs = 0; +int lastCo2T6713 = -1; +unsigned long lastCo2T6713ChangeMs = 0; +unsigned long lastZigbeeOkMs = 0; + +// Error counters +int bmeErrorCount = 0, shtsgpErrorCount = 0, t6713ErrorCount = 0; +const int maxI2cErrors = 10; + +// Watchdog thresholds +const unsigned long WATCHDOG_PERIOD_MS = 10000; // 10s +const unsigned long SENSOR_STUCK_TIMEOUT_MS = 30UL * 60UL * 1000UL; // 30min +const unsigned long ZIGBEE_DOWN_TIMEOUT_MS = 10UL * 60UL * 1000UL; // 10min + +// ----------------------------------------------------------------------------- +// Zigbee health touch after successful reports +// ----------------------------------------------------------------------------- +inline void zigbeeHealthTouch() { + if (Zigbee.connected()) lastZigbeeOkMs = millis(); +} + +// ----------------------------------------------------------------------------- +// Helper: I2C guarded execution (use mutex) +// ----------------------------------------------------------------------------- +#include +bool withI2C(std::function fn, uint32_t timeoutMs = 100) { + if (xSemaphoreTake(i2cMutex, pdMS_TO_TICKS(timeoutMs)) == pdTRUE) { + bool ok = fn(); + xSemaphoreGive(i2cMutex); + return ok; + } + return false; +} + +// ----------------------------------------------------------------------------- +// T6713 helper functions (unchanged) +// ----------------------------------------------------------------------------- +int readT6713() { + int result = -1; + bool ok = withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); Wire.write(0x8B); // 0x138B + Wire.write(0x00); Wire.write(0x01); + if (Wire.endTransmission() != 0) return false; + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() >= 4) { + Wire.read(); Wire.read(); // skip func+len + byte high = Wire.read(); + byte low = Wire.read(); + result = (high << 8) | low; + return true; + } + return false; + }); + if (!ok) result = -1; + return result; +} + +void configureT6713(bool enableABC) { + delay(1000); + // Optional status check + withI2C([&]() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); Wire.write(0x13); Wire.write(0x8A); // 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() >= 4) { + Wire.read(); Wire.read(); + uint16_t status = (Wire.read() << 8) | Wire.read(); +#ifdef DEBUG_TRACE + if (status == 0x08) Serial.println("T6713 Warming up..."); +#endif + } + return true; + }); + + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + byte error = Wire.endTransmission(); + if (error == 0) { +#ifdef DEBUG_TRACE + Serial.print("T6713 ABC Logic set to "); Serial.println(enableABC ? "ON" : "OFF"); +#endif + } else { +#ifdef DEBUG_TRACE + Serial.println("T6713 Failed to set ABC Logic"); +#endif + } + return (error == 0); + }); + delay(100); +} + +// ----------------------------------------------------------------------------- +// BME68x task (adapted, endpoint 10/11) +// ----------------------------------------------------------------------------- +static void bme680sensorvalueupdate(void *arg) { + for (;;) { + float temperature = NAN, humidity = NAN, gasResistance = NAN; + bme68xData data; + bool ok = withI2C([&]() { + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; + humidity = data.humidity; + gasResistance = data.gas_resistance; + return true; + } + return false; + }); + + if (ok) { + bmeErrorCount = 0; + unsigned long now = millis(); + if (!bmeFirstOk) { + bmeFirstOk = true; + lastTempBme = temperature; lastHumBme = humidity; lastGasRes = gasResistance; + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = now; + } else { + if (temperature != lastTempBme) { lastTempBme = temperature; lastTempBmeChangeMs = now; } + if (humidity != lastHumBme) { lastHumBme = humidity; lastHumBmeChangeMs = now; } + if (gasResistance != lastGasRes) { lastGasRes = gasResistance; lastGasResChangeMs = now; } + } + zbTempSensorBME.setTemperature(temperature); + zbTempSensorBME.setHumidity(humidity); + // zbTempSensorBME.report(); + zigbeeHealthTouch(); + zbAnalogBME.setAnalogInput(round(gasResistance)); + // zbAnalogBME.reportAnalogInput(); + zigbeeHealthTouch(); +#ifdef DEBUG_TRACE + Serial.printf("BME68x T:%.2fC H:%.2f%% Gas:%.2f ohm\n", temperature, humidity, gasResistance); +#endif + } else { + bmeErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("BME68x read error or I2C busy."); +#endif + if (bmeErrorCount >= maxI2cErrors) { + Serial.println("BME68x too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// SHT40/SGP40 task (from Node11, endpoint 12/13) +// ----------------------------------------------------------------------------- +static void sgp40sht40sensorvalueupdate(void *arg) { + for (;;) { + float currentTemp = NAN, currentHum = NAN; + uint16_t currentRaw = NAN; + + bool ok = withI2C([&]() { + sensors_event_t humidity, temp; + if (!sht4.getEvent(&humidity, &temp)) return false; + currentTemp = temp.temperature; + currentHum = humidity.relative_humidity; + + currentRaw = sgp.measureRaw(currentTemp, currentHum); + return true; + }); + + if (ok) { + shtsgpErrorCount = 0; + unsigned long now = millis(); + if (!shtsgpFirstOk) { + shtsgpFirstOk = true; + lastTempSht = currentTemp; lastHumSht = currentHum; lastRawSgp = currentRaw; + lastTempShtChangeMs = lastHumShtChangeMs = lastRawSgpChangeMs = now; + } else { + if (currentTemp != lastTempSht) { lastTempSht = currentTemp; lastTempShtChangeMs = now; } + if (currentHum != lastHumSht) { lastHumSht = currentHum; lastHumShtChangeMs = now; } + if (currentRaw != lastRawSgp) { lastRawSgp = currentRaw; lastRawSgpChangeMs = now; } + } + zbTempSensorSHTSGP.setTemperature(currentTemp); + zbTempSensorSHTSGP.setHumidity(currentHum); + // zbTempSensorSHTSGP.report(); + zigbeeHealthTouch(); + zbAnalogSGP.setAnalogInput(round(currentRaw)); + // zbAnalogSGP.reportAnalogInput(); + zigbeeHealthTouch(); +#ifdef DEBUG_TRACE + Serial.printf("SHT40/SGP40 T:%.2fC H:%.2f%% Raw:%d\n", currentTemp, currentHum, currentRaw); +#endif + } else { + shtsgpErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("SHT40/SGP40 read error or I2C busy."); +#endif + if (shtsgpErrorCount >= maxI2cErrors) { + Serial.println("SHT40/SGP40 too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// T6713 task (unchanged) +// ----------------------------------------------------------------------------- +static void t6713sensorvalueupdate(void *arg) { + for (;;) { + int co2t6713 = readT6713(); + if (co2t6713 >= 0) { + t6713ErrorCount = 0; + unsigned long now = millis(); + if (!t6713FirstOk) { + t6713FirstOk = true; + lastCo2T6713 = co2t6713; + lastCo2T6713ChangeMs = now; + } else if (co2t6713 != lastCo2T6713) { + lastCo2T6713 = co2t6713; + lastCo2T6713ChangeMs = now; +#ifdef DEBUG_TRACE + Serial.print("T6713 CO2: "); Serial.print(co2t6713); Serial.println(" ppm"); +#endif + } + zbCo2T6713.setCarbonDioxide(co2t6713); + // zbCo2T6713.report(); + zigbeeHealthTouch(); + } else { + t6713ErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("T6713 read error."); +#endif + if (t6713ErrorCount >= maxI2cErrors) { + Serial.println("T6713 too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// Watchdog task (updated checks for new sensors) +// ----------------------------------------------------------------------------- +void watchdogTask(void *param) { + for (;;) { +#ifdef DEBUG_TRACE + Serial.println("Watchdog ran."); +#endif + unsigned long now = millis(); + bool zigbeeBad = !Zigbee.connected() || (now - lastZigbeeOkMs > ZIGBEE_DOWN_TIMEOUT_MS); + bool bmeStuck = bmeFirstOk && ( + (now - lastTempBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastHumBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastGasResChangeMs > SENSOR_STUCK_TIMEOUT_MS)); + bool shtsgpStuck = shtsgpFirstOk && ( + (now - lastTempShtChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastHumShtChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastRawSgpChangeMs > SENSOR_STUCK_TIMEOUT_MS)); + bool t6713Stuck = t6713FirstOk && (now - lastCo2T6713ChangeMs > SENSOR_STUCK_TIMEOUT_MS); + + if (zigbeeBad || bmeStuck || shtsgpStuck || t6713Stuck) { + Serial.println("Watchdog fault detected, restarting..."); + delay(500); ESP.restart(); + } + vTaskDelay(pdMS_TO_TICKS(WATCHDOG_PERIOD_MS)); + } +} + +// ----------------------------------------------------------------------------- +// setup +// ----------------------------------------------------------------------------- +void setup() { + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + delay(100); + + // Global manufacturer/model + // Zigbee.setManufacturer("Espressif"); + // Zigbee.setModel("Node_New_BME680_T6713_SHT40_SGP40_v1"); + + // I2C init + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + i2cMutex = xSemaphoreCreateMutex(); + + // BME680 init + Serial.println("Connecting to BME680..."); + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); + + // Step-by-step status checks + if (bme.checkStatus() == BME68X_ERROR) { + Serial.println("❌ BME68X_ERROR: " + bme.statusString()); + } else if (bme.checkStatus() == BME68X_WARNING) { + Serial.println("⚠️ BME68X_WARNING: " + bme.statusString()); + } else { + Serial.println("✓ BME68X status OK"); + } + + + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + bme.setHeaterProf(300, 100); + bme.setOpMode(BME68X_FORCED_MODE); + zbTempSensorBME.setManufacturerAndModel("Espressif", "Node_14_bme680th"); + zbTempSensorBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorBME.setMinMaxValue(-20, 80); + zbTempSensorBME.setTolerance(1); + zbTempSensorBME.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorBME); + zbAnalogBME.setManufacturerAndModel("Espressif", "Node_14_bme680r"); + zbAnalogBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogBME.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogBME); + + // SHT40/SGP40 init + Serial.println("Initializing SHT40..."); + if (!sht4.begin(&Wire)) { + Serial.println("SHT40 not found! Check wiring."); + while (1) delay(10); + } + sht4.setPrecision(SHT4X_HIGH_PRECISION); + sht4.setHeater(SHT4X_NO_HEATER); + Serial.println("Initializing SGP40..."); + if (!sgp.begin(&Wire)) { + Serial.println("SGP40 not found! Check wiring."); + while (1) delay(10); + } + zbTempSensorSHTSGP.setManufacturerAndModel("Espressif", "Node_14_sht40sgp40th"); + zbTempSensorSHTSGP.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorSHTSGP.setMinMaxValue(-20, 80); + zbTempSensorSHTSGP.setTolerance(1); + zbTempSensorSHTSGP.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorSHTSGP); + zbAnalogSGP.setManufacturerAndModel("Espressif", "Node_14_sgp40raw"); + zbAnalogSGP.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogSGP.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogSGP); + + // T6713 config & endpoint + configureT6713(true); // Enable ABC + zbCo2T6713.setManufacturerAndModel("Espressif", "Node_14_t6713"); + zbCo2T6713.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbCo2T6713.setMinMaxValue(0, 10000); + Zigbee.addEndpoint(&zbCo2T6713); + + // Start Zigbee as router + Serial.println("Starting Zigbee..."); + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start! Rebooting..."); + ESP.restart(); + } + Serial.println("Zigbee started successfully! Connecting to network..."); + bool ledState = false; + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + if (millis() - startTime > timeoutMs) { + Serial.println(" timed out (60s). Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, LOW); + Serial.println(" connected!"); + lastZigbeeOkMs = millis(); + + // Create sensor tasks + xTaskCreate(bme680sensorvalueupdate, "bme_task", 4096, NULL, 10, NULL); + xTaskCreate(sgp40sht40sensorvalueupdate, "shtsgp_task", 4096, NULL, 10, NULL); + xTaskCreate(t6713sensorvalueupdate, "t6713_task", 4096, NULL, 10, NULL); + xTaskCreate(watchdogTask, "watchdog", 4096, NULL, 5, NULL); + + // Reporting configuration (after Zigbee.begin) + zbTempSensorBME.setReporting(60, 0, 0.5); + zbAnalogBME.setAnalogInputReporting(60, 600, 10); + zbTempSensorSHTSGP.setReporting(60, 0, 0.5); + zbAnalogSGP.setAnalogInputReporting(60, 600, 10); + zbCo2T6713.setReporting(30, 300, 10); +} + +// ----------------------------------------------------------------------------- +// loop (light - button reset + test commands) +// ----------------------------------------------------------------------------- +void loop() { + // Test commands via Serial + if (Serial.available()) { + char cmd = Serial.read(); + switch (cmd) { + case 'Z': // Force Zigbee failure (watchdog test) + Serial.println("SIM Zigbee disconnect test"); + lastZigbeeOkMs = 0; // Watchdog sees Zigbee down + break; + case 'E': // Force stuck sensor detection + Serial.println("SIM Stuck sensor test"); + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = 0; + lastTempShtChangeMs = lastHumShtChangeMs = lastRawSgpChangeMs = 0; + lastCo2T6713ChangeMs = 0; + break; + case 'R': // Manual restart + Serial.println("SIM Manual restart"); + ESP.restart(); + break; + } + } + + // Factory reset on long button press + static uint8_t button = BOOT_PIN; + if (digitalRead(button) == LOW) { // push button pressed + delay(100); // debounce + 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(); + ESP.restart(); + } + } + } + + vTaskDelay(pdMS_TO_TICKS(50)); +} diff --git a/Node14_dht11_router_v2/Node14_dht11_router_v2.ino b/Node14_dht11_router_v2/Node14_dht11_router_v2.ino new file mode 100644 index 0000000..fb49e8c --- /dev/null +++ b/Node14_dht11_router_v2/Node14_dht11_router_v2.ino @@ -0,0 +1,133 @@ +/* + * ESP32-C6 Zigbee Router with DHT11 Sensor + * + * Logic: + * 1. Initialize as a Zigbee Router (ZR). + * 2. Create an endpoint with Temperature and Humidity clusters. + * 3. Read DHT11 sensor periodically. + * 4. Update and report values to the Zigbee network. + * + * Libraries required: + * - EspZigbee (Standard with ESP32 Board package v3.0.0+) + * - DHT sensor library by Adafruit (Install via Library Manager) + */ + +#include "Zigbee.h" +#include "DHT.h" + +// --- Hardware Config --- +#define DHTPIN 17 // Pin connected to DHT11 Data +#define DHTTYPE DHT11 // Sensor type +#define DHTPOWER 4 // GPIO pin to power the sensor + +// --- Zigbee Config --- +// Identify the endpoint (arbitrary number, 1-240) +#define SENSOR_ENDPOINT_NUM 10 + +// --- Global Objects --- +DHT dht(DHTPIN, DHTTYPE); + +// Define the Zigbee Temperature Sensor object +// Note: Depending on the specific library version, this helper class +// might primarily handle Temperature. We will configure it to report. +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(SENSOR_ENDPOINT_NUM); + +// Timer for reporting +unsigned long lastReportTime = 0; +const unsigned long REPORT_INTERVAL = 10000; // Report every 10 seconds + +void setup() { + Serial.begin(115200); + + pinMode(DHTPOWER, OUTPUT); + digitalWrite(DHTPOWER, HIGH); // Power on the sensor + + // Initialize DHT Sensor + dht.begin(); + Serial.println("DHT11 Sensor Initialized"); + + // --- Zigbee Setup --- + + // 1. Set Manufacturer and Model details (visible in Home Assistant/Zigbee2MQTT) + zbTempSensor.setManufacturerAndModel("Espressif", "ESP32C6-Router-Temp"); + + // 2. Add the Temperature and Humidity clusters to the endpoint + // The default ZigbeeTempSensor includes the Temperature Measurement cluster. + // We explicitly try to set the sensor config. + // Note: If you need a dedicated Humidity cluster separate from this helper, + // you might need to use the generic EspZigbee::ZigbeeEP helper, but + // most modern helpers support adding standard clusters. + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + + + + // 3. Add Endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // 4. Initialize Zigbee as a ROUTER + // ZIGBEE_ROUTER: Mains-powered, always on, routes packets for other devices. + // Serial.println("Starting Zigbee as Router..."); + // if (!Zigbee.begin(ZIGBEE_ROUTER)) { + // Serial.println("Zigbee failed to start! Restarting..."); + // delay(1000); + // ESP.restart(); + // } + // Serial.println("Zigbee Started. Waiting for network..."); + + // Zigbee.factoryReset(); + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in Router mode + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + 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("Connected"); + +} + +void loop() { + // Check if enough time has passed to report data + if (millis() - lastReportTime > REPORT_INTERVAL) { + lastReportTime = millis(); + + // 1. Read Sensor + float temp = dht.readTemperature(); + float hum = dht.readHumidity(); + + // Check if read failed + if (isnan(temp) || isnan(hum)) { + Serial.println("Failed to read from DHT sensor!"); + return; + } + + Serial.printf("Temp: %.1f C, Humidity: %.1f %%\n", temp, hum); + + // 2. Update Zigbee Clusters + // The ZigbeeTempSensor class updates the local attribute + zbTempSensor.setTemperature(temp); + + // Note: If your specific version of ZigbeeTempSensor does not support setHumidity, + // you may need to add a separate Humidity endpoint or use raw attribute setting. + // However, recent ESP32-Arduino versions often bundle these. + zbTempSensor.setHumidity(hum); // Uncomment if supported by your version + + // 3. Report Values + // This triggers a report attribute command to the coordinator + zbTempSensor.report(); + } +} diff --git a/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1/.theia/launch.json b/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1/.theia/launch.json new file mode 100644 index 0000000..fef7b06 --- /dev/null +++ b/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1/.theia/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + }, + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + } + ] +} diff --git a/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1.ino b/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1.ino new file mode 100644 index 0000000..e3f1aaf --- /dev/null +++ b/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1/Node15_Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D_v1.ino @@ -0,0 +1,295 @@ +//Seeedstudio Xiao ESP32-C6 + + + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +//#include "DHT.h" +//#define DHTPIN 17 // Digital pin connected to the DHT sensor +//#define DHTPOWER 4 // GPIO pin to power the sensor +//https://github.com/adafruit/DHT-sensor-library/blob/master/examples/DHTtester/DHTtester.ino +//#define DHTTYPE DHT11 // DHT 11 +//DHT dht(DHTPIN, DHTTYPE); + + +#include +#include +#include "Adafruit_SHT31.h" +bool enableHeater = false; +uint8_t loopCnt = 0; +#define SHT31_POWER_PIN 16 // GPIO used to power the sensor +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 295 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +const int batteryPin = 0; // A0 +#define BAT_ADC_PIN A0 // ADC input pin +#define BAT_GPIO_ENABLE 17 // GPIO controlling R1 +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.2; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float x_corrected = x * 2 / 1000; + Serial.printf("mapFloat: x = %.2f° V, in_min = %.2f° V, in_max = %.2f%%\r\n", x_corrected, in_min, in_max); + float val; + val = (x_corrected - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(batteryPin); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature * 2; + + // Use DHT11 sensor + // Read temperature as Celsius (the default) + //float temperature = dht.readTemperature(); + //float temperature = 23.5; + float temperature = round(sht31.readTemperature() * 10) / 10.0; + // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) + //float humidity = dht.readHumidity(); + //float humidity = 43; + float humidity = round(sht31.readHumidity() * 10) / 10.0; + + // Check if any reads failed and exit early (to try again). + if (isnan(humidity) || isnan(temperature)) { + Serial.println(F("Failed to read from SHT31D sensor!")); + delay(100); + return; + } + + delay(100); + + digitalWrite(SHT31_POWER_PIN, LOW); // Power off sensor + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + + delay(1000); + + + + // Enable the voltage divider + digitalWrite(BAT_GPIO_ENABLE, HIGH); + delay(5); // Give time for voltage to stabilize + + // read the analog / millivolts value for pin 0: + int analogValue = analogRead(BAT_ADC_PIN); + int analogVolts = analogReadMilliVolts(BAT_ADC_PIN); + uint8_t percentage = mapFloat(analogVolts, minVoltage, maxVoltage); + // print out the values you read: + Serial.print("ADC analog value = "); + Serial.println(analogValue); + Serial.print("ADC millivolts value = "); + Serial.print(analogVolts); + Serial.println(" mV"); + // Please adjust the calculation coefficient according to the actual measurement. + Serial.print("BAT millivolts value = "); + Serial.print(analogVolts * 2); + Serial.println(" mV"); + Serial.print("BAT percentage value = "); + Serial.print(percentage); + Serial.println(" %"); + Serial.println("--------------"); + + zbTempSensor.setBatteryPercentage(percentage); + zbTempSensor.reportBatteryPercentage(); + + // Disable the divider to save power + // pinMode(BAT_GPIO_ENABLE, INPUT); // High-Z to avoid sinking current + digitalWrite(BAT_GPIO_ENABLE, LOW); + + + // Add small delay to allow the data to be sent before going to sleep + //delay(1000); + + digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level) + delay(200); // wait for a second + digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW + //delay(100); // wait for a second + + // Put device to deep sleep + Serial.println("Going to sleep now"); + delay(100); + esp_deep_sleep_start(); + // delay(1000); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + pinMode(SHT31_POWER_PIN, OUTPUT); + digitalWrite(SHT31_POWER_PIN, HIGH); // Power on the sensor + + + delay(1000); // Wait for a second to allow the Serial Monitor to open and DHT11 to stabilize + + Serial.println("Starting setup..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor_Node15"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 99); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 3000; + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + //dht.begin(); + //Serial.println(F("DHTxx test!")); + + Serial.println("SHT31 test"); + if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr + Serial.println("Couldn't find SHT31"); + while (1) delay(1); + } else { + Serial.println("SHT31 sensor initialized successfully"); + //Serial.print("Temp *C = "); Serial.print(sht31.readTemperature()); Serial.print("\t\t"); + //Serial.print("Hum. % = "); Serial.println(sht31.readHumidity()); + } + Serial.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) + Serial.println("ENABLED"); + else + Serial.println("DISABLED"); + + + + //set the resolution to 12 bits (0-4096) + analogReadResolution(12); + + pinMode(BAT_GPIO_ENABLE, OUTPUT); + + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); +} + +void loop() { + // 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(); + } + } + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); +} diff --git a/Node15_sht31d_router_v2/Node15_sht31d_router_v2.ino b/Node15_sht31d_router_v2/Node15_sht31d_router_v2.ino new file mode 100644 index 0000000..038d5e6 --- /dev/null +++ b/Node15_sht31d_router_v2/Node15_sht31d_router_v2.ino @@ -0,0 +1,272 @@ +/* + +Xiao ESP32-C6 + +NodeXX_Zigbee_SHT31D_Sleepy_v1.ino +DFRobot Beetle ESP32-C6 or Seeedstudio Xiao ESP32-C6 +Zigbee End Device (sleepy) with SHT31D temperature/humidity sensor +Battery powered with deep sleep support +Based on Node14 (multi-sensor router) + Node15 (SHT31D sleepy end device) +*/ + + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator/router mode is not selected in Tools > Zigbee mode" +#endif + +#define DEBUGTRACE // Comment out to reduce logging + +#include +#include +#include + +// ----------------------------------------------------------------------------- +// Hardware definitions +// ----------------------------------------------------------------------------- +#define LED_PIN LED_BUILTIN +#define I2C_SDA_PIN 22 +#define I2C_SCL_PIN 23 +#define SHT31_POWER_PIN 16 // Optional power control for SHT31D + +// Endpoint numbers +#define SHT31_TEMP_ENDPOINT 10 +#define SHT31_HUM_ENDPOINT 11 // Using analog for humidity if needed + +// Sensor object +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +// Zigbee objects +ZigbeeTempSensor zbTempSensorSHT31(SHT31_TEMP_ENDPOINT); + +// ----------------------------------------------------------------------------- +// Health monitoring globals +// ----------------------------------------------------------------------------- +SemaphoreHandle_t i2cMutex = NULL; +bool sht31FirstOk = false; +float lastTempSht31 = NAN, lastHumSht31 = NAN; +unsigned long lastTempSht31ChangeMs = 0, lastHumSht31ChangeMs = 0; +unsigned long lastZigbeeOkMs = 0; +int sht31ErrorCount = 0; +const int maxI2cErrors = 10; + +// Watchdog thresholds +const unsigned long WATCHDOG_PERIOD_MS = 10000; // 10s +const unsigned long SENSOR_STUCK_TIMEOUT_MS = 30UL * 60UL * 1000UL; // 30min +const unsigned long ZIGBEE_DOWN_TIMEOUT_MS = 10UL * 60UL * 1000UL; // 10min + +// ----------------------------------------------------------------------------- +// Zigbee health touch +// ----------------------------------------------------------------------------- +inline void zigbeeHealthTouch() { + if (Zigbee.connected()) { + lastZigbeeOkMs = millis(); + } +} + +// ----------------------------------------------------------------------------- +// Helper: I2C guarded execution +// ----------------------------------------------------------------------------- +#include +bool withI2C(std::function fn, uint32_t timeoutMs = 100) { + if (xSemaphoreTake(i2cMutex, pdMS_TO_TICKS(timeoutMs)) == pdTRUE) { + bool ok = fn(); + xSemaphoreGive(i2cMutex); + return ok; + } + return false; +} + +// ----------------------------------------------------------------------------- +// SHT31D sensor task +// ----------------------------------------------------------------------------- +static void sht31SensorValueUpdate(void* arg) { + for (;;) { + float temperature = NAN, humidity = NAN; + + // Read SHT31D with I2C protection + bool ok = withI2C([&]() -> bool { + temperature = sht31.readTemperature(); + humidity = sht31.readHumidity(); + return !isnan(temperature) && !isnan(humidity); + }); + + if (ok) { + sht31ErrorCount = 0; + unsigned long now = millis(); + + if (!sht31FirstOk) { + sht31FirstOk = true; + lastTempSht31 = temperature; + lastHumSht31 = humidity; + lastTempSht31ChangeMs = lastHumSht31ChangeMs = now; + } else { + if (temperature != lastTempSht31) { + lastTempSht31 = temperature; + lastTempSht31ChangeMs = now; + } + if (humidity != lastHumSht31) { + lastHumSht31 = humidity; + lastHumSht31ChangeMs = now; + } + } + + // Update and report Zigbee values + zbTempSensorSHT31.setTemperature(temperature); + zbTempSensorSHT31.setHumidity(humidity); + // zbTempSensorSHT31.report(); + zigbeeHealthTouch(); + +#ifdef DEBUGTRACE + Serial.printf("SHT31D T:%.2fC H:%.2f%%\n", temperature, humidity); +#endif + } else { + sht31ErrorCount++; +#ifdef DEBUGTRACE + Serial.println("SHT31D read error or I2C busy."); +#endif + if (sht31ErrorCount >= maxI2cErrors) { + Serial.println("SHT31D too many errors, restarting..."); + delay(200); + ESP.restart(); + } + } + + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s interval + } +} + +// ----------------------------------------------------------------------------- +// Watchdog task +// ----------------------------------------------------------------------------- +void watchdogTask(void* param) { + for (;;) { +#ifdef DEBUGTRACE + Serial.println("Watchdog ran."); +#endif + + unsigned long now = millis(); + bool zigbeeBad = !Zigbee.connected() || (now - lastZigbeeOkMs > ZIGBEE_DOWN_TIMEOUT_MS); + bool sht31Stuck = sht31FirstOk && + (now - lastTempSht31ChangeMs > SENSOR_STUCK_TIMEOUT_MS || + now - lastHumSht31ChangeMs > SENSOR_STUCK_TIMEOUT_MS); + + if (zigbeeBad || sht31Stuck) { + Serial.println("Watchdog fault detected, restarting..."); + delay(500); + ESP.restart(); + } + + vTaskDelay(pdMS_TO_TICKS(WATCHDOG_PERIOD_MS)); + } +} + +// ----------------------------------------------------------------------------- +// setup +// ----------------------------------------------------------------------------- +void setup() { + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + delay(100); + + // Global manufacturer/model + // Zigbee.setManufacturer("Espressif"); + // Zigbee.setModel("NodeXX-SHT31D-Router-v1"); + + // I2C init + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + i2cMutex = xSemaphoreCreateMutex(); + + // SHT31D init + Serial.println("Connecting to SHT31D..."); + pinMode(SHT31_POWER_PIN, OUTPUT); + digitalWrite(SHT31_POWER_PIN, HIGH); // Power on if controlled + delay(100); + + if (!sht31.begin(0x44)) { // 0x45 for alternate i2c addr + Serial.println("SHT31D not found! Check wiring."); + while (1) delay(10); + } + Serial.println("SHT31D initialized successfully!"); + + // Configure Zigbee endpoint + zbTempSensorSHT31.setManufacturerAndModel("Espressif", "Node_15-sht31d-th"); + zbTempSensorSHT31.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorSHT31.setMinMaxValue(-20, 80); + zbTempSensorSHT31.setTolerance(0.1); + zbTempSensorSHT31.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorSHT31); + + // Start Zigbee as router + Serial.println("Starting Zigbee..."); + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start! Rebooting..."); + ESP.restart(); + } + + Serial.println("Zigbee started successfully! Connecting to network..."); + bool ledState = false; + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; + + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + if (millis() - startTime > timeoutMs) { + Serial.println("\nConnection timed out (60s). Restarting..."); + ESP.restart(); + } + } + + digitalWrite(LED_PIN, LOW); + Serial.println("\nConnected!"); + lastZigbeeOkMs = millis(); + + // Create sensor tasks + xTaskCreate(sht31SensorValueUpdate, "sht31task", 4096, NULL, 10, NULL); + xTaskCreate(watchdogTask, "watchdog", 4096, NULL, 5, NULL); + + // Reporting configuration + zbTempSensorSHT31.setReporting(60, 0, 0.1); // Min 60s, default, tol 0.5C +} + +void loop() { + // Serial test commands + if (Serial.available()) { + char cmd = Serial.read(); + switch (cmd) { + case 'Z': // Force Zigbee failure watchdog test + Serial.println("SIM Zigbee disconnect test"); + lastZigbeeOkMs = 0; + break; + case 'E': // Force stuck sensor detection + Serial.println("SIM Stuck sensor test"); + lastTempSht31ChangeMs = lastHumSht31ChangeMs = 0; + break; + case 'R': // Manual restart + Serial.println("SIM Manual restart"); + ESP.restart(); + break; + } + } + + // Factory reset on long button press + static uint8_t button = BOOT_PIN; + if (digitalRead(button) == LOW) { // push button pressed + delay(100); // debounce + 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(); + ESP.restart(); + } + } + } + + vTaskDelay(pdMS_TO_TICKS(50)); +} diff --git a/Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino b/Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino new file mode 100644 index 0000000..018ab1f --- /dev/null +++ b/Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino @@ -0,0 +1,413 @@ +// DFRobot Beetle ESP32-C6 Partition Scheme: Zigbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZR/ZC (coordinator,router) +// LED: GPIO15, on when HIGH + + +// DFRobot FireBeetle2 ESP32-C6 +// Partition Scheme: Zigbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZR/ZC (coordinator,router) +// LED: LED_BUILTIN, on when HIGH +// Node16: BME680 + T6713 only + +#ifndef ZIGBEE_MODE_ZCZR +#error Zigbee coordinator/router mode is not selected in Tools->Zigbee mode +#endif + +#define DEBUG_TRACE // Comment out DEBUG_TRACE to reduce normal-path logging + +#include "Zigbee.h" +#include "Wire.h" +#include "bme68xLibrary.h" + +// ----------------------------------------------------------------------------- +// Hardware definitions (shared I2C bus) +// ----------------------------------------------------------------------------- + +#define LED_PIN LED_BUILTIN +#define I2C_SDA_PIN 17 +#define I2C_SCL_PIN 16 + +#define POWER_PIN 21 // GPIO pin to power the sensor + +// T6713 I2C address and registers +#define T6713_ADDR 0x15 +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +// Endpoint numbers (BME680 + T6713 only) +#define BME_TEMP_ENDPOINT 10 +#define BME_ANALOG_ENDPOINT 11 +#define T6713_CO2_ENDPOINT 12 + +// Sensor objects (BME680 + T6713 only) +Bme68x bme; +ZigbeeTempSensor zbTempSensorBME(BME_TEMP_ENDPOINT); +ZigbeeAnalog zbAnalogBME(BME_ANALOG_ENDPOINT); +ZigbeeCarbonDioxideSensor zbCo2T6713(T6713_CO2_ENDPOINT); + +// ----------------------------------------------------------------------------- +// Health watchdog globals (BME + T6713 only) +// ----------------------------------------------------------------------------- + +SemaphoreHandle_t i2cMutex; +bool bmeFirstOk = false; +bool t6713FirstOk = false; + +// Last-change tracking (BME + T6713 only) +float lastTempBme = NAN, lastHumBme = NAN, lastGasRes = NAN; +unsigned long lastTempBmeChangeMs = 0, lastHumBmeChangeMs = 0, lastGasResChangeMs = 0; +int lastCo2T6713 = -1; +unsigned long lastCo2T6713ChangeMs = 0; +unsigned long lastZigbeeOkMs = 0; + +// Error counters (BME + T6713 only) +int bmeErrorCount = 0, t6713ErrorCount = 0; +const int maxI2cErrors = 10; + +// Watchdog thresholds +const unsigned long WATCHDOG_PERIOD_MS = 10000; // 10s +const unsigned long SENSOR_STUCK_TIMEOUT_MS = 30UL * 60UL * 1000UL; // 30min +const unsigned long ZIGBEE_DOWN_TIMEOUT_MS = 10UL * 60UL * 1000UL; // 10min + +// ----------------------------------------------------------------------------- +// Zigbee health touch after successful reports +// ----------------------------------------------------------------------------- + +inline void zigbeeHealthTouch() { + if (Zigbee.connected()) lastZigbeeOkMs = millis(); +} + +// ----------------------------------------------------------------------------- +// Helper: I2C guarded execution (use mutex) +// ----------------------------------------------------------------------------- + +#include +bool withI2C(std::function fn, uint32_t timeoutMs = 100) { + if (xSemaphoreTake(i2cMutex, pdMS_TO_TICKS(timeoutMs)) == pdTRUE) { + bool ok = fn(); + xSemaphoreGive(i2cMutex); + return ok; + } + return false; +} + +// ----------------------------------------------------------------------------- +// T6713 helper functions (unchanged) +// ----------------------------------------------------------------------------- + +int readT6713() { + int result = -1; + bool ok = withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); Wire.write(0x8B); // 0x138B + Wire.write(0x00); Wire.write(0x01); + if (Wire.endTransmission() != 0) return false; + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() >= 4) { + Wire.read(); Wire.read(); // skip func+len + byte high = Wire.read(); + byte low = Wire.read(); + result = (high << 8) | low; + return true; + } + return false; + }); + if (!ok) result = -1; + return result; +} + +void configureT6713(bool enableABC) { + delay(1000); + // Optional status check + withI2C([&]() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); Wire.write(0x13); Wire.write(0x8A); // 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() >= 4) { + Wire.read(); Wire.read(); + uint16_t status = (Wire.read() << 8) | Wire.read(); +#ifdef DEBUG_TRACE + if (status == 0x08) Serial.println("T6713 Warming up..."); +#endif + } + return true; + }); + + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + byte error = Wire.endTransmission(); + if (error == 0) { +#ifdef DEBUG_TRACE + Serial.print("T6713 ABC Logic set to "); Serial.println(enableABC ? "ON" : "OFF"); +#endif + } else { +#ifdef DEBUG_TRACE + Serial.println("T6713 Failed to set ABC Logic"); +#endif + } + return (error == 0); + }); + delay(100); +} + +// ----------------------------------------------------------------------------- +// BME68x task (endpoint 10/11) +// ----------------------------------------------------------------------------- + +static void bme680sensorvalueupdate(void *arg) { + for (;;) { + float temperature = NAN, humidity = NAN, gasResistance = NAN; + bme68xData data; + bool ok = withI2C([&]() { + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; + humidity = data.humidity; + gasResistance = data.gas_resistance; + return true; + } + return false; + }); + + if (ok) { + bmeErrorCount = 0; + unsigned long now = millis(); + if (!bmeFirstOk) { + bmeFirstOk = true; + lastTempBme = temperature; lastHumBme = humidity; lastGasRes = gasResistance; + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = now; + } else { + if (temperature != lastTempBme) { lastTempBme = temperature; lastTempBmeChangeMs = now; } + if (humidity != lastHumBme) { lastHumBme = humidity; lastHumBmeChangeMs = now; } + if (gasResistance != lastGasRes) { lastGasRes = gasResistance; lastGasResChangeMs = now; } + } + + zbTempSensorBME.setTemperature(temperature); + zbTempSensorBME.setHumidity(humidity); + zigbeeHealthTouch(); + + zbAnalogBME.setAnalogInput(round(gasResistance)); + zigbeeHealthTouch(); + +#ifdef DEBUG_TRACE + Serial.printf("BME68x T:%.2fC H:%.2f%% Gas:%.2f ohm\n", temperature, humidity, gasResistance); +#endif + } else { + bmeErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("BME68x read error or I2C busy."); +#endif + if (bmeErrorCount >= maxI2cErrors) { + Serial.println("BME68x too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// T6713 task (endpoint 15) +// ----------------------------------------------------------------------------- + +static void t6713sensorvalueupdate(void *arg) { + for (;;) { + int co2t6713 = readT6713(); + if (co2t6713 >= 0) { + t6713ErrorCount = 0; + unsigned long now = millis(); + if (!t6713FirstOk) { + t6713FirstOk = true; + lastCo2T6713 = co2t6713; + lastCo2T6713ChangeMs = now; + } else if (co2t6713 != lastCo2T6713) { + lastCo2T6713 = co2t6713; + lastCo2T6713ChangeMs = now; +#ifdef DEBUG_TRACE + Serial.print("T6713 CO2: "); Serial.print(co2t6713); Serial.println(" ppm"); +#endif + } + + zbCo2T6713.setCarbonDioxide(co2t6713); + zigbeeHealthTouch(); + } else { + t6713ErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("T6713 read error."); +#endif + if (t6713ErrorCount >= maxI2cErrors) { + Serial.println("T6713 too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// Watchdog task (BME + T6713 only) +// ----------------------------------------------------------------------------- + +void watchdogTask(void *param) { + for (;;) { +#ifdef DEBUG_TRACE + Serial.println("Watchdog ran."); +#endif + unsigned long now = millis(); + bool zigbeeBad = !Zigbee.connected() || (now - lastZigbeeOkMs > ZIGBEE_DOWN_TIMEOUT_MS); + bool bmeStuck = bmeFirstOk && ( + (now - lastTempBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastHumBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastGasResChangeMs > SENSOR_STUCK_TIMEOUT_MS)); + bool t6713Stuck = t6713FirstOk && (now - lastCo2T6713ChangeMs > SENSOR_STUCK_TIMEOUT_MS); + + if (zigbeeBad || bmeStuck || t6713Stuck) { + Serial.println("Watchdog fault detected, restarting..."); + delay(500); ESP.restart(); + } + vTaskDelay(pdMS_TO_TICKS(WATCHDOG_PERIOD_MS)); + } +} + +// ----------------------------------------------------------------------------- +// setup +// ----------------------------------------------------------------------------- + +void setup() { + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); // Power on the sensor(s) + + delay(100); + + // I2C init + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + i2cMutex = xSemaphoreCreateMutex(); + + // BME680 init + Serial.println("Connecting to BME680..."); + bme.begin(BME68X_I2C_ADDR_LOW, Wire); // BME68X_I2C_ADDR_LOW, BME68X_I2C_ADDR_HIGH + if (bme.checkStatus() == BME68X_ERROR) { + Serial.println("❌ BME68X_ERROR: " + bme.statusString()); + } else if (bme.checkStatus() == BME68X_WARNING) { + Serial.println("⚠️ BME68X_WARNING: " + bme.statusString()); + } else { + Serial.println("✓ BME68X status OK"); + } + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + bme.setHeaterProf(300, 100); + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensorBME.setManufacturerAndModel("Espressif", "Node16_bme680th"); + zbTempSensorBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorBME.setMinMaxValue(-20, 80); + zbTempSensorBME.setTolerance(1); + zbTempSensorBME.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorBME); + + zbAnalogBME.setManufacturerAndModel("Espressif", "Node16_bme680r"); + zbAnalogBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogBME.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogBME); + + // T6713 config & endpoint + configureT6713(true); // Enable ABC + zbCo2T6713.setManufacturerAndModel("Espressif", "Node16_t6713"); + zbCo2T6713.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbCo2T6713.setMinMaxValue(0, 10000); + Zigbee.addEndpoint(&zbCo2T6713); + + // Start Zigbee as router + Serial.println("Starting Zigbee..."); + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start! Rebooting..."); + ESP.restart(); + } + Serial.println("Zigbee started successfully! Connecting to network..."); + bool ledState = false; + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + if (millis() - startTime > timeoutMs) { + Serial.println(" timed out (60s). Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, LOW); + Serial.println(" connected!"); + lastZigbeeOkMs = millis(); + + // Create sensor tasks + xTaskCreate(bme680sensorvalueupdate, "bme_task", 4096, NULL, 10, NULL); + xTaskCreate(t6713sensorvalueupdate, "t6713_task", 4096, NULL, 10, NULL); + xTaskCreate(watchdogTask, "watchdog", 4096, NULL, 5, NULL); + + // Reporting configuration (after Zigbee.begin) + zbTempSensorBME.setReporting(60, 0, 0.5); + zbAnalogBME.setAnalogInputReporting(60, 600, 10); + zbCo2T6713.setReporting(30, 300, 10); +} + +// ----------------------------------------------------------------------------- +// loop (light - button reset + test commands) +// ----------------------------------------------------------------------------- + +void loop() { + // Test commands via Serial + if (Serial.available()) { + char cmd = Serial.read(); + switch (cmd) { + case 'Z': // Force Zigbee failure (watchdog test) + Serial.println("SIM Zigbee disconnect test"); + lastZigbeeOkMs = 0; // Watchdog sees Zigbee down + break; + case 'E': // Force stuck sensor detection + Serial.println("SIM Stuck sensor test"); + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = 0; + lastCo2T6713ChangeMs = 0; + break; + case 'R': // Manual restart + Serial.println("SIM Manual restart"); + ESP.restart(); + break; + } + } + + // Factory reset on long button press + static uint8_t button = BOOT_PIN; + if (digitalRead(button) == LOW) { // push button pressed + delay(100); // debounce + 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(); + ESP.restart(); + } + } + } + + vTaskDelay(pdMS_TO_TICKS(50)); +} diff --git a/Node16_bme680_t6713_sleepy_v1/Node16_bme680_t6713_sleepy_v1.ino b/Node16_bme680_t6713_sleepy_v1/Node16_bme680_t6713_sleepy_v1.ino new file mode 100644 index 0000000..a6f20a8 --- /dev/null +++ b/Node16_bme680_t6713_sleepy_v1/Node16_bme680_t6713_sleepy_v1.ino @@ -0,0 +1,443 @@ +/* +Device: DF Robot Firebeetle 2 ESP32-C6 + +*/ + + + + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +// Uncomment the following line to display debug traces in serial monitor of Arduino IDE +#define DEBUG_TRACE +#include "Zigbee.h" +//#include +//#include +#include "Arduino.h" +#include +#include "TelaireT6713.h" + +// Define the I2C pins +#define SCL_PIN 16 +#define SDA_PIN 17 + +#define BAT_ADC_PIN 0 // ADC input pin + +#define POWER_PIN 21 // GPIO pin to power the sensor + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 300 /* Sleep for 10 minutes */ + + +/* Zigbee temperature + humidity sensor configuration */ +#define BME_TEMP_SENSOR_ENDPOINT_NUMBER 10 +ZigbeeTempSensor zbTempSensor_bme = ZigbeeTempSensor(BME_TEMP_SENSOR_ENDPOINT_NUMBER); + +#define BME_CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_bme = ZigbeeCarbonDioxideSensor(BME_CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + + +#define T6713_CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 12 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_t6713 = ZigbeeCarbonDioxideSensor(T6713_CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +TelaireT6713 co2Sensor; + + + +/* Zigbee contact sensor configuration */ +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// uint8_t float_switch_pin = 3; +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); + + + +// #define MAGNETIC_SENSOR_PIN 12 +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); +// bool contact_open = false; + + + +/* Zigbee analog device configuration */ +// #define ANALOG_DEVICE_ENDPOINT_NUMBER 15 +// uint8_t analogPin = 3; +// ZigbeeAnalog zbAnalogDevice = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.0; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float val; + val = (x - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(BAT_ADC_PIN); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + +// Get data from BME280 sensor and go to deep sleep mode +void meausureAndSleep() { + // Measure temperature sensor value + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + float vBat; + + // BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + // BME280::PresUnit presUnit(BME280::PresUnit_hPa); + // Read temperature and humidity on BME280 sensor + // sensor.read(pressure, temperature, humidity, tempUnit, presUnit); + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + // Set the desired settings for the BME680 + //bme.amb_temp = 25; // Set ambient temperature for compensation + //bme.meas_status = 0; // Clear previous measurement status + // Perform a measurement + //rslt = bme68x_get_sensor_data(BME68X_ALL, &data, &bme); + //if (rslt == BME68X_OK) { + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + + + +// // Checking pin for contact change +// static bool contact = false; +// if (digitalRead(float_switch_pin) == HIGH && !contact) { +// // Update contact sensor value +// // Serial.println("Float sensor: true"); +// zbContactSwitch.setOpen(); +// contact = true; +// } else if (digitalRead(float_switch_pin) == LOW && contact) { +// // Serial.println("Float sensor: true"); +// zbContactSwitch.setClosed(); +// contact = false; +// } +// #ifdef DEBUG_TRACE +// Serial.println(contact ? "Float sensor: true" : "Float sensor: false"); +// #endif + + + // // Read ADC value and update the analog value every 2s + // float analog = (float)analogRead(analogPin); + // Serial.printf("Updating analog input to %.1f\r\n", analog); + // zbAnalogDevice.setAnalogInput(analog); + // delay(100); + // // Analog input supports reporting + // zbAnalogDevice.reportAnalogInput(); + + + + int co2ppm = co2Sensor.readCO2(); + if (co2ppm >= 0) { + Serial.print("CO2: "); Serial.print(co2ppm); Serial.println(" ppm"); + } else { + Serial.println("CO2 read error"); + } + + + + + delay(100); + + digitalWrite(POWER_PIN, LOW); // Power off sensor + + + + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_bme.setTemperature(temperature); + zbTempSensor_bme.setHumidity(humidity); + //zbTempSensor.setGasResistance(gasResistance); // Assuming you have a method for gas resistance + + + // Measure battery voltage + vBat = getVbatt(); + percentage = mapFloat(vBat, minVoltage, maxVoltage); +#ifdef DEBUG_TRACE + Serial.printf("Battery: %.2fV (%d%%)\n", vBat, percentage); +#endif + // Update battery percentage + zbTempSensor_bme.setBatteryPercentage(percentage); + //zbTempSensor.setBatteryVoltage(vBat * 10); // voltage in 100mV + + + // Magnetic contact sensor + // static bool contact = false; + // if (digitalRead(MAGNETIC_SENSOR_PIN) == HIGH && !contact) { + // // Update contact sensor value + // zbContactSwitch.setOpen(); + // contact = true; + // Serial.printf("contact = true"); + // } else if (digitalRead(MAGNETIC_SENSOR_PIN) == LOW && contact) { + // zbContactSwitch.setClosed(); + // contact = false; + // Serial.printf("contact = false"); + // } + + + // Report values + zbTempSensor_bme.report(); + zbTempSensor_bme.reportBatteryPercentage(); + + zbCarbonDioxideSensor_bme.setCarbonDioxide(gasResistance); + zbCarbonDioxideSensor_bme.report(); + + zbCarbonDioxideSensor_t6713.setCarbonDioxide(co2ppm); + zbCarbonDioxideSensor_t6713.report(); + +#ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); +#endif + // Turn on the builtin LED for a very short time + flashLED(); + // Add small delay to allow the data to be sent before going to sleep + delay(500); + // Put device to deep sleep +#ifdef DEBUG_TRACE + Serial.println("Going to sleep now"); +#endif + esp_deep_sleep_start(); + // delay(2000); +} + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + +/********************* Arduino functions **************************/ +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Configure use of external antenna + // pinMode(WIFI_ENABLE, OUTPUT); // pinMode(3, OUTPUT); + // digitalWrite(WIFI_ENABLE, LOW); // digitalWrite(3, LOW); // Activate RF switch control + // delay(100); + // pinMode(WIFI_ANT_CONFIG, OUTPUT); // pinMode(14, OUTPUT); + // digitalWrite(WIFI_ANT_CONFIG, HIGH); // digitalWrite(14, HIGH); // Use external antenna + + // Configure builtin LED and turn it OFF (HIGH) + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); // Power on the sensor(s) + + + + /* + // Init BME280 sensor + Wire.begin(); + while (!sensor.begin()) { +#ifdef DEBUG_TRACE + Serial.println("Could not find BME280 sensor!"); +#endif + delay(1000); + } + */ + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_LOW, Wire); // BME68X_I2C_ADDR_HIGH=0x76 (SDO CONNECTED TO VCC), BME68X_I2C_ADDR_LOW=0x77 (SDO CONNECTED TO GND) + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + // Configure A0 as ADC input for reading battery voltage + pinMode(BAT_ADC_PIN, INPUT); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + // Optional: set Zigbee device name and model + zbTempSensor_bme.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor_Node16"); + //zbCarbonDioxideSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor"); + + // Set minimum and maximum temperature measurement value + zbTempSensor_bme.setMinMaxValue(-20, 80); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_bme.setTolerance(1); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + //zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + zbTempSensor_bme.setPowerSource(ZB_POWER_SOURCE_BATTERY); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_bme.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_bme); + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor_bme.setMinMaxValue(0, 150000000); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor_bme); + + + // pinMode(MAGNETIC_SENSOR_PIN, INPUT_PULLUP); // Assuming switch pulls LOW when closed + // Zigbee.addEndpoint(&zbContactSwitch); + + // pinMode(float_switch_pin, INPUT_PULLUP); + // Zigbee.addEndpoint(&zbContactSwitch); + + + // // Set analog resolution to 10 bits + // analogReadResolution(10); + // // Add analog clusters to Zigbee Analog according your needs + // zbAnalogDevice.addAnalogInput(); + // // Add endpoints to Zigbee Core + // Zigbee.addEndpoint(&zbAnalogDevice); + // zbAnalogDevice.setAnalogInputReporting(5, 60, 1.0); // Example: report every 5–60s if change >= 1.0 + + + // Telaire CO2 sensor init + co2Sensor.setI2CPins(SDA_PIN, SCL_PIN); + co2Sensor.setAddress(0x15); + co2Sensor.begin(); + co2Sensor.enableABC(); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor_t6713.setMinMaxValue(0, 100000); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor_t6713); + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + // If Zigbee does not start with 30s default timeout (ZB_BEGIN_TIMEOUT_DEFAULT) then restart +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); // If Zigbee failed to start, reboot the device and try again + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + //zbCarbonDioxideSensor.setReporting(0, 30, 0); + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); + // Call the function to measure temperature and put the device to deep sleep + // meausureAndSleep(); +} + +void loop() { + // No actions are performed in the loop (the ESP32C6 enters the setup function when it exits deep sleep). + meausureAndSleep(); +} + + + + +x \ No newline at end of file diff --git a/Node16_bme680_t6713_sleepy_v1/TelaireT6713.cpp b/Node16_bme680_t6713_sleepy_v1/TelaireT6713.cpp new file mode 100644 index 0000000..8c66b6d --- /dev/null +++ b/Node16_bme680_t6713_sleepy_v1/TelaireT6713.cpp @@ -0,0 +1,112 @@ +#include "TelaireT6713.h" + +TelaireT6713::TelaireT6713(uint8_t address, uint8_t sda, uint8_t scl) + : _address(address), _sda(sda), _scl(scl) {} + +void TelaireT6713::setI2CPins(uint8_t sda, uint8_t scl) { + _sda = sda; + _scl = scl; +} + +void TelaireT6713::setAddress(uint8_t address) { + _address = address; +} + +void TelaireT6713::begin() { + Wire.begin(_sda, _scl); + delay(1000); + Serial.println("Telaire T6713 Initialized."); + printSensorStatus(); +} + +int TelaireT6713::readCO2(bool debug) { + int data[4]; + + Wire.beginTransmission(_address); + Wire.write(0x04); Wire.write(0x13); Wire.write(0x8B); + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + + delay(2000); + + Wire.requestFrom(_address, (uint8_t)4); + if (Wire.available() < 4) { + if (debug) Serial.println("Error: Less than 4 bytes received"); + return -1; + } + + data[0] = Wire.read(); + data[1] = Wire.read(); + data[2] = Wire.read(); + data[3] = Wire.read(); + + if (debug) { + Serial.print("FUNC: 0x"); Serial.println(data[0], HEX); + Serial.print("BYTE COUNT: 0x"); Serial.println(data[1], HEX); + Serial.print("MSB: 0x"); Serial.println(data[2], HEX); + Serial.print("LSB: 0x"); Serial.println(data[3], HEX); + } + + int ppm = ((data[2] & 0x3F) << 8) | data[3]; + return ppm; +} + +void TelaireT6713::enableABC() { + uint8_t cmd[] = { 0x05, 0x03, 0xEE, 0xFF, 0x00 }; + sendCommand(cmd, sizeof(cmd)); + Serial.println("ABC Enabled."); +} + +void TelaireT6713::disableABC() { + uint8_t cmd[] = { 0x05, 0x03, 0xEE, 0x00, 0x00 }; + sendCommand(cmd, sizeof(cmd)); + Serial.println("ABC Disabled."); +} + +void TelaireT6713::printSensorStatus() { + uint8_t statusCmd[] = { 0x04, 0x13, 0x8A, 0x00, 0x01 }; + sendCommand(statusCmd, sizeof(statusCmd)); + delay(100); + + uint8_t response[4]; + if (!readBytes(response, 4)) { + Serial.println("Failed to read sensor status."); + return; + } + + uint8_t msb = response[2]; + uint8_t lsb = response[3]; + + Serial.print("Sensor status: "); + if (msb == 0x00 && lsb == 0x00) Serial.println("No error."); + else if (msb == 0x00 && lsb == 0x01) Serial.println("Error condition."); + else if (msb == 0x00 && lsb == 0x02) Serial.println("Flash error."); + else if (msb == 0x00 && lsb == 0x03) Serial.println("Calibration error."); + else if (msb == 0x04 && lsb == 0x00) Serial.println("Reboot."); + else if (msb == 0x08 && lsb == 0x00) Serial.println("Warm-up mode."); + else if (msb == 0x80 && lsb == 0x00) Serial.println("Single point calibration."); + else { + Serial.print("Unknown status (0x"); + Serial.print(msb, HEX); + Serial.print(" 0x"); + Serial.print(lsb, HEX); + Serial.println(")"); + } +} + +void TelaireT6713::sendCommand(const uint8_t* cmd, size_t len) { + Wire.beginTransmission(_address); + for (size_t i = 0; i < len; ++i) { + Wire.write(cmd[i]); + } + Wire.endTransmission(); +} + +bool TelaireT6713::readBytes(uint8_t* buffer, size_t length) { + Wire.requestFrom(_address, (uint8_t)length); + size_t i = 0; + while (Wire.available() && i < length) { + buffer[i++] = Wire.read(); + } + return i == length; +} diff --git a/Node16_bme680_t6713_sleepy_v1/TelaireT6713.h b/Node16_bme680_t6713_sleepy_v1/TelaireT6713.h new file mode 100644 index 0000000..7c00c5e --- /dev/null +++ b/Node16_bme680_t6713_sleepy_v1/TelaireT6713.h @@ -0,0 +1,26 @@ +#ifndef TELAIRE_T6713_H +#define TELAIRE_T6713_H + +#include +#include + +class TelaireT6713 { + public: + TelaireT6713(uint8_t address = 0x15, uint8_t sda = 8, uint8_t scl = 14); + void begin(); + int readCO2(bool debug = false); + void enableABC(); + void disableABC(); + void printSensorStatus(); + void setI2CPins(uint8_t sda, uint8_t scl); + void setAddress(uint8_t address); + + private: + uint8_t _address; + uint8_t _sda, _scl; + + void sendCommand(const uint8_t* cmd, size_t len); + bool readBytes(uint8_t* buffer, size_t length); +}; + +#endif diff --git a/Node17_bme680_scd41_t6713_c4001_router_v2/Node17_bme680_scd41_t6713_c4001_router_v2.ino b/Node17_bme680_scd41_t6713_c4001_router_v2/Node17_bme680_scd41_t6713_c4001_router_v2.ino new file mode 100644 index 0000000..a48e2bd --- /dev/null +++ b/Node17_bme680_scd41_t6713_c4001_router_v2/Node17_bme680_scd41_t6713_c4001_router_v2.ino @@ -0,0 +1,1033 @@ +// DFRobot Beetle ESP32-C6 +// Partition Scheme: ZIgbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZRZC (coordinator,router) + + + + + + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + + +#include "Zigbee.h" + +#define LED_PIN 15 + + + + + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds - adjust as needed +const unsigned long TRIGGER_DELAY = 10; // 10 -> 100 ms + + + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/500, /*trig*/500)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(8)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(8)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/TRIGGER_DELAY, /*keep*/OCCUPANCY_TIMEOUT)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + + +// 1. Define the task function (Global scope, outside setup/loop) +void pirTask(void * parameter) { + // Move the static variable here. It doesn't need to be 'static' anymore + // because this function only runs once and stays in the loop below. + // bool occupancy = false; + + // 2. Infinite Loop: Tasks must never return! + for(;;) { + // --- Your Original Logic Start --- + + if (currentMode == eExitMode) { + bool motionNow = radar.motionDetection(); + + if (motionNow && !lastOccupancy) { + // Motion STARTED → Set occupancy ON + Serial.println("MOTION DETECTED → OCCUPANCY ON"); + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + + } else if (motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion still present → timeout reset"); + occupancyStartTime = millis(); + + } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // TIMEOUT → Clear occupancy + Serial.println("OCCUPANCY TIMEOUT → OFF"); + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + + } else if (!motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion ended → timeout started"); + // occupancyStartTime = millis(); + } + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + + // --- Your Original Logic End --- + + // 3. CRITICAL: Delay to yield control + // Polling a PIR every 50ms is plenty fast and saves CPU. + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + + + + + + + + + +// Define your custom SCL/SDA pins +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin +// Create custom I2C instance +// TwoWire sharedI2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) + + +// #include +// // DFRobot_SCD4X SCD4X(&Wire, /*i2cAddr = */SCD4X_I2C_ADDR); +// // SCD41 with custom I2C +// DFRobot_SCD4X SCD4X(&sharedI2C, SCD4X_I2C_ADDR); + +#include +#include +#include + +SensirionI2cScd4x scd41; + + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +#define TEMP_SENSOR_ENDPOINT_NUMBER 12 +ZigbeeTempSensor zbTempSensor_SCD4X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + + +static void scd4x_sensor_value_update(void *arg) { + for (;;) { + + // --- Read SCD41 --- + uint16_t co2_scd = 0; + float temperature_scd = 0.0f; + float humidity_scd = 0.0f; + bool scdReady = false; + + uint16_t error = scd41.readMeasurement(co2_scd, temperature_scd, humidity_scd); + if (error == 0 && co2_scd != 0) { + scdReady = true; + } + + if (scdReady) { + + zbCarbonDioxideSensor.setCarbonDioxide(co2_scd); + zbCarbonDioxideSensor.report(); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_SCD4X.setTemperature(temperature_scd); + zbTempSensor_SCD4X.setHumidity(humidity_scd); + // Report temperature and humidity values + zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + } + + #ifdef DEBUG_TRACE + Serial.print("[SCD41] CO2: "); Serial.print(co2_scd); Serial.print(" ppm"); + Serial.print(" | Temp: "); Serial.print(temperature_scd); Serial.print(" C"); + Serial.print(" | Hum: "); Serial.print(humidity_scd); Serial.println(" %"); + #endif + + + delay(10000); + } +} + + + + + + + + + +// --- BME680 Settings --- + +#include +Bme68x bme; +// TwoWire BME68X_I2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) +// #include // BME680 library +// DFRobot_BME680_I2C bme680(0x76); // 0x76 +// #include +// #include "Adafruit_BME680.h" +// Adafruit_BME680 bme680; +unsigned long bme_report_time = millis(); + +#define TEMP_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 14 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + +/************************ Temp sensor *****************************/ +static void bme680_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_BME68X.setTemperature(temperature); + zbTempSensor_BME68X.setHumidity(humidity); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("BME680: Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + delay(10000); + } +} + + + + + + + + + +// --- T6713 Settings --- +#define T6713_ADDR 0x15 +// T6713 Register Addresses (Modbus) +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +unsigned long t6713_report_time = millis(); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713 15 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_T6713 = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713); + + +static void t6713_sensor_value_update(void *arg) { + for (;;) { + + // --- Read T6713 (CO2) --- + int co2_t6713 = readT6713(); + if (co2_t6713 >= 0) { + Serial.print("T6713 | CO2: "); Serial.print(co2_t6713); Serial.println(" ppm"); + zbCarbonDioxideSensor_T6713.setCarbonDioxide(co2_t6713); + zbCarbonDioxideSensor_T6713.report(); + t6713_report_time = millis(); + } + // else { + // Serial.println("T6713 | Read Error"); + // } + + delay(10000); + } +} + + +// Helper function for T6713 +int readT6713() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); // Address High + Wire.write(0x8B); // Address Low + Wire.write(0x00); + Wire.write(0x01); // Length (1 register) + if (Wire.endTransmission() != 0) return -1; + + delay(10); // Processing delay + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Skip Func & Len + byte high = Wire.read(); + byte low = Wire.read(); + return (high << 8) | low; + } + return -1; +} + + +void configureT6713(bool enableABC) { + // 1. Wait for Sensor Warm-up (at least 500ms after power on, datasheet says much longer for accuracy) + delay(1000); + + // 2. Check Status Register (Optional but good practice) + // We read register 0x138A (5002) to check for errors/warmup + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); + Wire.write(0x13); Wire.write(0x8A); // Address 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Func, Len + uint16_t status = (Wire.read() << 8) | Wire.read(); + // Bit 3 is Warm-up mode. If 1, sensor is still warming up. + if (status & 0x08) { + Serial.println("T6713: Warming up..."); + } + } + + // 3. Configure ABC Logic (Automatic Background Calibration) + // Write to Register 0x03EE (1006). Value: 0xFF00 = Enable, 0x0000 = Disable + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Function: Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + + byte error = Wire.endTransmission(); + if (error == 0) { + Serial.print("T6713: ABC Logic set to "); + Serial.println(enableABC ? "ON" : "OFF"); + } else { + Serial.println("T6713: Failed to set ABC Logic"); + } + + // 4. Wait for the write to "stick" + delay(100); +} + + + + + + + + + + + + + +void setup() { + Serial.begin(115200); + + pinMode(LED_PIN, OUTPUT); + bool ledState = false; + digitalWrite(LED_PIN, HIGH); + + + // while (!Serial); + // unsigned long start = millis(); + // while (!Serial && millis() - start < 3000); + delay(100); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + + + + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + // Initialize custom I2C with YOUR pins + // SCD41_I2C.begin(SCD41_SDA_PIN, SCD41_SCL_PIN, 100000); // 100kHz standard + // Initialize SHARED I2C bus ONCE + // sharedI2C.begin(I2C_SDA_PIN, I2C_SCL_PIN, 100000); + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + scd41.begin(Wire, SCD41_I2C_ADDR_62); + + // while( !SCD4X.begin() ){ + // Serial.println("Communication with device failed, please check connection"); + // delay(3000); + // } + scd41.stopPeriodicMeasurement(); + Serial.println("SCD4x: Begin ok!"); + scd41.startPeriodicMeasurement(); + + // SCD4X.setTempComp(4.0); + // float temp = 0; + // temp = SCD4X.getTempComp(); + // Serial.print("The current temperature compensation value : "); + // Serial.print(temp); + // Serial.println(" C"); + + // SCD4X.setSensorAltitude(540); + // uint16_t altitude = 0; + // altitude = SCD4X.getSensorAltitude(); + // Serial.print("Set the current environment altitude : "); + // Serial.print(altitude); + // Serial.println(" m"); + + // SCD4X.enablePeriodMeasure(SCD4X_START_PERIODIC_MEASURE); + + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "Node17_bme680_scd41_t6713_c4001_router"); + zbCarbonDioxideSensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_SCD4X.setMinMaxValue(10, 50); + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_SCD4X.setTolerance(1); + // Optional: Time cluster configuration (default params, as this device will revieve time from coordinator) + // zbTempSensor.addTimeCluster(); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_SCD4X.addHumiditySensor(0, 100, 1); + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_SCD4X); + + + + + + + Serial.println("Connecting to BME680..."); + + // // Init BME680 + // if (bme680.begin(sharedI2C) != 0) { + // Serial.println("BME680 init failed!"); + // } else { + // Serial.println("BME680 ready!"); + // } + // Wire.begin(SCD41_SDA_PIN, SCD41_SCL_PIN); + // Wire.setClock(100000); // Set I2C clock speed to 100kHz + // // Initialize the BME680 + // bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme.begin(BME68X_I2C_ADDR_HIGH, &BME68X_I2C); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme680.begin() + // // Set up the BME680 + // // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // // bme.setOversampling(T2, OS_2X); + // // bme.setOversampling(T1, OS_16X); + // // bme.setOversampling(H1, OS_2X); + // // bme.setFilter(FILTER_SIZE_3); + // // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + // if(bme.checkStatus()) + // { + // if (bme.checkStatus() == BME68X_ERROR) + // { + // Serial.println("Sensor error:" + bme.statusString()); + // return; + // } + // else if (bme.checkStatus() == BME68X_WARNING) + // { + // Serial.println("Sensor Warning:" + bme.statusString()); + // } + // } + // /* Set the default configuration for temperature, pressure and humidity */ + // bme.setTPH(); + // /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + // bme.setHeaterProf(300, 100); + + // bme68xData data; + // bme.setOpMode(BME68X_FORCED_MODE); + + + // Note the syntax: .begin(Address, TwoWirePointer) + // if (!bme680.begin(0x77, &sharedI2C)) { + // Serial.println("BME680 not found at 0x77, trying 0x76..."); + // if (!bme680.begin(0x76, &sharedI2C)) { + // Serial.println("BME680 Init Failed! Check wiring."); + // while (1); + // } + // } + // Serial.println("BME680 initialized via TwoWire."); + // // BME680 Settings + // bme680.setTemperatureOversampling(BME680_OS_8X); + // bme680.setHumidityOversampling(BME680_OS_2X); + // bme680.setPressureOversampling(BME680_OS_4X); + // bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); + // bme680.setGasHeater(320, 150); + + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + /* Set the default configuration for temperature, pressure and humidity */ + // setTPH(uint8_t os_temp, uint8_t os_pres, uint8_t os_hum); BME68X_OS_NONE, BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X, BME68X_OS_16X + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensor_BME68X.setMinMaxValue(-20, 80); + zbTempSensor_BME68X.setTolerance(1); + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + // Set analog resolution to 10 bits + // analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + + + // TRUE = Normal Home/Office use + // FALSE = Greenhouse / Constantly occupied + configureT6713(true); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor_T6713.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor_T6713); + + + + + + + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + // Increase keep-alive to 5 seconds (default is often 3000ms) + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 5000; + // zigbeeConfig.nwk_cfg.zed_cfg.ed_timeout = ESP_ZB_ED_AGING_TIMEOUT_256MIN; // 4 hours; How long the parent remembers this device. + + // 1. Our custom config (zigbeeConfig) + // 2. false = Do NOT erase NVS (keep network credentials) + // 3. true = Start automatically (optional, defaults to true) + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + 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); + // } + // Record the start time + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; // 120 seconds + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + + // Check if 120 seconds have passed + if (millis() - startTime > timeoutMs) { + Serial.println("\nConnection timed out (120s). Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, LOW); + Serial.println("\nZigbee connected!"); + Serial.println(); + + + + xTaskCreate(bme680_sensor_value_update, "bme680_sensor_value_update", 2048, NULL, 10, NULL); + xTaskCreate(scd4x_sensor_value_update, "scd4x_sensor_value_update", 2048, NULL, 10, NULL); + xTaskCreate(t6713_sensor_value_update, "t6713_sensor_value_update", 2048, NULL, 10, NULL); + + // 4. Create the task + xTaskCreate( + pirTask, // Function to call + "PIR_Check", // Name for debugging + 4096, // Stack size (bytes) - Zigbee operations need space! + NULL, // Parameter to pass + 1, // Priority (1 is standard, higher numbers = higher priority) + NULL // Task handle + ); + + + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbTempSensor_SCD4X.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(1, 0, 1); + zbAnalogDevice_BME68X.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 + zbCarbonDioxideSensor_T6713.setReporting(0, 30, 0); + +} + + + +void loop() { + // handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + + // if (currentMode == eExitMode) { + // // PRESENCE MODE + // // static bool occupancy = false; + // // bool occupancyNow = radar.motionDetection(); + // // Serial.println(occupancyNow); + // // // if (radar.motionDetection() == 1 && !occupancy) { + // // if (occupancyNow != lastOccupancy) { + // // Serial.println("MOTION DETECTED"); + // // zbOccupancySensor.setOccupancy(occupancyNow); + // // zbOccupancySensor.report(); + // // // occupancy = true; + // // lastOccupancy = occupancyNow; + // // // } else if (radar.motionDetection() == 0 && occupancy) { + // // // } else if (radar.motionDetection() == 0) { + // // // Serial.println("MOTION ENDED"); + // // // zbOccupancySensor.setOccupancy(false); + // // // zbOccupancySensor.report(); + // // // occupancy = false; + // // } + // // PRESENCE MODE - proper state machine + // bool motionNow = radar.motionDetection(); + // // Serial.println(motionNow); + // // Serial.println(lastOccupancy); + // // Serial.println(millis() - occupancyStartTime); + + // if (motionNow && !lastOccupancy) { + // // Motion STARTED → Set occupancy ON + // Serial.println("MOTION DETECTED → OCCUPANCY ON"); + // lastOccupancy = true; + // occupancyStartTime = millis(); + // zbOccupancySensor.setOccupancy(true); + // zbOccupancySensor.report(); + + // } else if (motionNow && lastOccupancy) { + // // Motion ENDED → Start timeout timer + // // Serial.println("Motion still present → timeout reset"); + // occupancyStartTime = millis(); + + // } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // // TIMEOUT → Clear occupancy + // Serial.println("OCCUPANCY TIMEOUT → OFF"); + // lastOccupancy = false; + // zbOccupancySensor.setOccupancy(false); + // zbOccupancySensor.report(); + + // } else if (!motionNow && lastOccupancy) { + // // Motion ENDED → Start timeout timer + // // Serial.println("Motion ended → timeout started"); + // // occupancyStartTime = millis(); + // } + + // } else if (currentMode == eSpeedMode) { + // // SPEED MODE + // Serial.print("Targets: "); + // Serial.print(radar.getTargetNumber()); + // Serial.print(" | Speed: "); + // Serial.print(radar.getTargetSpeed(), 2); + // Serial.print(" m/s | Range: "); + // Serial.print(radar.getTargetRange(), 2); + // Serial.print(" m | Energy: "); + // Serial.println(radar.getTargetEnergy()); + // } + + + + // // --- Read SCD41 --- + // uint16_t co2_scd = 0; + // float temperature_scd = 0.0f; + // float humidity_scd = 0.0f; + // bool scdReady = false; + + // uint16_t error = scd41.readMeasurement(co2_scd, temperature_scd, humidity_scd); + // if (error == 0 && co2_scd != 0) { + // scdReady = true; + // } + + // if (scdReady) { + // Serial.print("[SCD41] CO2: "); Serial.print(co2_scd); Serial.print(" ppm"); + // Serial.print(" | Temp: "); Serial.print(temperature_scd); Serial.print(" C"); + // Serial.print(" | Hum: "); Serial.print(humidity_scd); Serial.println(" %"); + + // zbCarbonDioxideSensor.setCarbonDioxide(co2_scd); + // zbCarbonDioxideSensor.report(); + + // // Update temperature and humidity values in Temperature sensor EP + // zbTempSensor_SCD4X.setTemperature(temperature_scd); + // zbTempSensor_SCD4X.setHumidity(humidity_scd); + // // Report temperature and humidity values + // zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // // Serial.print("SCD41 reported."); + + // } + // else { + // Serial.println("[SCD41] Waiting for measurement..."); + // } + + + // if(SCD4X.getDataReadyStatus()) { + // DFRobot_SCD4X::sSensorMeasurement_t data; + // SCD4X.readMeasurement(&data); + + // Serial.print("Carbon dioxide concentration : "); + // Serial.print(data.CO2ppm); + // Serial.println(" ppm"); + + // Serial.print("Environment temperature : "); + // Serial.print(data.temp); + // Serial.println(" C"); + + // Serial.print("Relative humidity : "); + // Serial.print(data.humidity); + // Serial.println(" RH"); + + // Serial.println(); + + // zbCarbonDioxideSensor.setCarbonDioxide(data.CO2ppm); + // zbCarbonDioxideSensor.report(); + + // // Update temperature and humidity values in Temperature sensor EP + // zbTempSensor_SCD4X.setTemperature(data.temp); + // zbTempSensor_SCD4X.setHumidity(data.humidity); + // // Report temperature and humidity values + // zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + + // } + + + // Serial.println("---------------------------"); + + // float bme_temperature(NAN), bme_humidity(NAN), bme_pressure(NAN), bme_gasResistance(NAN); + // bme68xData data; + // bme.setOpMode(BME68X_FORCED_MODE); + // delayMicroseconds(bme.getMeasDur()); + // // delay(bme.getMeasDur(BME68X_FORCED_MODE) / 1000 + 50); + // if (bme.fetchData() && (millis() - bme_report_time > 5000)) { + // bme.getData(data); + // bme_temperature = data.temperature; // Temperature in °C + // bme_humidity = data.humidity; // Humidity in % + // bme_pressure = data.pressure; // Pressure in hPa + // bme_gasResistance = data.gas_resistance; // Gas resistance in ohms + // // errorCount = 0; // Reset error count on successful read + // Serial.printf("[BME680] temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", bme_temperature, bme_humidity, bme_gasResistance); + + // zbTempSensor_BME68X.setTemperature(bme_temperature); + // zbTempSensor_BME68X.setHumidity(bme_humidity); + // // Report temperature and humidity values + // zbTempSensor_BME68X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + + // zbAnalogDevice_BME68X.setAnalogInput(bme_gasResistance); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + // digitalWrite(LED_PIN, HIGH); + // delay(50); + // digitalWrite(LED_PIN, LOW); + + // // Serial.print("BME68X reported."); + // bme_report_time = millis(); + // } + // else { + // Serial.println("BME680 -> Waiting..."); + // } + + + + + + // // --- Read T6713 (CO2) --- + // int co2_t6713 = readT6713(); + // if ((co2_t6713 >= 0) && (millis() - t6713_report_time > 5000)) { + // Serial.print("T6713 | CO2: "); Serial.print(co2_t6713); Serial.println(" ppm"); + // zbCarbonDioxideSensor_T6713.setCarbonDioxide(co2_t6713); + // zbCarbonDioxideSensor_T6713.report(); + // t6713_report_time = millis(); + // } + // // else { + // // Serial.println("T6713 | Read Error"); + // // } + + + // 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(); + } + } + // force report of illuminance when button is pressed + // zbIlluminanceSensor.report(); + // zbTempSensor_BME68X.report(); + // zbCarbonDioxideSensor.report(); + // zbAnalogDevice_BME68X.reportAnalogInput(); + // zbEnvSensor_sgp40_sht40.report(); + + } + + delay(100); +} + + + + + diff --git a/Node17_bme680_scd41_t6713_c4001_router_v3/Node17_bme680_scd41_t6713_c4001_router_v3.ino b/Node17_bme680_scd41_t6713_c4001_router_v3/Node17_bme680_scd41_t6713_c4001_router_v3.ino new file mode 100644 index 0000000..606392c --- /dev/null +++ b/Node17_bme680_scd41_t6713_c4001_router_v3/Node17_bme680_scd41_t6713_c4001_router_v3.ino @@ -0,0 +1,803 @@ +// DFRobot Beetle ESP32-C6 +// Partition Scheme: Zigbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZRZC (coordinator,router) + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator/router mode is not selected in Tools->Zigbee mode" +#endif + +// Comment out DEBUG_TRACE to reduce normal-path logging +#define DEBUG_TRACE + +#include "Zigbee.h" +#include "DFRobot_C4001.h" +#include +#include +#include + +// ----------------------------------------------------------------------------- +// Hardware definitions +// ----------------------------------------------------------------------------- +#define LED_PIN 15 +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 + +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +// Radar UART pins (DFRobot C4001) +#define RADAR_RX_PIN 17 +#define RADAR_TX_PIN 16 + +// I2C pins +#define I2C_SCL_PIN 20 +#define I2C_SDA_PIN 6 + +// T6713 I2C address and registers +#define T6713_ADDR 0x15 +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +// Endpoint numbers +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_SCD41 11 +#define TEMP_SENSOR_ENDPOINT_NUMBER_SCD41 12 +#define TEMP_SENSOR_ENDPOINT_NUMBER_BME68X 13 +#define ANALOG_DEVICE_ENDPOINT_NUMBER_BME68X 14 +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713 15 + +// Radar / occupancy +ZigbeeOccupancySensor zbOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, RADAR_RX_PIN, RADAR_TX_PIN); + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed + +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; + +// Radar presence configuration +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds (sensor-side keep time) +const unsigned long TRIGGER_DELAY = 10; // 10 -> 100 ms + +// ----------------------------------------------------------------------------- +// Health / watchdog globals +// ----------------------------------------------------------------------------- + +// I2C mutex to guard shared bus across tasks +SemaphoreHandle_t i2cMutex; + +// “first data received” guards +bool scd41FirstOk = false; +bool bmeFirstOk = false; +bool t6713FirstOk = false; + +// SCD41 last-change tracking +uint16_t lastCo2Scd = 0; +float lastTempScd = NAN; +float lastHumScd = NAN; +unsigned long lastCo2ScdChangeMs = 0; +unsigned long lastTempScdChangeMs = 0; +unsigned long lastHumScdChangeMs = 0; + +// T6713 last-change tracking +int lastCo2T6713 = -1; +unsigned long lastCo2T6713ChangeMs = 0; + +// BME68x last-change tracking +float lastTempBme = NAN; +float lastHumBme = NAN; +float lastGasRes = NAN; +unsigned long lastTempBmeChangeMs = 0; +unsigned long lastHumBmeChangeMs = 0; +unsigned long lastGasResChangeMs = 0; + +// Zigbee health +unsigned long lastZigbeeOkMs = 0; + +// Watchdog thresholds +const unsigned long WATCHDOG_PERIOD_MS = 10000; // 10 s +const unsigned long SENSOR_STUCK_TIMEOUT_MS = 30UL * 60UL * 1000UL; // 30 min +const unsigned long ZIGBEE_DOWN_TIMEOUT_MS = 10UL * 60UL * 1000UL; // 10 min + +// I2C error counters +int scd41ErrorCount = 0; +int bmeErrorCount = 0; +int t6713ErrorCount = 0; +const int maxI2cErrors = 10; + +// ----------------------------------------------------------------------------- +// Zigbee sensor endpoints +// ----------------------------------------------------------------------------- +SensirionI2cScd4x scd41; +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor( + CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_SCD41); +ZigbeeTempSensor zbTempSensor_SCD4X( + TEMP_SENSOR_ENDPOINT_NUMBER_SCD41); + +Bme68x bme; +ZigbeeTempSensor zbTempSensor_BME68X( + TEMP_SENSOR_ENDPOINT_NUMBER_BME68X); +ZigbeeAnalog zbAnalogDevice_BME68X( + ANALOG_DEVICE_ENDPOINT_NUMBER_BME68X); + +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_T6713( + CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713); + +// ----------------------------------------------------------------------------- +// Helper: Zigbee health “touch” after successful reports +// ----------------------------------------------------------------------------- +inline void zigbeeHealthTouch() { + if (Zigbee.connected()) { + lastZigbeeOkMs = millis(); + } +} + +// ----------------------------------------------------------------------------- +// Helper: I2C guarded execution (use mutex) +// If your toolchain dislikes std::function, inline xSemaphoreTake/Give in tasks. +// ----------------------------------------------------------------------------- +#include + +bool withI2C(std::function fn, uint32_t timeoutMs = 100) { + if (xSemaphoreTake(i2cMutex, pdMS_TO_TICKS(timeoutMs)) == pdTRUE) { + bool ok = fn(); + xSemaphoreGive(i2cMutex); + return ok; + } + return false; +} + +// ----------------------------------------------------------------------------- +// Radar configuration +// ----------------------------------------------------------------------------- +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; +#ifdef DEBUG_TRACE + Serial.println("Switched to PRESENCE mode"); +#endif + + sSensorStatus_t data; + data = radar.getStatus(); +#ifdef DEBUG_TRACE + Serial.print("work status = "); + Serial.println(data.workStatus); + Serial.print("work mode = "); + Serial.println(data.workMode); + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); +#endif + + if (radar.setDetectionRange(/*min*/ 30, /*max*/ 500, /*trig*/ 500)) { +#ifdef DEBUG_TRACE + Serial.println("Radar: set detection range successfully"); +#endif + if (radar.setTrigSensitivity(8)) { +#ifdef DEBUG_TRACE + Serial.println("Radar: set trig sensitivity successfully"); +#endif + if (radar.setKeepSensitivity(8)) { +#ifdef DEBUG_TRACE + Serial.println("Radar: set keep sensitivity successfully"); +#endif + if (radar.setDelay(/*trig*/ TRIGGER_DELAY, /*keep*/ OCCUPANCY_TIMEOUT)) { +#ifdef DEBUG_TRACE + Serial.println("Radar: set delay successfully"); + + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); +#endif + } + } + } + } +} + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; +#ifdef DEBUG_TRACE + Serial.println("Switched to SPEED mode"); +#endif + + sSensorStatus_t data; + data = radar.getStatus(); +#ifdef DEBUG_TRACE + Serial.print("work status = "); + Serial.println(data.workStatus); + Serial.print("work mode = "); + Serial.println(data.workMode); + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); +#endif + + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { +#ifdef DEBUG_TRACE + Serial.println("Radar: set detect threshold successfully"); +#endif + radar.setFrettingDetection(eON); +#ifdef DEBUG_TRACE + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); +#endif + } +} + +// Optional: serial commands to switch radar mode +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } +} + +// ----------------------------------------------------------------------------- +// Radar / occupancy task (FreeRTOS) +// ----------------------------------------------------------------------------- +void pirTask(void *parameter) { + for (;;) { + if (currentMode == eExitMode) { + bool motionNow = radar.motionDetection(); + + if (motionNow && !lastOccupancy) { +#ifdef DEBUG_TRACE + Serial.println("MOTION DETECTED → OCCUPANCY ON"); +#endif + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + zigbeeHealthTouch(); + } else if (motionNow && lastOccupancy) { + // Motion still present → reset timeout + occupancyStartTime = millis(); + } else if (!motionNow && lastOccupancy && + (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT * 1000UL / 2UL)) { +#ifdef DEBUG_TRACE + Serial.println("OCCUPANCY TIMEOUT → OFF"); +#endif + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + zigbeeHealthTouch(); + } else { + // no motion and already off, or still within timeout + } + } else if (currentMode == eSpeedMode) { +#ifdef DEBUG_TRACE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); +#endif + } + + vTaskDelay(pdMS_TO_TICKS(50)); + } +} + +// ----------------------------------------------------------------------------- +// SCD41 task +// ----------------------------------------------------------------------------- +static void scd4x_sensor_value_update(void *arg) { + for (;;) { + uint16_t co2_scd = 0; + float temperature_scd = 0.0f; + float humidity_scd = 0.0f; + uint16_t error = 1; + + bool i2cOk = withI2C([&]() -> bool { + error = scd41.readMeasurement(co2_scd, temperature_scd, humidity_scd); + return (error == 0); + }); + + if (i2cOk && error == 0 && co2_scd != 0) { + scd41ErrorCount = 0; + + unsigned long now = millis(); + if (!scd41FirstOk) { + scd41FirstOk = true; + lastCo2Scd = co2_scd; + lastTempScd = temperature_scd; + lastHumScd = humidity_scd; + lastCo2ScdChangeMs = now; + lastTempScdChangeMs = now; + lastHumScdChangeMs = now; + } else { + if (co2_scd != lastCo2Scd) { + lastCo2Scd = co2_scd; + lastCo2ScdChangeMs = now; + } + if (temperature_scd != lastTempScd) { + lastTempScd = temperature_scd; + lastTempScdChangeMs = now; + } + if (humidity_scd != lastHumScd) { + lastHumScd = humidity_scd; + lastHumScdChangeMs = now; + } + } + + zbCarbonDioxideSensor.setCarbonDioxide(co2_scd); + // zbCarbonDioxideSensor.report(); + zigbeeHealthTouch(); + + zbTempSensor_SCD4X.setTemperature(temperature_scd); + zbTempSensor_SCD4X.setHumidity(humidity_scd); + // zbTempSensor_SCD4X.report(); + zigbeeHealthTouch(); + +#ifdef DEBUG_TRACE + Serial.print("[SCD41] CO2: "); Serial.print(co2_scd); Serial.print(" ppm"); + Serial.print(" | Temp: "); Serial.print(temperature_scd); Serial.print(" C"); + Serial.print(" | Hum: "); Serial.print(humidity_scd); Serial.println(" %"); +#endif + } else { + scd41ErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("SCD41 read error or I2C busy."); +#endif + if (scd41ErrorCount >= maxI2cErrors) { + Serial.println("SCD41: too many errors, restarting..."); + delay(200); + ESP.restart(); + } + } + + vTaskDelay(pdMS_TO_TICKS(10000)); // ~10 s + } +} + +// ----------------------------------------------------------------------------- +// BME68x task +// ----------------------------------------------------------------------------- +static void bme680_sensor_value_update(void *arg) { + for (;;) { + float temperature = NAN, humidity = NAN, pressure = NAN, gasResistance = NAN; + bme68xData data; + + bool ok = withI2C([&]() -> bool { + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; + humidity = data.humidity; + pressure = data.pressure; + gasResistance = data.gas_resistance; + return true; + } + return false; + }); + + if (ok) { + bmeErrorCount = 0; + + unsigned long now = millis(); + if (!bmeFirstOk) { + bmeFirstOk = true; + lastTempBme = temperature; + lastHumBme = humidity; + lastGasRes = gasResistance; + lastTempBmeChangeMs = now; + lastHumBmeChangeMs = now; + lastGasResChangeMs = now; + } else { + if (temperature != lastTempBme) { + lastTempBme = temperature; + lastTempBmeChangeMs = now; + } + if (humidity != lastHumBme) { + lastHumBme = humidity; + lastHumBmeChangeMs = now; + } + if (gasResistance != lastGasRes) { + lastGasRes = gasResistance; + lastGasResChangeMs = now; + } + } + + zbTempSensor_BME68X.setTemperature(temperature); + zbTempSensor_BME68X.setHumidity(humidity); + // zbTempSensor_BME68X.report(); + zigbeeHealthTouch(); + + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + zigbeeHealthTouch(); + +#ifdef DEBUG_TRACE + Serial.printf("BME68x: T=%.2fC H=%.2f%% Gas=%.2f ohm\r\n", + temperature, humidity, gasResistance); +#endif + } else { + bmeErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("BME68x read error or I2C busy."); +#endif + if (bmeErrorCount >= maxI2cErrors) { + Serial.println("BME68x: too many errors, restarting..."); + delay(200); + ESP.restart(); + } + } + + vTaskDelay(pdMS_TO_TICKS(10000)); // ~10 s + } +} + +// ----------------------------------------------------------------------------- +// T6713 helper and task +// ----------------------------------------------------------------------------- +int readT6713() { + int result = -1; + bool ok = withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); + Wire.write(0x8B); + Wire.write(0x00); + Wire.write(0x01); + if (Wire.endTransmission() != 0) return false; + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // skip func & len + byte high = Wire.read(); + byte low = Wire.read(); + result = (high << 8) | low; + return true; + } + return false; + }); + + if (!ok) { + result = -1; + } + return result; +} + +void configureT6713(bool enableABC) { + delay(1000); + + // Optional status check + withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); + Wire.write(0x13); Wire.write(0x8A); // 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); + uint16_t status = (Wire.read() << 8) | Wire.read(); +#ifdef DEBUG_TRACE + if (status & 0x08) { + Serial.println("T6713: Warming up..."); + } +#endif + } + return true; + }); + + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + + withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + byte error = Wire.endTransmission(); + if (error == 0) { +#ifdef DEBUG_TRACE + Serial.print("T6713: ABC Logic set to "); + Serial.println(enableABC ? "ON" : "OFF"); +#endif + } else { +#ifdef DEBUG_TRACE + Serial.println("T6713: Failed to set ABC Logic"); +#endif + } + return true; + }); + + delay(100); +} + +static void t6713_sensor_value_update(void *arg) { + for (;;) { + int co2_t6713 = readT6713(); + if (co2_t6713 >= 0) { + t6713ErrorCount = 0; + + unsigned long now = millis(); + if (!t6713FirstOk) { + t6713FirstOk = true; + lastCo2T6713 = co2_t6713; + lastCo2T6713ChangeMs = now; + } else if (co2_t6713 != lastCo2T6713) { + lastCo2T6713 = co2_t6713; + lastCo2T6713ChangeMs = now; + } + +#ifdef DEBUG_TRACE + Serial.print("T6713 | CO2: "); Serial.print(co2_t6713); Serial.println(" ppm"); +#endif + zbCarbonDioxideSensor_T6713.setCarbonDioxide(co2_t6713); + // zbCarbonDioxideSensor_T6713.report(); + zigbeeHealthTouch(); + } else { + t6713ErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("T6713 read error."); +#endif + if (t6713ErrorCount >= maxI2cErrors) { + Serial.println("T6713: too many errors, restarting..."); + delay(200); + ESP.restart(); + } + } + + vTaskDelay(pdMS_TO_TICKS(10000)); // ~10 s + } +} + +// ----------------------------------------------------------------------------- +// Watchdog task: checks Zigbee and “no-change” conditions +// ----------------------------------------------------------------------------- +void watchdogTask(void *param) { + for (;;) { + +// #ifdef DEBUG_TRACE +// Serial.println("Watchdog ran."); +// Serial.printf("scd41FirstOk=%i, lastCo2ScdChangeMs=%i\r\n", +// scd41FirstOk, lastCo2ScdChangeMs); +// #endif + + unsigned long now = millis(); + + bool zigbeeBad = (!Zigbee.connected() && + (now - lastZigbeeOkMs > ZIGBEE_DOWN_TIMEOUT_MS)); + + bool co2ScdStuck = scd41FirstOk && + (now - lastCo2ScdChangeMs > SENSOR_STUCK_TIMEOUT_MS); + bool tempScdStuck = scd41FirstOk && + (now - lastTempScdChangeMs > SENSOR_STUCK_TIMEOUT_MS); + bool humScdStuck = scd41FirstOk && + (now - lastHumScdChangeMs > SENSOR_STUCK_TIMEOUT_MS); + bool co2T6713Stuck = t6713FirstOk && + (now - lastCo2T6713ChangeMs > SENSOR_STUCK_TIMEOUT_MS); + bool tempBmeStuck = bmeFirstOk && + (now - lastTempBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS); + bool humBmeStuck = bmeFirstOk && + (now - lastHumBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS); + bool gasResStuck = bmeFirstOk && + (now - lastGasResChangeMs > SENSOR_STUCK_TIMEOUT_MS); + + if (zigbeeBad || co2ScdStuck || tempScdStuck || humScdStuck || + co2T6713Stuck || tempBmeStuck || humBmeStuck || gasResStuck) { + + Serial.println("Watchdog: fault detected, restarting..."); + delay(500); + ESP.restart(); + } + + vTaskDelay(pdMS_TO_TICKS(WATCHDOG_PERIOD_MS)); + } +} + +// ----------------------------------------------------------------------------- +// setup() +// ----------------------------------------------------------------------------- +void setup() { + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + + delay(100); + + // Global (affects all endpoints) + // Zigbee.setManufacturer("Espressif"); + // Zigbee.setModel("Node17_MultiSensor_v3"); + + + // Radar UART + RadarSerial.begin(9600, SERIAL_8N1, RADAR_RX_PIN, RADAR_TX_PIN); + while (!radar.begin()) { + Serial.println("NO Radar device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + // Occupancy Zigbee endpoint + zbOccupancySensor.setManufacturerAndModel("Espressif", "Node17"); // Node17_c4001 + // zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + zbCarbonDioxideSensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + Zigbee.addEndpoint(&zbOccupancySensor); + + // I2C init + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + i2cMutex = xSemaphoreCreateMutex(); + + // SCD41 init + scd41.begin(Wire, SCD41_I2C_ADDR_62); + scd41.stopPeriodicMeasurement(); + Serial.println("SCD4x: Begin ok!"); + scd41.startPeriodicMeasurement(); + + // SCD41 Zigbee endpoints + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "Node17"); // Node17_scd41_co2 + zbCarbonDioxideSensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbCarbonDioxideSensor.setMinMaxValue(0, 10000); + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + zbTempSensor_SCD4X.setManufacturerAndModel("Espressif", "Node17"); // Node17_scd41_th + zbTempSensor_SCD4X.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensor_SCD4X.setMinMaxValue(-20, 80); + zbTempSensor_SCD4X.setTolerance(1); + zbTempSensor_SCD4X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_SCD4X); + + // BME68x init + Serial.println("Connecting to BME680..."); + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + bme.setHeaterProf(300, 100); + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensor_BME68X.setManufacturerAndModel("Espressif", "Node17"); // Node17_bme680_th + zbTempSensor_BME68X.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensor_BME68X.setMinMaxValue(-20, 80); + zbTempSensor_BME68X.setTolerance(1); + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + zbAnalogDevice_BME68X.setManufacturerAndModel("Espressif", "Node17"); // Node17_bme680_r + zbAnalogDevice_BME68X.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogDevice_BME68X.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + // T6713 config + configureT6713(true); + zbCarbonDioxideSensor_T6713.setManufacturerAndModel("Espressif", "Node17"); // Node17_t6713 + zbCarbonDioxideSensor_T6713.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbCarbonDioxideSensor_T6713.setMinMaxValue(0, 10000); + Zigbee.addEndpoint(&zbCarbonDioxideSensor_T6713); + + // Start Zigbee as router + Serial.println("Starting Zigbee..."); + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + + Serial.println("Connecting to network"); + bool ledState = false; + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; + + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + + if (millis() - startTime > timeoutMs) { + Serial.println("\nConnection timed out (60s). Restarting..."); + ESP.restart(); + } + } + + digitalWrite(LED_PIN, LOW); + Serial.println("\nZigbee connected!"); + Serial.println(); + + lastZigbeeOkMs = millis(); + + // Create sensor tasks + xTaskCreate(bme680_sensor_value_update, "bme680_sensor_value_update", 4096, NULL, 10, NULL); + xTaskCreate(scd4x_sensor_value_update, "scd4x_sensor_value_update", 4096, NULL, 10, NULL); + xTaskCreate(t6713_sensor_value_update, "t6713_sensor_value_update", 4096, NULL, 10, NULL); + xTaskCreate(pirTask, "PIR_Check", 4096, NULL, 1, NULL); + xTaskCreate(watchdogTask, "watchdog", 4096, NULL, 5, NULL); + + // Reporting configuration + zbCarbonDioxideSensor.setReporting(30, 300, 10); + zbTempSensor_SCD4X.setReporting(60, 0, 0.5); + zbTempSensor_BME68X.setReporting(60, 0, 0.5); + zbAnalogDevice_BME68X.setAnalogInputReporting(60, 600, 10); + zbCarbonDioxideSensor_T6713.setReporting(30, 300, 10); +} + +// ----------------------------------------------------------------------------- +// loop() +// ----------------------------------------------------------------------------- +void loop() { + // Optional: for manual mode switches + // handleSerialCommands(); + + // Test commands via Serial + // if (Serial.available()) { + // char cmd = Serial.read(); + // switch(cmd) { + // case 'Z': // Force Zigbee failure + // Serial.println("SIM: Zigbee disconnect test"); + // lastZigbeeOkMs = 0; // Watchdog sees Zigbee down + // break; + + // case 'E': // Force "stuck sensor" detection + // Serial.println("SIM: Stuck sensor test"); + // // Set ALL change timestamps to ancient past → triggers stuck detection + // lastCo2ScdChangeMs = lastTempScdChangeMs = lastHumScdChangeMs = 0; + // lastCo2T6713ChangeMs = lastTempBmeChangeMs = lastHumBmeChangeMs = 0; + // lastGasResChangeMs = 0; + // break; + + // case 'S': // Force SINGLE sensor restart (per-task check) + // Serial.println("SIM: SCD41 error threshold → restart"); + // scd41ErrorCount = maxI2cErrors; // Task will check & restart itself + // break; + + // case 'R': // Manual restart + // Serial.println("SIM: Manual restart"); + // ESP.restart(); + // break; + // } + // } + + // Factory reset logic on long button press + if (digitalRead(button) == LOW) { // push button pressed + delay(100); // debounce + + 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(); + // Zigbee.factoryReset() usually does not return + ESP.restart(); + } + } + } + + // Keep loop light; everything else runs in tasks + vTaskDelay(pdMS_TO_TICKS(50)); +} diff --git a/Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino b/Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino new file mode 100644 index 0000000..b1d432f --- /dev/null +++ b/Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino @@ -0,0 +1,786 @@ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +#define LED_PIN 15 + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds - adjust as needed +const unsigned long TRIGGER_DELAY = 10; // 10 -> 100 ms + + + + + + +// Define your custom SCL/SDA pins +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin +// Create custom I2C instance +// TwoWire sharedI2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) + + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +// #include +// // DFRobot_SCD4X SCD4X(&Wire, /*i2cAddr = */SCD4X_I2C_ADDR); +// // SCD41 with custom I2C +// DFRobot_SCD4X SCD4X(&sharedI2C, SCD4X_I2C_ADDR); + +#include +#include +#include + +SensirionI2cScd4x scd41; + + + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 12 +ZigbeeTempSensor zbTempSensor_SCD4X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + + + + + + + +// --- BME680 Settings --- + +#include +Bme68x bme; +// TwoWire BME68X_I2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) +// #include // BME680 library +// DFRobot_BME680_I2C bme680(0x76); // 0x76 +// #include +// #include "Adafruit_BME680.h" +// Adafruit_BME680 bme680; +unsigned long bme_report_time = millis(); + +#define TEMP_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 14 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + + + + +// --- T6713 Settings --- +#define T6713_ADDR 0x15 +// T6713 Register Addresses (Modbus) +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +unsigned long t6713_report_time = millis(); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713 15 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_T6713 = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713); + + + + + + + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/500, /*trig*/500)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(8)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(8)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/TRIGGER_DELAY, /*keep*/OCCUPANCY_TIMEOUT)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + + + + + + + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + + + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + +void setup() { + Serial.begin(115200); + + pinMode(LED_PIN, OUTPUT); + bool ledState = false; + digitalWrite(LED_PIN, HIGH); + + + // while (!Serial); + // unsigned long start = millis(); + // while (!Serial && millis() - start < 3000); + delay(100); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + + + + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + // Initialize custom I2C with YOUR pins + // SCD41_I2C.begin(SCD41_SDA_PIN, SCD41_SCL_PIN, 100000); // 100kHz standard + // Initialize SHARED I2C bus ONCE + // sharedI2C.begin(I2C_SDA_PIN, I2C_SCL_PIN, 100000); + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + scd41.begin(Wire, SCD41_I2C_ADDR_62); + + // while( !SCD4X.begin() ){ + // Serial.println("Communication with device failed, please check connection"); + // delay(3000); + // } + scd41.stopPeriodicMeasurement(); + Serial.println("SCD4x: Begin ok!"); + scd41.startPeriodicMeasurement(); + + // SCD4X.setTempComp(4.0); + // float temp = 0; + // temp = SCD4X.getTempComp(); + // Serial.print("The current temperature compensation value : "); + // Serial.print(temp); + // Serial.println(" C"); + + // SCD4X.setSensorAltitude(540); + // uint16_t altitude = 0; + // altitude = SCD4X.getSensorAltitude(); + // Serial.print("Set the current environment altitude : "); + // Serial.print(altitude); + // Serial.println(" m"); + + // SCD4X.enablePeriodMeasure(SCD4X_START_PERIODIC_MEASURE); + + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_SCD4X.setMinMaxValue(10, 50); + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_SCD4X.setTolerance(1); + // Optional: Time cluster configuration (default params, as this device will revieve time from coordinator) + // zbTempSensor.addTimeCluster(); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_SCD4X.addHumiditySensor(0, 100, 1); + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_SCD4X); + + + + + + + Serial.println("Connecting to BME680..."); + + // // Init BME680 + // if (bme680.begin(sharedI2C) != 0) { + // Serial.println("BME680 init failed!"); + // } else { + // Serial.println("BME680 ready!"); + // } + // Wire.begin(SCD41_SDA_PIN, SCD41_SCL_PIN); + // Wire.setClock(100000); // Set I2C clock speed to 100kHz + // // Initialize the BME680 + // bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme.begin(BME68X_I2C_ADDR_HIGH, &BME68X_I2C); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme680.begin() + // // Set up the BME680 + // // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // // bme.setOversampling(T2, OS_2X); + // // bme.setOversampling(T1, OS_16X); + // // bme.setOversampling(H1, OS_2X); + // // bme.setFilter(FILTER_SIZE_3); + // // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + // if(bme.checkStatus()) + // { + // if (bme.checkStatus() == BME68X_ERROR) + // { + // Serial.println("Sensor error:" + bme.statusString()); + // return; + // } + // else if (bme.checkStatus() == BME68X_WARNING) + // { + // Serial.println("Sensor Warning:" + bme.statusString()); + // } + // } + // /* Set the default configuration for temperature, pressure and humidity */ + // bme.setTPH(); + // /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + // bme.setHeaterProf(300, 100); + + // bme68xData data; + // bme.setOpMode(BME68X_FORCED_MODE); + + + // Note the syntax: .begin(Address, TwoWirePointer) + // if (!bme680.begin(0x77, &sharedI2C)) { + // Serial.println("BME680 not found at 0x77, trying 0x76..."); + // if (!bme680.begin(0x76, &sharedI2C)) { + // Serial.println("BME680 Init Failed! Check wiring."); + // while (1); + // } + // } + // Serial.println("BME680 initialized via TwoWire."); + // // BME680 Settings + // bme680.setTemperatureOversampling(BME680_OS_8X); + // bme680.setHumidityOversampling(BME680_OS_2X); + // bme680.setPressureOversampling(BME680_OS_4X); + // bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); + // bme680.setGasHeater(320, 150); + + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + /* Set the default configuration for temperature, pressure and humidity */ + // setTPH(uint8_t os_temp, uint8_t os_pres, uint8_t os_hum); BME68X_OS_NONE, BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X, BME68X_OS_16X + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensor_BME68X.setMinMaxValue(-20, 80); + zbTempSensor_BME68X.setTolerance(1); + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + // Set analog resolution to 10 bits + // analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + + + // TRUE = Normal Home/Office use + // FALSE = Greenhouse / Constantly occupied + configureT6713(true); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor_T6713.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor_T6713); + + + + + + + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + // Increase keep-alive to 5 seconds (default is often 3000ms) + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 5000; + // zigbeeConfig.nwk_cfg.zed_cfg.ed_timeout = ESP_ZB_ED_AGING_TIMEOUT_256MIN; // 4 hours; How long the parent remembers this device. + + // 1. Our custom config (zigbeeConfig) + // 2. false = Do NOT erase NVS (keep network credentials) + // 3. true = Start automatically (optional, defaults to true) + if (!Zigbee.begin(&zigbeeConfig, false)) { + 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); + // } + // Record the start time + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; // 120 seconds + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + + // Check if 120 seconds have passed + if (millis() - startTime > timeoutMs) { + Serial.println("\nConnection timed out (120s). Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, LOW); + Serial.println("\nZigbee connected!"); + Serial.println(); + + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbTempSensor_SCD4X.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(1, 0, 1); + // zbAnalogDevice.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 + +} + + + + +void loop() { + // handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + + if (currentMode == eExitMode) { + // PRESENCE MODE + // static bool occupancy = false; + // bool occupancyNow = radar.motionDetection(); + // Serial.println(occupancyNow); + // // if (radar.motionDetection() == 1 && !occupancy) { + // if (occupancyNow != lastOccupancy) { + // Serial.println("MOTION DETECTED"); + // zbOccupancySensor.setOccupancy(occupancyNow); + // zbOccupancySensor.report(); + // // occupancy = true; + // lastOccupancy = occupancyNow; + // // } else if (radar.motionDetection() == 0 && occupancy) { + // // } else if (radar.motionDetection() == 0) { + // // Serial.println("MOTION ENDED"); + // // zbOccupancySensor.setOccupancy(false); + // // zbOccupancySensor.report(); + // // occupancy = false; + // } + // PRESENCE MODE - proper state machine + bool motionNow = radar.motionDetection(); + // Serial.println(motionNow); + // Serial.println(lastOccupancy); + // Serial.println(millis() - occupancyStartTime); + + if (motionNow && !lastOccupancy) { + // Motion STARTED → Set occupancy ON + Serial.println("MOTION DETECTED → OCCUPANCY ON"); + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + + } else if (motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion still present → timeout reset"); + occupancyStartTime = millis(); + + } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // TIMEOUT → Clear occupancy + Serial.println("OCCUPANCY TIMEOUT → OFF"); + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + + } else if (!motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion ended → timeout started"); + // occupancyStartTime = millis(); + } + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + + + // --- Read SCD41 --- + uint16_t co2_scd = 0; + float temperature_scd = 0.0f; + float humidity_scd = 0.0f; + bool scdReady = false; + + uint16_t error = scd41.readMeasurement(co2_scd, temperature_scd, humidity_scd); + if (error == 0 && co2_scd != 0) { + scdReady = true; + } + + if (scdReady) { + Serial.print("[SCD41] CO2: "); Serial.print(co2_scd); Serial.print(" ppm"); + Serial.print(" | Temp: "); Serial.print(temperature_scd); Serial.print(" C"); + Serial.print(" | Hum: "); Serial.print(humidity_scd); Serial.println(" %"); + + zbCarbonDioxideSensor.setCarbonDioxide(co2_scd); + zbCarbonDioxideSensor.report(); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_SCD4X.setTemperature(temperature_scd); + zbTempSensor_SCD4X.setHumidity(humidity_scd); + // Report temperature and humidity values + zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + } + // else { + // Serial.println("[SCD41] Waiting for measurement..."); + // } + + + // if(SCD4X.getDataReadyStatus()) { + // DFRobot_SCD4X::sSensorMeasurement_t data; + // SCD4X.readMeasurement(&data); + + // Serial.print("Carbon dioxide concentration : "); + // Serial.print(data.CO2ppm); + // Serial.println(" ppm"); + + // Serial.print("Environment temperature : "); + // Serial.print(data.temp); + // Serial.println(" C"); + + // Serial.print("Relative humidity : "); + // Serial.print(data.humidity); + // Serial.println(" RH"); + + // Serial.println(); + + // zbCarbonDioxideSensor.setCarbonDioxide(data.CO2ppm); + // zbCarbonDioxideSensor.report(); + + // // Update temperature and humidity values in Temperature sensor EP + // zbTempSensor_SCD4X.setTemperature(data.temp); + // zbTempSensor_SCD4X.setHumidity(data.humidity); + // // Report temperature and humidity values + // zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + + // } + + + // Serial.println("---------------------------"); + + float bme_temperature(NAN), bme_humidity(NAN), bme_pressure(NAN), bme_gasResistance(NAN); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + // delay(bme.getMeasDur(BME68X_FORCED_MODE) / 1000 + 50); + if (bme.fetchData() && (millis() - bme_report_time > 5000)) { + bme.getData(data); + bme_temperature = data.temperature; // Temperature in °C + bme_humidity = data.humidity; // Humidity in % + bme_pressure = data.pressure; // Pressure in hPa + bme_gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + Serial.printf("[BME680] temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", bme_temperature, bme_humidity, bme_gasResistance); + + zbTempSensor_BME68X.setTemperature(bme_temperature); + zbTempSensor_BME68X.setHumidity(bme_humidity); + // Report temperature and humidity values + zbTempSensor_BME68X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + + zbAnalogDevice_BME68X.setAnalogInput(bme_gasResistance); + zbAnalogDevice_BME68X.reportAnalogInput(); + + digitalWrite(LED_PIN, HIGH); + delay(50); + digitalWrite(LED_PIN, LOW); + + // Serial.print("BME68X reported."); + bme_report_time = millis(); + } + // else { + // Serial.println("BME680 -> Waiting..."); + // } + + + + + + // --- Read T6713 (CO2) --- + int co2_t6713 = readT6713(); + if ((co2_t6713 >= 0) && (millis() - t6713_report_time > 5000)) { + Serial.print("T6713 | CO2: "); Serial.print(co2_t6713); Serial.println(" ppm"); + zbCarbonDioxideSensor_T6713.setCarbonDioxide(co2_t6713); + zbCarbonDioxideSensor_T6713.report(); + t6713_report_time = millis(); + } + // else { + // Serial.println("T6713 | Read Error"); + // } + + + delay(100); +} + + + + + + +// Helper function for T6713 +int readT6713() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); // Address High + Wire.write(0x8B); // Address Low + Wire.write(0x00); + Wire.write(0x01); // Length (1 register) + if (Wire.endTransmission() != 0) return -1; + + delay(10); // Processing delay + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Skip Func & Len + byte high = Wire.read(); + byte low = Wire.read(); + return (high << 8) | low; + } + return -1; +} + + +void configureT6713(bool enableABC) { + // 1. Wait for Sensor Warm-up (at least 500ms after power on, datasheet says much longer for accuracy) + delay(1000); + + // 2. Check Status Register (Optional but good practice) + // We read register 0x138A (5002) to check for errors/warmup + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); + Wire.write(0x13); Wire.write(0x8A); // Address 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Func, Len + uint16_t status = (Wire.read() << 8) | Wire.read(); + // Bit 3 is Warm-up mode. If 1, sensor is still warming up. + if (status & 0x08) { + Serial.println("T6713: Warming up..."); + } + } + + // 3. Configure ABC Logic (Automatic Background Calibration) + // Write to Register 0x03EE (1006). Value: 0xFF00 = Enable, 0x0000 = Disable + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Function: Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + + byte error = Wire.endTransmission(); + if (error == 0) { + Serial.print("T6713: ABC Logic set to "); + Serial.println(enableABC ? "ON" : "OFF"); + } else { + Serial.println("T6713: Failed to set ABC Logic"); + } + + // 4. Wait for the write to "stick" + delay(100); +} + diff --git a/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/.theia/launch.json b/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1.ino b/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1.ino new file mode 100644 index 0000000..3b1d831 --- /dev/null +++ b/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/Node18_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1.ino @@ -0,0 +1,363 @@ + +// https://tutoduino.fr/en/tutorials/esp32c6-zigbee/ +// original: https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + + +// Board: esp32 -> ESP32C6 Dev Module +// Core Debug Level: Verbose +// Erase All Flash Before Sketch Upload: Enabled +// Partition scheme: Zigbee 4MB with spiffs +// Zigbee Mode: Zigbee ED + + + + + + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** + * @brief Zigbee temperature and humidity sensor Zigbee Sleepy End Device. + * + * https://tutoduino.fr/tutoriels/esp32c6-zigbee/ + * This code is based on example "Zigbee temperature and humidity sensor Sleepy device" created by Jan Procházka + * https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + */ + + + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +// Uncomment the following line to display debug traces in serial monitor of Arduino IDE +#define DEBUG_TRACE +#include "Zigbee.h" +//#include +//#include +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 7 +#define SDA_PIN 6 + + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Sleep for 10 minutes */ + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +// #define MAGNETIC_SENSOR_PIN 12 +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); +// bool contact_open = false; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.0; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float val; + val = (x - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(A0); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + +// Get data from BME280 sensor and go to deep sleep mode +void meausureAndSleep() { + // Measure temperature sensor value + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + float vBat; + + // BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + // BME280::PresUnit presUnit(BME280::PresUnit_hPa); + // Read temperature and humidity on BME280 sensor + // sensor.read(pressure, temperature, humidity, tempUnit, presUnit); + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + // Set the desired settings for the BME680 + //bme.amb_temp = 25; // Set ambient temperature for compensation + //bme.meas_status = 0; // Clear previous measurement status + // Perform a measurement + //rslt = bme68x_get_sensor_data(BME68X_ALL, &data, &bme); + //if (rslt == BME68X_OK) { + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + //zbTempSensor.setGasResistance(gasResistance); // Assuming you have a method for gas resistance + + + // Measure battery voltage + vBat = getVbatt(); + percentage = mapFloat(vBat, minVoltage, maxVoltage); +#ifdef DEBUG_TRACE + Serial.printf("Battery: %.2fV (%d%%)\n", vBat, percentage); +#endif + // Update battery percentage + zbTempSensor.setBatteryPercentage(percentage); + //zbTempSensor.setBatteryVoltage(vBat * 10); // voltage in 100mV + + + // Magnetic contact sensor + // static bool contact = false; + // if (digitalRead(MAGNETIC_SENSOR_PIN) == HIGH && !contact) { + // // Update contact sensor value + // zbContactSwitch.setOpen(); + // contact = true; + // Serial.printf("contact = true"); + // } else if (digitalRead(MAGNETIC_SENSOR_PIN) == LOW && contact) { + // zbContactSwitch.setClosed(); + // contact = false; + // Serial.printf("contact = false"); + // } + + + // Report values + zbTempSensor.report(); + zbTempSensor.reportBatteryPercentage(); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + zbCarbonDioxideSensor.report(); + +#ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); +#endif + // Turn on the builtin LED for a very short time + flashLED(); + // Add small delay to allow the data to be sent before going to sleep + delay(500); + // Put device to deep sleep +#ifdef DEBUG_TRACE + Serial.println("Going to sleep now"); +#endif + // esp_deep_sleep_start(); + delay(5000); +} + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + +/********************* Arduino functions **************************/ +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Configure use of external antenna + // pinMode(WIFI_ENABLE, OUTPUT); // pinMode(3, OUTPUT); + // digitalWrite(WIFI_ENABLE, LOW); // digitalWrite(3, LOW); // Activate RF switch control + // delay(100); + // pinMode(WIFI_ANT_CONFIG, OUTPUT); // pinMode(14, OUTPUT); + // digitalWrite(WIFI_ANT_CONFIG, HIGH); // digitalWrite(14, HIGH); // Use external antenna + + // Configure builtin LED and turn it OFF (HIGH) + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + /* + // Init BME280 sensor + Wire.begin(); + while (!sensor.begin()) { +#ifdef DEBUG_TRACE + Serial.println("Could not find BME280 sensor!"); +#endif + delay(1000); + } + */ + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + // Configure A0 as ADC input for reading battery voltage + pinMode(A0, INPUT); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor_Node18"); + //zbCarbonDioxideSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor"); + + // Set minimum and maximum temperature measurement value + zbTempSensor.setMinMaxValue(-20, 80); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + //zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + // pinMode(MAGNETIC_SENSOR_PIN, INPUT_PULLUP); // Assuming switch pulls LOW when closed + // Zigbee.addEndpoint(&zbContactSwitch); + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + // If Zigbee does not start with 30s default timeout (ZB_BEGIN_TIMEOUT_DEFAULT) then restart +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); // If Zigbee failed to start, reboot the device and try again + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + //zbCarbonDioxideSensor.setReporting(0, 30, 0); + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); + // Call the function to measure temperature and put the device to deep sleep + // meausureAndSleep(); +} + +void loop() { + // No actions are performed in the loop (the ESP32C6 enters the setup function when it exits deep sleep). + meausureAndSleep(); +} + + diff --git a/Node18_bme680_router_v2/.theia/launch.json b/Node18_bme680_router_v2/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node18_bme680_router_v2/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node18_bme680_router_v2/Node18_bme680_router_v2.ino b/Node18_bme680_router_v2/Node18_bme680_router_v2.ino new file mode 100644 index 0000000..4d131a3 --- /dev/null +++ b/Node18_bme680_router_v2/Node18_bme680_router_v2.ino @@ -0,0 +1,346 @@ +// ESP32C6 Dev Module +// Partition Scheme: ZIgbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZRZC (coordinator,router) + + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" +// #include + +// #define SENSOR_RX 17 // ESP32 RX connected to sensor TX +// #define SENSOR_TX 16 // ESP32 TX connected to sensor RX +// HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +// #define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +// uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +// ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 7 +#define SDA_PIN 6 + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +// #define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +// ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 11 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + +/************************ Temp sensor *****************************/ +static void bme680_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_BME68X.setTemperature(temperature); + zbTempSensor_BME68X.setHumidity(humidity); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("BME680: Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + delay(10000); + } +} + + + + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + + + +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + // Optional: set Zigbee device name and model + zbTempSensor_BME68X.setManufacturerAndModel("Espressif", "Node18_bme680_router"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbTempSensor_BME68X.setPowerSource(ZB_POWER_SOURCE_MAINS); + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_BME68X.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_BME68X.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin(ZIGBEE_ROUTER)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + + + + // Start Temperature sensor reading task + xTaskCreate(bme680_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(0, 15, 1); + // zbTempSensor2.setReporting(0, 15, 0); + + + // zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbAnalogDevice_BME68X.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + + +} + +void loop() { + // 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(); + } + } + // force report of illuminance when button is pressed + // zbIlluminanceSensor.report(); + zbTempSensor_BME68X.report(); + // zbCarbonDioxideSensor.report(); + zbAnalogDevice_BME68X.reportAnalogInput(); + // zbEnvSensor_sgp40_sht40.report(); + + } + delay(100); +} diff --git a/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/.theia/launch.json b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1.ino b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1.ino new file mode 100644 index 0000000..06ec4a0 --- /dev/null +++ b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v1.ino @@ -0,0 +1,364 @@ + +// https://tutoduino.fr/en/tutorials/esp32c6-zigbee/ +// original: https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + + +// Board: esp32 -> EDFRobot FireBeetle 2 ESP32-C6 +// Core Debug Level: Verbose +// Erase All Flash Before Sketch Upload: Enabled +// Partition scheme: Zigbee 4MB with spiffs +// Zigbee Mode: Zigbee ED + + + + + + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** + * @brief Zigbee temperature and humidity sensor Zigbee Sleepy End Device. + * + * https://tutoduino.fr/tutoriels/esp32c6-zigbee/ + * This code is based on example "Zigbee temperature and humidity sensor Sleepy device" created by Jan Procházka + * https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + */ + + + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +// Uncomment the following line to display debug traces in serial monitor of Arduino IDE +#define DEBUG_TRACE +#include "Zigbee.h" +//#include +//#include +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 8 +#define SDA_PIN 14 + +#define BAT_ADC_PIN 0 // ADC input pin + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 300 /* Sleep for 10 minutes */ + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +// #define MAGNETIC_SENSOR_PIN 12 +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); +// bool contact_open = false; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.0; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float val; + val = (x - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(BAT_ADC_PIN); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + +// Get data from BME280 sensor and go to deep sleep mode +void meausureAndSleep() { + // Measure temperature sensor value + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + float vBat; + + // BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + // BME280::PresUnit presUnit(BME280::PresUnit_hPa); + // Read temperature and humidity on BME280 sensor + // sensor.read(pressure, temperature, humidity, tempUnit, presUnit); + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + // Set the desired settings for the BME680 + //bme.amb_temp = 25; // Set ambient temperature for compensation + //bme.meas_status = 0; // Clear previous measurement status + // Perform a measurement + //rslt = bme68x_get_sensor_data(BME68X_ALL, &data, &bme); + //if (rslt == BME68X_OK) { + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + //zbTempSensor.setGasResistance(gasResistance); // Assuming you have a method for gas resistance + + + // Measure battery voltage + vBat = getVbatt(); + percentage = mapFloat(vBat, minVoltage, maxVoltage); +#ifdef DEBUG_TRACE + Serial.printf("Battery: %.2fV (%d%%)\n", vBat, percentage); +#endif + // Update battery percentage + zbTempSensor.setBatteryPercentage(percentage); + //zbTempSensor.setBatteryVoltage(vBat * 10); // voltage in 100mV + + + // Magnetic contact sensor + // static bool contact = false; + // if (digitalRead(MAGNETIC_SENSOR_PIN) == HIGH && !contact) { + // // Update contact sensor value + // zbContactSwitch.setOpen(); + // contact = true; + // Serial.printf("contact = true"); + // } else if (digitalRead(MAGNETIC_SENSOR_PIN) == LOW && contact) { + // zbContactSwitch.setClosed(); + // contact = false; + // Serial.printf("contact = false"); + // } + + + // Report values + zbTempSensor.report(); + zbTempSensor.reportBatteryPercentage(); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + zbCarbonDioxideSensor.report(); + +#ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); +#endif + // Turn on the builtin LED for a very short time + flashLED(); + // Add small delay to allow the data to be sent before going to sleep + delay(500); + // Put device to deep sleep +#ifdef DEBUG_TRACE + Serial.println("Going to sleep now"); +#endif + esp_deep_sleep_start(); + // delay(5000); +} + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + +/********************* Arduino functions **************************/ +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Configure use of external antenna + // pinMode(WIFI_ENABLE, OUTPUT); // pinMode(3, OUTPUT); + // digitalWrite(WIFI_ENABLE, LOW); // digitalWrite(3, LOW); // Activate RF switch control + // delay(100); + // pinMode(WIFI_ANT_CONFIG, OUTPUT); // pinMode(14, OUTPUT); + // digitalWrite(WIFI_ANT_CONFIG, HIGH); // digitalWrite(14, HIGH); // Use external antenna + + // Configure builtin LED and turn it OFF (HIGH) + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + /* + // Init BME280 sensor + Wire.begin(); + while (!sensor.begin()) { +#ifdef DEBUG_TRACE + Serial.println("Could not find BME280 sensor!"); +#endif + delay(1000); + } + */ + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + // Configure A0 as ADC input for reading battery voltage + pinMode(BAT_ADC_PIN, INPUT); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor_Node19"); + //zbCarbonDioxideSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor"); + + // Set minimum and maximum temperature measurement value + zbTempSensor.setMinMaxValue(-20, 80); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + //zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + // pinMode(MAGNETIC_SENSOR_PIN, INPUT_PULLUP); // Assuming switch pulls LOW when closed + // Zigbee.addEndpoint(&zbContactSwitch); + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + // If Zigbee does not start with 30s default timeout (ZB_BEGIN_TIMEOUT_DEFAULT) then restart +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); // If Zigbee failed to start, reboot the device and try again + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + //zbCarbonDioxideSensor.setReporting(0, 30, 0); + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); + // Call the function to measure temperature and put the device to deep sleep + meausureAndSleep(); +} + +void loop() { + // No actions are performed in the loop (the ESP32C6 enters the setup function when it exits deep sleep). + // meausureAndSleep(); +} + + diff --git a/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2/.theia/launch.json b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2.ino b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2.ino new file mode 100644 index 0000000..59cd90b --- /dev/null +++ b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v2.ino @@ -0,0 +1,440 @@ + +// https://tutoduino.fr/en/tutorials/esp32c6-zigbee/ +// original: https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + + +// Board: esp32 -> EDFRobot FireBeetle 2 ESP32-C6 +// Core Debug Level: Verbose +// Erase All Flash Before Sketch Upload: Enabled +// Partition scheme: Zigbee 4MB with spiffs +// Zigbee Mode: Zigbee ED + + + + + + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** + * @brief Zigbee temperature and humidity sensor Zigbee Sleepy End Device. + * + * https://tutoduino.fr/tutoriels/esp32c6-zigbee/ + * This code is based on example "Zigbee temperature and humidity sensor Sleepy device" created by Jan Procházka + * https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + */ + + + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +// Uncomment the following line to display debug traces in serial monitor of Arduino IDE +#define DEBUG_TRACE + +#include "Zigbee.h" +//#include +//#include +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 8 +#define SDA_PIN 14 + +#define BAT_ADC_PIN 0 // ADC input pin + +#define POWER_PIN 21 // GPIO pin to power the sensor + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 300 /* Sleep for 10 minutes */ + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + + +// /* Zigbee contact sensor configuration */ +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// uint8_t float_switch_pin = 3; +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); + + + +// #define MAGNETIC_SENSOR_PIN 12 +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); +// bool contact_open = false; + + + +/* Zigbee analog device configuration */ +#define ANALOG_DEVICE_ENDPOINT_NUMBER 13 +uint8_t analogPin = 3; +ZigbeeAnalog zbAnalogDevice = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.0; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float val; + val = (x - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(BAT_ADC_PIN); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + +// Get data from BME280 sensor and go to deep sleep mode +void meausureAndSleep() { + // Measure temperature sensor value + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + float vBat; + + // BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + // BME280::PresUnit presUnit(BME280::PresUnit_hPa); + // Read temperature and humidity on BME280 sensor + // sensor.read(pressure, temperature, humidity, tempUnit, presUnit); + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + // Set the desired settings for the BME680 + //bme.amb_temp = 25; // Set ambient temperature for compensation + //bme.meas_status = 0; // Clear previous measurement status + // Perform a measurement + //rslt = bme68x_get_sensor_data(BME68X_ALL, &data, &bme); + //if (rslt == BME68X_OK) { + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + + + +// // Checking pin for contact change +// static bool contact = false; +// if (digitalRead(float_switch_pin) == HIGH && !contact) { +// // Update contact sensor value +// // Serial.println("Float sensor: true"); +// zbContactSwitch.setOpen(); +// contact = true; +// } else if (digitalRead(float_switch_pin) == LOW && contact) { +// // Serial.println("Float sensor: true"); +// zbContactSwitch.setClosed(); +// contact = false; +// } +// #ifdef DEBUG_TRACE +// Serial.println(contact ? "Float sensor: true" : "Float sensor: false"); +// #endif + + + // Read ADC value and update the analog value every 2s + float analog = (float)analogRead(analogPin); + Serial.printf("Updating analog input to %.1f\r\n", analog); + zbAnalogDevice.setAnalogInput(analog); + // Analog input supports reporting + zbAnalogDevice.reportAnalogInput(); + + + + + + + + delay(100); + + digitalWrite(POWER_PIN, LOW); // Power off sensor + + + + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + //zbTempSensor.setGasResistance(gasResistance); // Assuming you have a method for gas resistance + + + // Measure battery voltage + vBat = getVbatt(); + percentage = mapFloat(vBat, minVoltage, maxVoltage); +#ifdef DEBUG_TRACE + Serial.printf("Battery: %.2fV (%d%%)\n", vBat, percentage); +#endif + // Update battery percentage + zbTempSensor.setBatteryPercentage(percentage); + //zbTempSensor.setBatteryVoltage(vBat * 10); // voltage in 100mV + + + // Magnetic contact sensor + // static bool contact = false; + // if (digitalRead(MAGNETIC_SENSOR_PIN) == HIGH && !contact) { + // // Update contact sensor value + // zbContactSwitch.setOpen(); + // contact = true; + // Serial.printf("contact = true"); + // } else if (digitalRead(MAGNETIC_SENSOR_PIN) == LOW && contact) { + // zbContactSwitch.setClosed(); + // contact = false; + // Serial.printf("contact = false"); + // } + + + // Report values + zbTempSensor.report(); + zbTempSensor.reportBatteryPercentage(); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + zbCarbonDioxideSensor.report(); + +#ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); +#endif + // Turn on the builtin LED for a very short time + flashLED(); + // Add small delay to allow the data to be sent before going to sleep + delay(500); + // Put device to deep sleep +#ifdef DEBUG_TRACE + Serial.println("Going to sleep now"); +#endif + esp_deep_sleep_start(); + // delay(5000); +} + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + +/********************* Arduino functions **************************/ +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Configure use of external antenna + // pinMode(WIFI_ENABLE, OUTPUT); // pinMode(3, OUTPUT); + // digitalWrite(WIFI_ENABLE, LOW); // digitalWrite(3, LOW); // Activate RF switch control + // delay(100); + // pinMode(WIFI_ANT_CONFIG, OUTPUT); // pinMode(14, OUTPUT); + // digitalWrite(WIFI_ANT_CONFIG, HIGH); // digitalWrite(14, HIGH); // Use external antenna + + // Configure builtin LED and turn it OFF (HIGH) + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); // Power on the sensor(s) + + + // Set analog resolution to 10 bits + analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice); + + + /* + // Init BME280 sensor + Wire.begin(); + while (!sensor.begin()) { +#ifdef DEBUG_TRACE + Serial.println("Could not find BME280 sensor!"); +#endif + delay(1000); + } + */ + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + // Configure A0 as ADC input for reading battery voltage + pinMode(BAT_ADC_PIN, INPUT); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor_Node19"); + //zbCarbonDioxideSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor"); + + // Set minimum and maximum temperature measurement value + zbTempSensor.setMinMaxValue(-20, 80); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + //zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + // pinMode(MAGNETIC_SENSOR_PIN, INPUT_PULLUP); // Assuming switch pulls LOW when closed + // Zigbee.addEndpoint(&zbContactSwitch); + + // pinMode(float_switch_pin, INPUT_PULLUP); + // Zigbee.addEndpoint(&zbContactSwitch); + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + // If Zigbee does not start with 30s default timeout (ZB_BEGIN_TIMEOUT_DEFAULT) then restart +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); // If Zigbee failed to start, reboot the device and try again + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + //zbCarbonDioxideSensor.setReporting(0, 30, 0); + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); + // Call the function to measure temperature and put the device to deep sleep + // meausureAndSleep(); +} + +void loop() { + // No actions are performed in the loop (the ESP32C6 enters the setup function when it exits deep sleep). + meausureAndSleep(); +} + + diff --git a/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3/.theia/launch.json b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3.ino b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3.ino new file mode 100644 index 0000000..b355296 --- /dev/null +++ b/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3/Node19_Zigbee_Temp_Hum_Sensor_Sleepy_BME6_v3.ino @@ -0,0 +1,579 @@ + +// https://tutoduino.fr/en/tutorials/esp32c6-zigbee/ +// original: https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + +// https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples + +// Board: esp32 -> EDFRobot FireBeetle 2 ESP32-C6 +// Core Debug Level: Verbose +// Erase All Flash Before Sketch Upload: Enabled +// Partition scheme: Zigbee 4MB with spiffs +// Zigbee Mode: Zigbee ED + + + + + + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +/** + * @brief Zigbee temperature and humidity sensor Zigbee Sleepy End Device. + * + * https://tutoduino.fr/tutoriels/esp32c6-zigbee/ + * This code is based on example "Zigbee temperature and humidity sensor Sleepy device" created by Jan Procházka + * https://github.com/espressif/arduino-esp32/tree/master/libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy + */ + + + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +// Uncomment the following line to display debug traces in serial monitor of Arduino IDE +#define DEBUG_TRACE + +#define USE_GLOBAL_ON_RESPONSE_CALLBACK 1 // Set to 0 to use local callback specified directly for the endpoint. + + +#include "Zigbee.h" +//#include +//#include +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 8 +#define SDA_PIN 14 + +#define BAT_ADC_PIN 0 // ADC input pin + +#define POWER_PIN 21 // GPIO pin to power the sensor + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 55 /* Sleep for 10 minutes */ +#define REPORT_TIMEOUT 1000 /* Timeout for response from coordinator in ms */ + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +uint8_t dataToSend = 4; // 10: T, rH, Batt; 11: CO2/resistance +bool resend = false; + + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + + +// /* Zigbee contact sensor configuration */ +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// uint8_t float_switch_pin = 3; +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); + + + +// #define MAGNETIC_SENSOR_PIN 12 +// #define CONTACT_SWITCH_ENDPOINT_NUMBER 12 +// ZigbeeContactSwitch zbContactSwitch = ZigbeeContactSwitch(CONTACT_SWITCH_ENDPOINT_NUMBER); +// bool contact_open = false; + + + +/* Zigbee analog device configuration */ +#define ANALOG_DEVICE_ENDPOINT_NUMBER 13 +uint8_t analogPin = 0; +ZigbeeAnalog zbAnalogDevice = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + +/************************ Callbacks *****************************/ +#if USE_GLOBAL_ON_RESPONSE_CALLBACK +void onGlobalResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status, uint8_t endpoint, uint16_t cluster) { + Serial.printf("Global response command: %d, status: %s, endpoint: %d, cluster: 0x%04x, dataToSend: %i\r\n", command, esp_zb_zcl_status_to_name(status), endpoint, cluster, dataToSend); + if ((command == ZB_CMD_REPORT_ATTRIBUTE) && (endpoint == TEMP_SENSOR_ENDPOINT_NUMBER)) { + switch (status) { + case ESP_ZB_ZCL_STATUS_SUCCESS: dataToSend--; break; + case ESP_ZB_ZCL_STATUS_FAIL: resend = true; break; + default: break; // add more statuses like ESP_ZB_ZCL_STATUS_INVALID_VALUE, ESP_ZB_ZCL_STATUS_TIMEOUT etc. + } + } +} +#else +void onResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status) { + Serial.printf("Response command: %d, status: %s\r\n", command, esp_zb_zcl_status_to_name(status)); + if (command == ZB_CMD_REPORT_ATTRIBUTE) { + switch (status) { + case ESP_ZB_ZCL_STATUS_SUCCESS: dataToSend--; break; + case ESP_ZB_ZCL_STATUS_FAIL: resend = true; break; + default: break; // add more statuses like ESP_ZB_ZCL_STATUS_INVALID_VALUE, ESP_ZB_ZCL_STATUS_TIMEOUT etc. + } + } +} +#endif + + + + + + + + + + + + + + + + + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + +// 3.7 V Li-Ion battery voltage +const float minVoltage = 3.0; +const float maxVoltage = 4.0; + +// Mapp float values to percentage +uint8_t mapFloat(float x, float in_min, float in_max) { + float val; + val = (x - in_min) * (100) / (in_max - in_min); + if (val < 0) { + val = 0; + } else if (val > 100) { + val = 100; + } + return (uint8_t)val; +} + + +// Get battery voltage en V +float getVbatt() { + uint32_t Vbatt = 0; + for (int i = 0; i < 16; i++) { + Vbatt += analogReadMilliVolts(BAT_ADC_PIN); // Read and accumulate ADC voltage + } + return (2 * Vbatt / 16 / 1000.0); // Adjust for 1:2 divider and convert to volts +} + + + + + + + + + + + +// Get data from BME280 sensor and go to deep sleep mode +static void meausureAndSleep(void *arg) { + // Measure temperature sensor value + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + float vBat; + + // BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); + // BME280::PresUnit presUnit(BME280::PresUnit_hPa); + // Read temperature and humidity on BME280 sensor + // sensor.read(pressure, temperature, humidity, tempUnit, presUnit); + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + // Set the desired settings for the BME680 + //bme.amb_temp = 25; // Set ambient temperature for compensation + //bme.meas_status = 0; // Clear previous measurement status + // Perform a measurement + //rslt = bme68x_get_sensor_data(BME68X_ALL, &data, &bme); + //if (rslt == BME68X_OK) { + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + + + +// // Checking pin for contact change +// static bool contact = false; +// if (digitalRead(float_switch_pin) == HIGH && !contact) { +// // Update contact sensor value +// // Serial.println("Float sensor: true"); +// zbContactSwitch.setOpen(); +// contact = true; +// } else if (digitalRead(float_switch_pin) == LOW && contact) { +// // Serial.println("Float sensor: true"); +// zbContactSwitch.setClosed(); +// contact = false; +// } +// #ifdef DEBUG_TRACE +// Serial.println(contact ? "Float sensor: true" : "Float sensor: false"); +// #endif + + + + + + + + + delay(100); + + digitalWrite(POWER_PIN, LOW); // Power off sensor + + + + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + //zbTempSensor.setGasResistance(gasResistance); // Assuming you have a method for gas resistance + + + // Measure battery voltage + vBat = getVbatt(); + percentage = mapFloat(vBat, minVoltage, maxVoltage); +#ifdef DEBUG_TRACE + Serial.printf("Battery: %.2fV (%d%%)\n", vBat, percentage); +#endif + // Update battery percentage + zbTempSensor.setBatteryPercentage(percentage); + //zbTempSensor.setBatteryVoltage(vBat * 10); // voltage in 100mV + + + // Magnetic contact sensor + // static bool contact = false; + // if (digitalRead(MAGNETIC_SENSOR_PIN) == HIGH && !contact) { + // // Update contact sensor value + // zbContactSwitch.setOpen(); + // contact = true; + // Serial.printf("contact = true"); + // } else if (digitalRead(MAGNETIC_SENSOR_PIN) == LOW && contact) { + // zbContactSwitch.setClosed(); + // contact = false; + // Serial.printf("contact = false"); + // } + + + + // Read ADC value and update the analog value every 2s + float analog = (float)analogRead(analogPin); + Serial.printf("Updating analog input to %.1f\r\n", analog); + zbAnalogDevice.setAnalogInput(analog); + // Analog input supports reporting + // zbAnalogDevice.reportAnalogInput(); + + + // Report values + zbTempSensor.report(); + zbTempSensor.reportBatteryPercentage(); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + zbCarbonDioxideSensor.report(); + +#ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + Serial.printf("dataToSend: %i\r\n", dataToSend); + delay(50); +#endif + + + // Turn on the builtin LED for a very short time + flashLED(); + // Add small delay to allow the data to be sent before going to sleep + delay(50); + // Put device to deep sleep + + + + unsigned long startTime = millis(); + const unsigned long timeout = REPORT_TIMEOUT; + + Serial.printf("Waiting for data report to be confirmed \r\n"); + // Wait until data was successfully sent + int tries = 0; + const int maxTries = 3; + while (dataToSend != 0 && tries < maxTries) { + if (resend) { + Serial.println("Resending data on failure!"); + resend = false; + dataToSend = 2; + zbTempSensor.report(); // report again + } + if (millis() - startTime >= timeout) { + Serial.println("\nReport timeout! Report Again"); + dataToSend = 2; + zbTempSensor.report(); // report again + startTime = millis(); + tries++; + } + Serial.printf("."); + delay(50); // 50ms delay to avoid busy-waiting + } + + +#ifdef DEBUG_TRACE + Serial.println("Going to sleep now"); +#endif + esp_deep_sleep_start(); + // delay(5000); + +} + + + + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + + + + + +/********************* Arduino functions **************************/ +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Configure use of external antenna + // pinMode(WIFI_ENABLE, OUTPUT); // pinMode(3, OUTPUT); + // digitalWrite(WIFI_ENABLE, LOW); // digitalWrite(3, LOW); // Activate RF switch control + // delay(100); + // pinMode(WIFI_ANT_CONFIG, OUTPUT); // pinMode(14, OUTPUT); + // digitalWrite(WIFI_ANT_CONFIG, HIGH); // digitalWrite(14, HIGH); // Use external antenna + + // Configure builtin LED and turn it OFF (HIGH) + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); // Power on the sensor(s) + + + // Set callback for default response to handle status of reported data, there are 2 options. +#if USE_GLOBAL_ON_RESPONSE_CALLBACK + // Global callback for all endpoints with more params to determine the endpoint and cluster in the callback function. + Zigbee.onGlobalDefaultResponse(onGlobalResponse); +#else + // Callback specified for endpoint + zbTempSensor.onDefaultResponse(onResponse); +#endif + + + + + + // Set analog resolution to 10 bits + analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice); + + + /* + // Init BME280 sensor + Wire.begin(); + while (!sensor.begin()) { +#ifdef DEBUG_TRACE + Serial.println("Could not find BME280 sensor!"); +#endif + delay(1000); + } + */ + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + // Configure A0 as ADC input for reading battery voltage + pinMode(BAT_ADC_PIN, INPUT); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor_Node19"); + //zbCarbonDioxideSensor.setManufacturerAndModel("Tutoduino", "ESP32C6TempSensor"); + + // Set minimum and maximum temperature measurement value + zbTempSensor.setMinMaxValue(-20, 80); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + //zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + // pinMode(MAGNETIC_SENSOR_PIN, INPUT_PULLUP); // Assuming switch pulls LOW when closed + // Zigbee.addEndpoint(&zbContactSwitch); + + // pinMode(float_switch_pin, INPUT_PULLUP); + // Zigbee.addEndpoint(&zbContactSwitch); + + + + + // Create a default Zigbee configuration for End Device + // esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + // If Zigbee does not start with 30s default timeout (ZB_BEGIN_TIMEOUT_DEFAULT) then restart +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); // If Zigbee failed to start, reboot the device and try again + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + //zbCarbonDioxideSensor.setReporting(0, 30, 0); + + + // Optional: Add reporting for analog input + // zbAnalogDevice.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 + + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + // delay(1000); + // Call the function to measure temperature and put the device to deep sleep + // meausureAndSleep(); + + // Start Temperature sensor reading task + xTaskCreate(meausureAndSleep, "temp_sensor_update", 2048, NULL, 10, NULL); + + +} + +void loop() { + // No actions are performed in the loop (the ESP32C6 enters the setup function when it exits deep sleep). + // meausureAndSleep(); +} + + diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1.ino b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1.ino new file mode 100644 index 0000000..816fdf1 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1.ino @@ -0,0 +1,207 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif + +#include "Zigbee.h" +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX +HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + + + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + + + + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} + +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS + // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); + + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + +void setup() { + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + turnOnSensor(7); + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node21"); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + 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!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +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; + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + Serial.println("GPIO2 LOW"); + } + + // 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); +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/README.md b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/README.md new file mode 100644 index 0000000..0c5dcd0 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/ci.json b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v1/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/.theia/launch.json b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2.ino b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2.ino new file mode 100644 index 0000000..8500c92 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2.ino @@ -0,0 +1,230 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif + +#include "Zigbee.h" +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX +HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + + + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + + + + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + Serial.write(c); // Print response to Serial Monitor + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} + +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS + // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); + sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + + sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + +void setup() { + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + turnOnSensor(7); + + for (int i = 0; i < numCommands; i++) { + const char* cmd = commands[i]; + sendCommandAndWaitForDone(cmd, mmWaveSerial); + delay(10); // small delay before next command (optional) + } + + + + + + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + pinMode(ledPin, OUTPUT); + + analogWrite(ledPin, 255); // pin, dutyCycle + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node21"); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + 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!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +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; + analogWrite(ledPin, 0); + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + analogWrite(ledPin, 255); + Serial.println("GPIO2 LOW"); + } + + // 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); +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/README.md b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/README.md new file mode 100644 index 0000000..0c5dcd0 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/ci.json b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v2/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3.ino b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3.ino new file mode 100644 index 0000000..df7aa73 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3.ino @@ -0,0 +1,332 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif + +#include "Zigbee.h" +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX +HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +#define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + // Read temperature sensor value + // float tsens_value = temperatureRead(); + float tsens_value = random(180, 300) / 10.0; + // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(tsens_value); + zbTempSensor2.setTemperature(tsens_value); + + float humidity = random(300, 700) / 10.0; + zbTempSensor.setHumidity(humidity); + zbTempSensor2.setHumidity(humidity); + + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} + + + + + + + + + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + + + + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + Serial.write(c); // Print response to Serial Monitor + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} + +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS + // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); + sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + + sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + +void setup() { + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + turnOnSensor(7); + + for (int i = 0; i < numCommands; i++) { + const char* cmd = commands[i]; + sendCommandAndWaitForDone(cmd, mmWaveSerial); + delay(10); // small delay before next command (optional) + } + + + + + + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + pinMode(ledPin, OUTPUT); + + analogWrite(ledPin, 255); // pin, dutyCycle + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node21"); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor2.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor2.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor2.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor2); + + + + + + + + + + + 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!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + + + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 0); + zbTempSensor2.setReporting(0, 15, 0); + + + +} + +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; + analogWrite(ledPin, 0); + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + analogWrite(ledPin, 255); + Serial.println("GPIO2 LOW"); + } + + // 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(); + } + } + } + // zbTempSensor.report(); + delay(100); +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/README.md b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/README.md new file mode 100644 index 0000000..0c5dcd0 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/ci.json b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v3/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4.ino b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4.ino new file mode 100644 index 0000000..658991e --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4.ino @@ -0,0 +1,571 @@ +// Xiao ESP32-C6 + +// uploading new script +// Zigbee connection establishment --> ....... +// force remove deivce from Z2M with permit join OFF +// swich permit JOIN ON +// restart ESP32 +// leave permit jion on until configuration finished + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX +HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 21 +#define SDA_PIN 22 + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + +#define ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT 9 +uint8_t illuminance_sensor_pin = 1; // Insert the analog pin to which the sensor (e.g. photoresistor) is connected + +ZigbeeIlluminanceSensor zbIlluminanceSensor = ZigbeeIlluminanceSensor(ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT); + +/********************* Illuminance sensor **************************/ +static void illuminance_sensor_value_update(void *arg) { + for (;;) { + // read the raw analog value from the sensor + int lsens_analog_raw = analogRead(illuminance_sensor_pin); + Serial.printf("[Illuminance Sensor] raw analog value: %d\r\n", lsens_analog_raw); + + // conversion into zigbee raw illuminance value (typically between 0 in darkness and 50000 in direct sunlight) + // depends on the value range of the raw analog sensor values and will need calibration for correct lux values + // for demonstration purpose map the 12-bit ADC value (0-4095) to Zigbee illuminance range (0-50000) + int lsens_illuminance_raw = map(lsens_analog_raw, 0, 4095, 0, 50000); + Serial.printf("[Illuminance Sensor] raw illuminance value: %d\r\n", lsens_illuminance_raw); + + // according to zigbee documentation the formular 10^(lsens_illuminance_raw/10000)-1 can be used to calculate lux value from raw illuminance value + // Note: Zigbee2MQTT seems to be using the formular 10^(lsens_illuminance_raw/10000) instead (without -1) + int lsens_illuminance_lux = round(pow(10, (lsens_illuminance_raw / 10000.0)) - 1); + Serial.printf("[Illuminance Sensor] lux value: %d lux\r\n", lsens_illuminance_lux); + + // Update illuminance in illuminance sensor EP + zbIlluminanceSensor.setIlluminance(lsens_illuminance_raw); // use raw illuminance here! + + delay(10000); // reduce delay (in ms), if you want your device to react more quickly to changes in illuminance + } +} + + + + + + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + + + + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + Serial.write(c); // Print response to Serial Monitor + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} + +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS + // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); + sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + + sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + + turnOnSensor(7); // initialization of mmwave sensor + + for (int i = 0; i < numCommands; i++) { + const char* cmd = commands[i]; + sendCommandAndWaitForDone(cmd, mmWaveSerial); + delay(10); // small delay before next command (optional) + } + + + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + pinMode(ledPin, OUTPUT); + + analogWrite(ledPin, 255); // pin, dutyCycle + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node21"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + + + + // // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + // zbTempSensor2.setMinMaxValue(10, 50); + + // // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + // zbTempSensor2.setTolerance(1); + + // // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // // Add humidity cluster to the temperature sensor device with min, max and tolerance values + // zbTempSensor2.addHumiditySensor(0, 100, 1); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbTempSensor2); + + + + + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + + + + + // Set minimum and maximum for raw illuminance value (0 min and 50000 max equals to 0 lux - 100,000 lux) + zbIlluminanceSensor.setMinMaxValue(0, 50000); + + // Optional: Set tolerance for raw illuminance value + zbIlluminanceSensor.setTolerance(1); + + // Add endpoint to Zigbee Core + Serial.println("Adding Zigbee illuminance sensor endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbIlluminanceSensor); + + + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 0); + // zbTempSensor2.setReporting(0, 15, 0); + + + zbCarbonDioxideSensor.setReporting(0, 30, 0); + + + + // Start illuminance sensor reading task + xTaskCreate(illuminance_sensor_value_update, "illuminance_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting schedule for illuminance value measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta + // if min = 1 and max = 0, delta = 1000, reporting is sent when raw illuminance value changes by 1000, but at most once per second + // if min = 0 and max = 10, delta = 1000, reporting is sent every 10 seconds or if raw illuminance value changes by 1000 + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of illuminance change + // Note: On pairing with Zigbee Home Automation or Zigbee2MQTT the reporting schedule will most likely be overwritten with their default settings + zbIlluminanceSensor.setReporting(1, 0, 1000); + + + +} + +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; + analogWrite(ledPin, 0); + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + analogWrite(ledPin, 255); + Serial.println("GPIO2 LOW"); + } + + // 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(); + } + } + // force report of illuminance when button is pressed + zbIlluminanceSensor.report(); + zbTempSensor.report(); + zbCarbonDioxideSensor.report(); + } + delay(100); +} diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/README.md b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/README.md new file mode 100644 index 0000000..0c5dcd0 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/ci.json b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node21_Zigbee_Occupancy_Sensor_XiaoESP32C6_v4/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1.ino b/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1.ino new file mode 100644 index 0000000..d6c6f2d --- /dev/null +++ b/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1.ino @@ -0,0 +1,138 @@ +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee Range Extender (router). + * + * The example demonstrates how to use Zigbee library to create a Zigbee network ragbe extender (router). + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator/router mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee light bulb configuration */ +#define USE_CUSTOM_ZIGBEE_CONFIG 1 +#define ZIGBEE_EXTENDER_ENDPOINT 1 +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 + +#ifndef LED_BUILTIN +#define LED_BUILTIN 4 +#endif + +uint8_t led = LED_BUILTIN; +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + +ZigbeeRangeExtender zbExtender = ZigbeeRangeExtender(ZIGBEE_EXTENDER_ENDPOINT); + +/************************** Identify ******************************/ +// Create a task on identify call to handle the identify function +void identify(uint16_t time) { + static uint8_t blink = 1; + log_d("Identify called for %d seconds", time); + if (time == 0) { + digitalWrite(led, LOW); + return; + } + digitalWrite(led, blink); + blink = !blink; +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + + // Optional: Set callback function for device identify + // zbExtender.onIdentify(identify); + + // Optional: Set Zigbee device name and model + zbExtender.setManufacturerAndModel("Espressif", "ZigbeeRangeExtender_Node21"); + + // Add endpoint to Zigbee Core + Serial.println("Adding Zigbee Extender endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbExtender); + Zigbee.addEndpoint(&zbOccupancySensor); + +#if USE_CUSTOM_ZIGBEE_CONFIG + // Optional: Create a custom Zigbee configuration for Zigbee Extender + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ROUTER_CONFIG(); + zigbeeConfig.nwk_cfg.zczr_cfg.max_children = 20; // 10 is default + + // When all EPs are registered, start Zigbee with custom config + if (!Zigbee.begin(&zigbeeConfig)) { +#else + // When all EPs are registered, start Zigbee as ROUTER device + if (!Zigbee.begin(ZIGBEE_ROUTER)) { +#endif + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); +} + +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; + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + Serial.println("GPIO2 LOW"); + } + + + // 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(); + } + } + } +} diff --git a/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/README.md b/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/README.md new file mode 100644 index 0000000..198dd85 --- /dev/null +++ b/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/README.md @@ -0,0 +1,68 @@ +# Arduino-ESP32 Zigbee Range Extender (Router) Example + +This example shows how to configure the Zigbee Router device and use it as a Home Automation (HA) network range extender. + +To see if the communication with your Zigbee network works, use the Serial monitor and watch for output there. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming +* Board (ESP32-H2 or ESP32-C6) as Zigbee router device and upload the Zigbee_Range_Extender example +* Zigbee network / coordinator (Other board with switch examples or Zigbee2mqtt or ZigbeeHomeAssistant like application) + +### Configure the Project + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the Coordinator/Router device Zigbee mode: `Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` (select correct size) +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the Router device flashed with this example is not connecting to the coordinator, erase the flash of the Router device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/ci.json b/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/ci.json new file mode 100644 index 0000000..15d6190 --- /dev/null +++ b/Node21_Zigbee_Range_Extender_XiaoESP32C6_v1/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node21_bme680_sen0395_photoresistor/Node21_bme680_sen0395_photoresistor.ino b/Node21_bme680_sen0395_photoresistor/Node21_bme680_sen0395_photoresistor.ino new file mode 100644 index 0000000..8a82c8e --- /dev/null +++ b/Node21_bme680_sen0395_photoresistor/Node21_bme680_sen0395_photoresistor.ino @@ -0,0 +1,626 @@ +// Xiao ESP32-C6 + +// uploading new script +// Zigbee connection establishment --> ....... +// force remove deivce from Z2M with permit join OFF +// swich permit JOIN ON +// restart ESP32 +// leave permit jion on until configuration finished + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX +HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 21 +#define SDA_PIN 22 + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +// #define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +// ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 13 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance / 1000.0)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + +#define ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT 9 +uint8_t illuminance_sensor_pin = 1; // Insert the analog pin to which the sensor (e.g. photoresistor) is connected + +ZigbeeIlluminanceSensor zbIlluminanceSensor = ZigbeeIlluminanceSensor(ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT); + +/********************* Illuminance sensor **************************/ +static void illuminance_sensor_value_update(void *arg) { + for (;;) { + // read the raw analog value from the sensor + int lsens_analog_raw = analogRead(illuminance_sensor_pin); + Serial.printf("[Illuminance Sensor] raw analog value: %d\r\n", lsens_analog_raw); + + // conversion into zigbee raw illuminance value (typically between 0 in darkness and 50000 in direct sunlight) + // depends on the value range of the raw analog sensor values and will need calibration for correct lux values + // for demonstration purpose map the 12-bit ADC value (0-4095) to Zigbee illuminance range (0-50000) + int lsens_illuminance_raw = map(lsens_analog_raw, 0, 4095, 0, 50000); + Serial.printf("[Illuminance Sensor] raw illuminance value: %d\r\n", lsens_illuminance_raw); + + // according to zigbee documentation the formular 10^(lsens_illuminance_raw/10000)-1 can be used to calculate lux value from raw illuminance value + // Note: Zigbee2MQTT seems to be using the formular 10^(lsens_illuminance_raw/10000) instead (without -1) + int lsens_illuminance_lux = round(pow(10, (lsens_illuminance_raw / 10000.0)) - 1); + Serial.printf("[Illuminance Sensor] lux value: %d lux\r\n", lsens_illuminance_lux); + + // Update illuminance in illuminance sensor EP + zbIlluminanceSensor.setIlluminance(lsens_illuminance_raw); // use raw illuminance here! + + delay(10000); // reduce delay (in ms), if you want your device to react more quickly to changes in illuminance + } +} + + + + + + +// 1. Define the task function (Global scope, outside setup/loop) +void pirTask(void * parameter) { + // Move the static variable here. It doesn't need to be 'static' anymore + // because this function only runs once and stays in the loop below. + bool occupancy = false; + + // 2. Infinite Loop: Tasks must never return! + for(;;) { + // --- Your Original Logic Start --- + if (digitalRead(sensor_pin) == HIGH && !occupancy) { + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + occupancy = true; + analogWrite(ledPin, 0); + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + analogWrite(ledPin, 255); + Serial.println("GPIO2 LOW"); + } + // --- Your Original Logic End --- + + // 3. CRITICAL: Delay to yield control + // Polling a PIR every 50ms is plenty fast and saves CPU. + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + + + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + + + + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + Serial.write(c); // Print response to Serial Monitor + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} + +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS + // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); + sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + + sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + + turnOnSensor(5); // initialization of mmwave sensor + + for (int i = 0; i < numCommands; i++) { + const char* cmd = commands[i]; + sendCommandAndWaitForDone(cmd, mmWaveSerial); + delay(10); // small delay before next command (optional) + } + + + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + pinMode(ledPin, OUTPUT); + + analogWrite(ledPin, 255); // pin, dutyCycle + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node21"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + + + + // // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + // zbTempSensor2.setMinMaxValue(10, 50); + + // // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + // zbTempSensor2.setTolerance(1); + + // // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // // Add humidity cluster to the temperature sensor device with min, max and tolerance values + // zbTempSensor2.addHumiditySensor(0, 100, 1); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbTempSensor2); + + + + + + + // // Set minimum and maximum carbon dioxide measurement value in ppm + // zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + // // Add endpoints to Zigbee Core + // Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + // Set minimum and maximum for raw illuminance value (0 min and 50000 max equals to 0 lux - 100,000 lux) + zbIlluminanceSensor.setMinMaxValue(0, 50000); + + // Optional: Set tolerance for raw illuminance value + zbIlluminanceSensor.setTolerance(1); + + // Add endpoint to Zigbee Core + Serial.println("Adding Zigbee illuminance sensor endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbIlluminanceSensor); + + + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + + + + + // 4. Create the task + xTaskCreate( + pirTask, // Function to call + "PIR_Check", // Name for debugging + 4096, // Stack size (bytes) - Zigbee operations need space! + NULL, // Parameter to pass + 1, // Priority (1 is standard, higher numbers = higher priority) + NULL // Task handle + ); + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 1); + // zbTempSensor2.setReporting(0, 15, 0); + + + // zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbAnalogDevice_BME68X.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + + // Start illuminance sensor reading task + xTaskCreate(illuminance_sensor_value_update, "illuminance_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting schedule for illuminance value measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta + // if min = 1 and max = 0, delta = 1000, reporting is sent when raw illuminance value changes by 1000, but at most once per second + // if min = 0 and max = 10, delta = 1000, reporting is sent every 10 seconds or if raw illuminance value changes by 1000 + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of illuminance change + // Note: On pairing with Zigbee Home Automation or Zigbee2MQTT the reporting schedule will most likely be overwritten with their default settings + zbIlluminanceSensor.setReporting(1, 0, 1); + + + +} + +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; + // analogWrite(ledPin, 0); + // Serial.println("GPIO2 HIGH"); + // } else if (digitalRead(sensor_pin) == LOW && occupancy) { + // zbOccupancySensor.setOccupancy(false); + // zbOccupancySensor.report(); + // occupancy = false; + // analogWrite(ledPin, 255); + // Serial.println("GPIO2 LOW"); + // } + + // 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(); + } + } + // force report of illuminance when button is pressed + zbIlluminanceSensor.report(); + zbTempSensor.report(); + // zbCarbonDioxideSensor.report(); + zbAnalogDevice_BME68X.reportAnalogInput(); + + } + delay(100); +} diff --git a/Node21_bme680_sen0395_photoresistor/README.md b/Node21_bme680_sen0395_photoresistor/README.md new file mode 100644 index 0000000..0c5dcd0 --- /dev/null +++ b/Node21_bme680_sen0395_photoresistor/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_bme680_sen0395_photoresistor/ci.json b/Node21_bme680_sen0395_photoresistor/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node21_bme680_sen0395_photoresistor/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node21_bme680_sen0395_photoresistor_router_v2/Node21_bme680_sen0395_photoresistor_router_v2.ino b/Node21_bme680_sen0395_photoresistor_router_v2/Node21_bme680_sen0395_photoresistor_router_v2.ino new file mode 100644 index 0000000..6dd5754 --- /dev/null +++ b/Node21_bme680_sen0395_photoresistor_router_v2/Node21_bme680_sen0395_photoresistor_router_v2.ino @@ -0,0 +1,630 @@ +// Xiao ESP32-C6 + +// uploading new script +// Zigbee connection establishment --> ....... +// force remove deivce from Z2M with permit join OFF +// swich permit JOIN ON +// restart ESP32 +// leave permit jion on until configuration finished + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif +#ifndef ZIGBEE_MODE_ZCZR +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" +#include + +#define SENSOR_RX 17 // ESP32 RX connected to sensor TX +#define SENSOR_TX 16 // ESP32 TX connected to sensor RX +HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 21 +#define SDA_PIN 22 + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +// #define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +// ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 13 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + +#define ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT 9 +uint8_t illuminance_sensor_pin = 1; // Insert the analog pin to which the sensor (e.g. photoresistor) is connected + +ZigbeeIlluminanceSensor zbIlluminanceSensor = ZigbeeIlluminanceSensor(ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT); + +/********************* Illuminance sensor **************************/ +static void illuminance_sensor_value_update(void *arg) { + for (;;) { + // read the raw analog value from the sensor + int lsens_analog_raw = analogRead(illuminance_sensor_pin); + Serial.printf("[Illuminance Sensor] raw analog value: %d\r\n", lsens_analog_raw); + + // conversion into zigbee raw illuminance value (typically between 0 in darkness and 50000 in direct sunlight) + // depends on the value range of the raw analog sensor values and will need calibration for correct lux values + // for demonstration purpose map the 12-bit ADC value (0-4095) to Zigbee illuminance range (0-50000) + int lsens_illuminance_raw = map(lsens_analog_raw, 0, 4095, 0, 50000); + Serial.printf("[Illuminance Sensor] raw illuminance value: %d\r\n", lsens_illuminance_raw); + + // according to zigbee documentation the formular 10^(lsens_illuminance_raw/10000)-1 can be used to calculate lux value from raw illuminance value + // Note: Zigbee2MQTT seems to be using the formular 10^(lsens_illuminance_raw/10000) instead (without -1) + int lsens_illuminance_lux = round(pow(10, (lsens_illuminance_raw / 10000.0)) - 1); + Serial.printf("[Illuminance Sensor] lux value: %d lux\r\n", lsens_illuminance_lux); + + // Update illuminance in illuminance sensor EP + zbIlluminanceSensor.setIlluminance(lsens_illuminance_raw); // use raw illuminance here! + + delay(10000); // reduce delay (in ms), if you want your device to react more quickly to changes in illuminance + } +} + + + + + + +// 1. Define the task function (Global scope, outside setup/loop) +void pirTask(void * parameter) { + // Move the static variable here. It doesn't need to be 'static' anymore + // because this function only runs once and stays in the loop below. + bool occupancy = false; + + // 2. Infinite Loop: Tasks must never return! + for(;;) { + // --- Your Original Logic Start --- + if (digitalRead(sensor_pin) == HIGH && !occupancy) { + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + occupancy = true; + analogWrite(ledPin, 0); + Serial.println("GPIO2 HIGH"); + } else if (digitalRead(sensor_pin) == LOW && occupancy) { + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + occupancy = false; + analogWrite(ledPin, 255); + Serial.println("GPIO2 LOW"); + } + // --- Your Original Logic End --- + + // 3. CRITICAL: Delay to yield control + // Polling a PIR every 50ms is plenty fast and saves CPU. + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + + + +const char* commands[] = { + "getRange", + "getSensitivity", + "getLatency", + "getUart", + "getGpioMode 2", + "getLedMode 1", + "getEcho", + "getUartOutput 1", + "getUartOutput 2", + // "sensorStop", + // "sensorStart", + // "saveConfig", + // "resetCfg", + // "resetSystem", + "getHWV", + "getSWV", + "getOutput" +}; + +const int numCommands = sizeof(commands) / sizeof(commands[0]); + +String line = ""; + + + + + +bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { + // Send the command + sensorSerial.println(command); + Serial.print("Sending: "); + Serial.println(command); + + // Wait for "Done" response + unsigned long startTime = millis(); + String response; + + while (millis() - startTime < timeout) { + while (sensorSerial.available()) { + char c = sensorSerial.read(); + Serial.write(c); // Print response to Serial Monitor + response += c; + + // If "Done" is found in the response, return success + if (response.indexOf("Done") >= 0) { + Serial.println("✓ Done received."); + return true; + } + + // Optional: detect "Error" for debugging + if (response.indexOf("Error") >= 0) { + Serial.println("✗ Error received."); + return false; + } + } + } + + Serial.println("✗ Timeout waiting for Done."); + return false; +} + +void turnOnSensor(int sensitivity) { + Serial.println("=== Turning On Sensor ==="); + + sendCommandAndWaitForDone("sensorStop", mmWaveSerial); + sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + + // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS + // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO + sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS + sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + + sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); + sendCommandAndWaitForDone("setRange 0 6", mmWaveSerial); + sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + + sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). + sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off + sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + + sendCommandAndWaitForDone("saveConfig", mmWaveSerial); + sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +} + + + + + +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + + turnOnSensor(5); // initialization of mmwave sensor + + for (int i = 0; i < numCommands; i++) { + const char* cmd = commands[i]; + sendCommandAndWaitForDone(cmd, mmWaveSerial); + delay(10); // small delay before next command (optional) + } + + + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + + + // Init button + PIR sensor + pinMode(button, INPUT_PULLUP); + pinMode(sensor_pin, INPUT_PULLUP); + pinMode(ledPin, OUTPUT); + + analogWrite(ledPin, 255); // pin, dutyCycle + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node21"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + + + + + // // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + // zbTempSensor2.setMinMaxValue(10, 50); + + // // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + // zbTempSensor2.setTolerance(1); + + // // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // // Add humidity cluster to the temperature sensor device with min, max and tolerance values + // zbTempSensor2.addHumiditySensor(0, 100, 1); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbTempSensor2); + + + + + + + // // Set minimum and maximum carbon dioxide measurement value in ppm + // zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + // // Add endpoints to Zigbee Core + // Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + // Set minimum and maximum for raw illuminance value (0 min and 50000 max equals to 0 lux - 100,000 lux) + zbIlluminanceSensor.setMinMaxValue(0, 50000); + + // Optional: Set tolerance for raw illuminance value + zbIlluminanceSensor.setTolerance(1); + + // Add endpoint to Zigbee Core + Serial.println("Adding Zigbee illuminance sensor endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbIlluminanceSensor); + + + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin(ZIGBEE_ROUTER)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + + + + + // 4. Create the task + xTaskCreate( + pirTask, // Function to call + "PIR_Check", // Name for debugging + 4096, // Stack size (bytes) - Zigbee operations need space! + NULL, // Parameter to pass + 1, // Priority (1 is standard, higher numbers = higher priority) + NULL // Task handle + ); + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 1); + // zbTempSensor2.setReporting(0, 15, 0); + + + // zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbAnalogDevice_BME68X.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + + // Start illuminance sensor reading task + xTaskCreate(illuminance_sensor_value_update, "illuminance_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting schedule for illuminance value measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta + // if min = 1 and max = 0, delta = 1000, reporting is sent when raw illuminance value changes by 1000, but at most once per second + // if min = 0 and max = 10, delta = 1000, reporting is sent every 10 seconds or if raw illuminance value changes by 1000 + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of illuminance change + // Note: On pairing with Zigbee Home Automation or Zigbee2MQTT the reporting schedule will most likely be overwritten with their default settings + zbIlluminanceSensor.setReporting(1, 0, 1); + + + +} + +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; + // analogWrite(ledPin, 0); + // Serial.println("GPIO2 HIGH"); + // } else if (digitalRead(sensor_pin) == LOW && occupancy) { + // zbOccupancySensor.setOccupancy(false); + // zbOccupancySensor.report(); + // occupancy = false; + // analogWrite(ledPin, 255); + // Serial.println("GPIO2 LOW"); + // } + + // 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(); + } + } + // force report of illuminance when button is pressed + zbIlluminanceSensor.report(); + zbTempSensor.report(); + // zbCarbonDioxideSensor.report(); + zbAnalogDevice_BME68X.reportAnalogInput(); + + } + delay(100); +} diff --git a/Node21_bme680_sen0395_photoresistor_router_v2/README.md b/Node21_bme680_sen0395_photoresistor_router_v2/README.md new file mode 100644 index 0000000..0c5dcd0 --- /dev/null +++ b/Node21_bme680_sen0395_photoresistor_router_v2/README.md @@ -0,0 +1,57 @@ +# Arduino-ESP32 Zigbee Occupancy Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) occupancy sensor (PIR). + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). +Set the Sensor GPIO by changing the `sensor_pin` variable. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node21_bme680_sen0395_photoresistor_router_v2/ci.json b/Node21_bme680_sen0395_photoresistor_router_v2/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node21_bme680_sen0395_photoresistor_router_v2/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node22_Zigbee_Fan_Control_TempHum_v1/.theia/launch.json b/Node22_Zigbee_Fan_Control_TempHum_v1/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v1/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node22_Zigbee_Fan_Control_TempHum_v1/Node22_Zigbee_Fan_Control_TempHum_v1.ino b/Node22_Zigbee_Fan_Control_TempHum_v1/Node22_Zigbee_Fan_Control_TempHum_v1.ino new file mode 100644 index 0000000..3fa8461 --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v1/Node22_Zigbee_Fan_Control_TempHum_v1.ino @@ -0,0 +1,385 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee light bulb. + * + * The example demonstrates how to use Zigbee library to create a end device light bulb. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" + +/* Zigbee light bulb configuration */ +#define ZIGBEE_LIGHT_ENDPOINT 10 +//uint8_t led = LED_BUILTIN; +uint8_t led = 6; +uint8_t button = BOOT_PIN; +#define LED_PIN 15 // Onboard LED + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 22 +#define SDA_PIN 21 + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + + +ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); +// ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/********************* RGB LED functions **************************/ +void setLED(bool value) { + Serial.println("setLED called"); + digitalWrite(LED_PIN, value); + digitalWrite(led, value); +} + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} + +static void temp_sensor_value_update_old(void *arg) { + for (;;) { + // Read temperature sensor value + // float tsens_value = temperatureRead(); + float tsens_value = random(180, 300) / 10.0; + // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(tsens_value); + + float humidity = random(300, 700) / 10.0; + zbTempSensor.setHumidity(humidity); + + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature; + + // Simulate temperature between 18.0°C and 30.0°C + float temperature = random(180, 300) / 10.0; + // Simulate humidity between 30.0% and 70.0% + float humidity = random(300, 700) / 10.0; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(100); + + // Put device to deep sleep + // Serial.println("Going to sleep now"); + // esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood) + pinMode(led, OUTPUT); + digitalWrite(led, LOW); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + //Optional: set Zigbee device name and model + zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb_Node22"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbLight.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Set callback function for light change + zbLight.onLightChange(setLED); + + //Add endpoint to Zigbee Core + Serial.println("Adding ZigbeeLight endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbLight); + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + + + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + + + + + // Create a default Zigbee configuration for End Device + // esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 0); + + zbCarbonDioxideSensor.setReporting(0, 30, 0); + +} + +void loop() { + // 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(); + } + } + // Toggle light by pressing the button + zbLight.setLight(!zbLight.getLightState()); + // Call the function to measure temperature and put the device to sleep + // meausureAndSleep(); + // zbTempSensor.reportTemperature(); + zbTempSensor.report(); + zbCarbonDioxideSensor.report(); + } + delay(100); +} diff --git a/Node22_Zigbee_Fan_Control_TempHum_v1/README.md b/Node22_Zigbee_Fan_Control_TempHum_v1/README.md new file mode 100644 index 0000000..e74c750 --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v1/README.md @@ -0,0 +1,70 @@ +# Arduino-ESP32 Zigbee On/Off Light Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) on/off light. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_On_Off_switch example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_On_Off_Light example + +### Configure the Project + +Set the LED GPIO by changing the `LED_PIN` definition. By default, the LED_PIN is `RGB_BUILTIN`. +By default, the `rgbLedWrite` function is used to control the LED. You can change it to digitalWrite to control a simple LED. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node22_Zigbee_Fan_Control_TempHum_v1/ci.json b/Node22_Zigbee_Fan_Control_TempHum_v1/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v1/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node22_Zigbee_Fan_Control_TempHum_v2/.theia/launch.json b/Node22_Zigbee_Fan_Control_TempHum_v2/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v2/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Node22_Zigbee_Fan_Control_TempHum_v2/Node22_Zigbee_Fan_Control_TempHum_v2.ino b/Node22_Zigbee_Fan_Control_TempHum_v2/Node22_Zigbee_Fan_Control_TempHum_v2.ino new file mode 100644 index 0000000..6eeaf82 --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v2/Node22_Zigbee_Fan_Control_TempHum_v2.ino @@ -0,0 +1,431 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee light bulb. + * + * The example demonstrates how to use Zigbee library to create a end device light bulb. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" + +/* Zigbee light bulb configuration */ +#define ZIGBEE_FAN_CONTROL_ENDPOINT 10 +//uint8_t led = LED_BUILTIN; +uint8_t led = 6; +uint8_t button = BOOT_PIN; +#define LED_PIN 15 // Onboard LED + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 22 +#define SDA_PIN 21 + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + + + + +ZigbeeFanControl zbFanControl = ZigbeeFanControl(ZIGBEE_FAN_CONTROL_ENDPOINT); +// ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/********************* RGB LED functions **************************/ +void setLED(bool value) { + Serial.println("setLED called"); + digitalWrite(LED_PIN, value); + digitalWrite(led, value); +} + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} + +static void temp_sensor_value_update_old(void *arg) { + for (;;) { + // Read temperature sensor value + // float tsens_value = temperatureRead(); + float tsens_value = random(180, 300) / 10.0; + // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(tsens_value); + + float humidity = random(300, 700) / 10.0; + zbTempSensor.setHumidity(humidity); + + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature; + + // Simulate temperature between 18.0°C and 30.0°C + float temperature = random(180, 300) / 10.0; + // Simulate humidity between 30.0% and 70.0% + float humidity = random(300, 700) / 10.0; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(100); + + // Put device to deep sleep + // Serial.println("Going to sleep now"); + // esp_deep_sleep_start(); +} + + + + + + + + +/********************* fan control callback function **************************/ +void setFan(ZigbeeFanMode mode) { + switch (mode) { + case FAN_MODE_OFF: + rgbLedWrite(led, 0, 0, 0); // Off + Serial.println("Fan mode: OFF"); + break; + case FAN_MODE_LOW: + rgbLedWrite(led, 0, 0, 255); // Blue + Serial.println("Fan mode: LOW"); + break; + case FAN_MODE_MEDIUM: + rgbLedWrite(led, 255, 255, 0); // Yellow + Serial.println("Fan mode: MEDIUM"); + break; + case FAN_MODE_HIGH: + rgbLedWrite(led, 255, 0, 0); // Red + Serial.println("Fan mode: HIGH"); + break; + case FAN_MODE_ON: + rgbLedWrite(led, 255, 255, 255); // White + Serial.println("Fan mode: ON"); + break; + default: log_e("Unhandled fan mode: %d", mode); break; + } +} + + + + + + + + + +/********************* Arduino functions **************************/ +void setup() { + +#ifdef DEBUG_TRACE + Serial.begin(115200); + delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood) + pinMode(led, OUTPUT); + digitalWrite(led, LOW); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + //Optional: set Zigbee device name and model + zbFanControl.setManufacturerAndModel("Espressif", "ZBLightBulb_Node22"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbFanControl.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // Set the fan mode sequence to LOW_MED_HIGH + zbFanControl.setFanModeSequence(FAN_MODE_SEQUENCE_LOW_MED_HIGH); + + // Set callback function for fan mode change + zbFanControl.onFanModeChange(setFan); + + //Add endpoint to Zigbee Core + Serial.println("Adding ZigbeeFanControl endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbFanControl); + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + + + + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + + + + + + // Create a default Zigbee configuration for End Device + // esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 0); + + zbCarbonDioxideSensor.setReporting(0, 30, 0); + +} + +void loop() { + // 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(); + } + } + // Toggle light by pressing the button + // zbLight.setLight(!zbLight.getLightState()); + // Call the function to measure temperature and put the device to sleep + // meausureAndSleep(); + // zbTempSensor.reportTemperature(); + zbTempSensor.report(); + zbCarbonDioxideSensor.report(); + } + delay(100); +} diff --git a/Node22_Zigbee_Fan_Control_TempHum_v2/README.md b/Node22_Zigbee_Fan_Control_TempHum_v2/README.md new file mode 100644 index 0000000..e74c750 --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v2/README.md @@ -0,0 +1,70 @@ +# Arduino-ESP32 Zigbee On/Off Light Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) on/off light. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_On_Off_switch example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_On_Off_Light example + +### Configure the Project + +Set the LED GPIO by changing the `LED_PIN` definition. By default, the LED_PIN is `RGB_BUILTIN`. +By default, the `rgbLedWrite` function is used to control the LED. You can change it to digitalWrite to control a simple LED. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node22_Zigbee_Fan_Control_TempHum_v2/ci.json b/Node22_Zigbee_Fan_Control_TempHum_v2/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node22_Zigbee_Fan_Control_TempHum_v2/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node23_Zigbee_Analog_Input_Output_v1/Node23_Zigbee_Analog_Input_Output_v1.ino b/Node23_Zigbee_Analog_Input_Output_v1/Node23_Zigbee_Analog_Input_Output_v1.ino new file mode 100644 index 0000000..a80c49f --- /dev/null +++ b/Node23_Zigbee_Analog_Input_Output_v1/Node23_Zigbee_Analog_Input_Output_v1.ino @@ -0,0 +1,188 @@ +/* + +how to define various analog devices: +https://github.com/espressif/esp-zigbee-sdk/blob/main/components/esp-zigbee-lib/include/zcl/esp_zigbee_zcl_analog_input.h + +zbAnalogTemp.setAnalogInputApplication(ESP_ZB_ZCL_AI_TEMPERATURE_OTHER); + + + + +*/ + + + + + + + + + + + + + + +// Copyright 2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee analog input / output device. + * + * The example demonstrates how to use Zigbee library to create a end device analog device. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + * Modified by Pat Clay + */ + +// #ifndef ZIGBEE_MODE_ZCZR +// #error "Zigbee coordinator/router device mode is not selected in Tools->Zigbee mode" +// #endif + +#include "Zigbee.h" + +/* Zigbee analog device configuration */ +#define ANALOG_DEVICE_ENDPOINT_NUMBER 1 + +uint8_t analogPin = A0; +uint8_t button = BOOT_PIN; + +ZigbeeAnalog zbAnalogDevice = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); +ZigbeeAnalog zbAnalogTemp = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 1); +ZigbeeAnalog zbAnalogFan = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 2); +ZigbeeAnalog zbAnalogPercent = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 3); + +void onAnalogOutputChange(float analog_output) { + Serial.printf("Received analog output change: %.1f\r\n", analog_output); +} + +void setup() { + Serial.begin(115200); + Serial.println("Starting..."); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Set analog resolution to 10 bits + analogReadResolution(10); + + // Optional: set Zigbee device name and model + zbAnalogDevice.setManufacturerAndModel("Espressif", "ZigbeeAnalogDevice_Node23"); + + // Set up analog input + zbAnalogDevice.addAnalogInput(); + zbAnalogDevice.setAnalogInputApplication(ESP_ZB_ZCL_AI_POWER_IN_WATTS_CONSUMPTION); + zbAnalogDevice.setAnalogInputDescription("Power Consumption (Watts)"); + zbAnalogDevice.setAnalogInputResolution(0.01); + + // Set up analog output + zbAnalogDevice.addAnalogOutput(); + zbAnalogDevice.setAnalogOutputApplication(ESP_ZB_ZCL_AI_RPM_OTHER); + zbAnalogDevice.setAnalogOutputDescription("Fan Speed (RPM)"); + zbAnalogDevice.setAnalogOutputResolution(1); + + // Set the min and max values for the analog output which is used by HA to limit the range of the analog output + zbAnalogDevice.setAnalogOutputMinMax(-10000, 10000); //-10000 to 10000 RPM + + // If analog output cluster is added, set callback function for analog output change + zbAnalogDevice.onAnalogOutputChange(onAnalogOutputChange); + + // Set up analog input + zbAnalogTemp.addAnalogInput(); + zbAnalogTemp.setAnalogInputApplication(ESP_ZB_ZCL_AI_TEMPERATURE_OTHER); + zbAnalogTemp.setAnalogInputDescription("Temperature"); + zbAnalogTemp.setAnalogInputResolution(0.1); + + // Set up analog input + zbAnalogFan.addAnalogInput(); + zbAnalogFan.setAnalogInputApplication(ESP_ZB_ZCL_AI_RPM_OTHER); + zbAnalogFan.setAnalogInputDescription("RPM"); + zbAnalogFan.setAnalogInputResolution(1); + + // Set up analog input + zbAnalogPercent.addAnalogInput(); + zbAnalogPercent.setAnalogInputApplication(ESP_ZB_ZCL_AI_PERCENTAGE_OTHER); + zbAnalogPercent.setAnalogInputDescription("Percentage"); + zbAnalogPercent.setAnalogInputResolution(0.01); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice); + Zigbee.addEndpoint(&zbAnalogTemp); + Zigbee.addEndpoint(&zbAnalogFan); + Zigbee.addEndpoint(&zbAnalogPercent); + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in Router Device mode + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + 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("Connected"); + + // Optional: Add reporting for analog input + zbAnalogDevice.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 +} + +void loop() { + static uint32_t timeCounter = 0; + + // Read ADC value and update the analog value every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + float analog = (float)analogRead(analogPin); + Serial.printf("Updating analog input to %.1f\r\n", analog); + zbAnalogDevice.setAnalogInput(analog); + zbAnalogTemp.setAnalogInput(analog / 100); + zbAnalogFan.setAnalogInput(analog); + zbAnalogPercent.setAnalogInput(analog / 10); + + // Analog input supports reporting + zbAnalogDevice.reportAnalogInput(); + zbAnalogTemp.reportAnalogInput(); + zbAnalogFan.reportAnalogInput(); + zbAnalogPercent.reportAnalogInput(); + } + + // Checking button for factory reset and reporting + 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(); + } + } + // For demonstration purposes, increment the analog output value by 100 + zbAnalogDevice.setAnalogOutput(zbAnalogDevice.getAnalogOutput() + 100); + zbAnalogDevice.reportAnalogOutput(); + } + delay(100); +} diff --git a/Node23_Zigbee_Analog_Input_Output_v1/README.md b/Node23_Zigbee_Analog_Input_Output_v1/README.md new file mode 100644 index 0000000..d629417 --- /dev/null +++ b/Node23_Zigbee_Analog_Input_Output_v1/README.md @@ -0,0 +1,72 @@ +# Arduino-ESP32 Zigbee Analog Input Output Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) analog input/output device. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Analog Sensor Functions + + * After this board first starts up, it would be configured locally to report an analog input on change or every 30 seconds. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured value to the network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +Set the ADC GPIO by changing the `analogPin` variable. By default, it's the pin `A0`. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node23_Zigbee_Analog_Input_Output_v1/ci.json b/Node23_Zigbee_Analog_Input_Output_v1/ci.json new file mode 100644 index 0000000..15d6190 --- /dev/null +++ b/Node23_Zigbee_Analog_Input_Output_v1/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr", + "requires": [ + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/Node23_Zigbee_Temp_Hum_Sensor_Sleepy.ino b/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/Node23_Zigbee_Temp_Hum_Sensor_Sleepy.ino new file mode 100644 index 0000000..9d1cf52 --- /dev/null +++ b/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/Node23_Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -0,0 +1,238 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +#define USE_GLOBAL_ON_RESPONSE_CALLBACK 1 // Set to 0 to use local callback specified directly for the endpoint. + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ +#define REPORT_TIMEOUT 1000 /* Timeout for response from coordinator in ms */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + + + +// #define ANALOG_DEVICE_ENDPOINT_NUMBER 1 +// ZigbeeAnalog zbAnalogPercent = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER + 3); + + + +uint8_t dataToSend = 2; // Temperature and humidity values are reported in same endpoint, so 2 values are reported +bool resend = false; + +/************************ Callbacks *****************************/ +#if USE_GLOBAL_ON_RESPONSE_CALLBACK +void onGlobalResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status, uint8_t endpoint, uint16_t cluster) { + Serial.printf("Global response command: %d, status: %s, endpoint: %d, cluster: 0x%04x\r\n", command, esp_zb_zcl_status_to_name(status), endpoint, cluster); + if ((command == ZB_CMD_REPORT_ATTRIBUTE) && (endpoint == TEMP_SENSOR_ENDPOINT_NUMBER)) { + switch (status) { + case ESP_ZB_ZCL_STATUS_SUCCESS: dataToSend--; break; + case ESP_ZB_ZCL_STATUS_FAIL: resend = true; break; + default: break; // add more statuses like ESP_ZB_ZCL_STATUS_INVALID_VALUE, ESP_ZB_ZCL_STATUS_TIMEOUT etc. + } + } +} +#else +void onResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status) { + Serial.printf("Response command: %d, status: %s\r\n", command, esp_zb_zcl_status_to_name(status)); + if (command == ZB_CMD_REPORT_ATTRIBUTE) { + switch (status) { + case ESP_ZB_ZCL_STATUS_SUCCESS: dataToSend--; break; + case ESP_ZB_ZCL_STATUS_FAIL: resend = true; break; + default: break; // add more statuses like ESP_ZB_ZCL_STATUS_INVALID_VALUE, ESP_ZB_ZCL_STATUS_TIMEOUT etc. + } + } +} +#endif + +/************************ Temp sensor *****************************/ +static void meausureAndSleep(void *arg) { + // Measure temperature sensor value + float temperature = temperatureRead(); + + // Use temperature value as humidity value to demonstrate both temperature and humidity + float humidity = temperature; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // float analogpercent = temperature * 0.5; + // zbAnalogPercent.reportAnalogInput(); + // Serial.printf("Reported zbAnalogPercent: %.2f°C\r\n", analogpercent); + + + unsigned long startTime = millis(); + const unsigned long timeout = REPORT_TIMEOUT; + + Serial.printf("Waiting for data report to be confirmed \r\n"); + // Wait until data was successfully sent + int tries = 0; + const int maxTries = 3; + while (dataToSend != 0 && tries < maxTries) { + if (resend) { + Serial.println("Resending data on failure!"); + resend = false; + dataToSend = 2; + zbTempSensor.report(); // report again + } + if (millis() - startTime >= timeout) { + Serial.println("\nReport timeout! Report Again"); + dataToSend = 2; + zbTempSensor.report(); // report again + startTime = millis(); + tries++; + } + Serial.printf("."); + delay(50); // 50ms delay to avoid busy-waiting + } + + // Put device to deep sleep after data was sent successfully or timeout + Serial.println("Going to sleep now"); + esp_deep_sleep_start(); + // delay(1000); + // Serial.println("\n---------------Next cycle-----------------"); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.println("---------------Setup begin-----------------"); + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor_Node23"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + + + // Set up analog input + // zbAnalogPercent.addAnalogInput(); + // zbAnalogPercent.setAnalogInputApplication(ESP_ZB_ZCL_AI_PERCENTAGE_OTHER); + // zbAnalogPercent.setAnalogInputDescription("Percentage"); + // zbAnalogPercent.setAnalogInputResolution(0.01); + + + // Set callback for default response to handle status of reported data, there are 2 options. + +#if USE_GLOBAL_ON_RESPONSE_CALLBACK + // Global callback for all endpoints with more params to determine the endpoint and cluster in the callback function. + Zigbee.onGlobalDefaultResponse(onGlobalResponse); +#else + // Callback specified for endpoint + zbTempSensor.onDefaultResponse(onResponse); +#endif + + + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Zigbee.addEndpoint(&zbAnalogPercent); + + + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); // If Zigbee failed to start, reboot the device and try again + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + // Start Temperature sensor reading task + xTaskCreate(meausureAndSleep, "temp_sensor_update", 2048, NULL, 10, NULL); +} + +void loop() { + // 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) > 10000) { + // If key pressed for more than 10secs, factory reset Zigbee and reboot + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + // Optional set reset in factoryReset to false, to not restart device after erasing nvram, but set it to endless sleep manually instead + Zigbee.factoryReset(false); + Serial.println("Going to endless sleep, press RESET button or power off/on the device to wake up"); + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); + esp_deep_sleep_start(); + } + } + } + delay(100); +} diff --git a/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/README.md b/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/README.md new file mode 100644 index 0000000..afaa12c --- /dev/null +++ b/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/README.md @@ -0,0 +1,75 @@ +# Arduino-ESP32 Zigbee Temperature and Humidity Sensor Sleepy Device Example + +This example demonstrates how to use the Zigbee library to create an end device temperature/humidity sensor and use it as a Home Automation (HA) extended temperature sensor. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Temperature Sensor Functions + +1. Initialize a Zigbee temperature and humidity sensor. +2. Measure temperature and humidity values. +3. Report the measured values to the Zigbee network. +4. Put the device to sleep to save power. + +## Hardware Required + +* ESP32-H2 or ESP32-C6 development board +* A USB cable for power supply and programming + +### Configure the Project + +In this example, to demonstrate the functionality the chip temperature is used and reported as temperature and humidity. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/ci.json b/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Node23_Zigbee_Temp_Hum_Sensor_Sleepy/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/NodeX_Zigbee_Fan_Control_TempHum_v1/.theia/launch.json b/NodeX_Zigbee_Fan_Control_TempHum_v1/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/NodeX_Zigbee_Fan_Control_TempHum_v1/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/NodeX_Zigbee_Fan_Control_TempHum_v1/NodeX_Zigbee_Fan_Control_TempHum_v1.ino b/NodeX_Zigbee_Fan_Control_TempHum_v1/NodeX_Zigbee_Fan_Control_TempHum_v1.ino new file mode 100644 index 0000000..c78e7c5 --- /dev/null +++ b/NodeX_Zigbee_Fan_Control_TempHum_v1/NodeX_Zigbee_Fan_Control_TempHum_v1.ino @@ -0,0 +1,209 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee light bulb. + * + * The example demonstrates how to use Zigbee library to create a end device light bulb. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#define DEBUG_TRACE + +#include "Zigbee.h" + +/* Zigbee light bulb configuration */ +#define ZIGBEE_LIGHT_ENDPOINT 10 +//uint8_t led = LED_BUILTIN; +uint8_t led = 6; +uint8_t button = BOOT_PIN; +#define LED_PIN 15 // Onboard LED + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 + +ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/********************* RGB LED functions **************************/ +void setLED(bool value) { + Serial.println("setLED called"); + digitalWrite(LED_PIN, value); + digitalWrite(led, value); +} + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + // Read temperature sensor value + // float tsens_value = temperatureRead(); + float tsens_value = random(180, 300) / 10.0; + // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(tsens_value); + + float humidity = random(300, 700) / 10.0; + zbTempSensor.setHumidity(humidity); + + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature; + + // Simulate temperature between 18.0°C and 30.0°C + float temperature = random(180, 300) / 10.0; + // Simulate humidity between 30.0% and 70.0% + float humidity = random(300, 700) / 10.0; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(100); + + // Put device to deep sleep + // Serial.println("Going to sleep now"); + // esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood) + pinMode(led, OUTPUT); + digitalWrite(led, LOW); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + //Optional: set Zigbee device name and model + zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); + + // Set callback function for light change + zbLight.onLightChange(setLED); + + //Add endpoint to Zigbee Core + Serial.println("Adding ZigbeeLight endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbLight); + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + + + + + // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 15, 0); + + +} + +void loop() { + // 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(); + } + } + // Toggle light by pressing the button + zbLight.setLight(!zbLight.getLightState()); + // Call the function to measure temperature and put the device to sleep + // meausureAndSleep(); + // zbTempSensor.reportTemperature(); + zbTempSensor.report(); + } + delay(100); +} diff --git a/NodeX_Zigbee_Fan_Control_TempHum_v1/README.md b/NodeX_Zigbee_Fan_Control_TempHum_v1/README.md new file mode 100644 index 0000000..e74c750 --- /dev/null +++ b/NodeX_Zigbee_Fan_Control_TempHum_v1/README.md @@ -0,0 +1,70 @@ +# Arduino-ESP32 Zigbee On/Off Light Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) on/off light. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_On_Off_switch example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_On_Off_Light example + +### Configure the Project + +Set the LED GPIO by changing the `LED_PIN` definition. By default, the LED_PIN is `RGB_BUILTIN`. +By default, the `rgbLedWrite` function is used to control the LED. You can change it to digitalWrite to control a simple LED. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/NodeX_Zigbee_Fan_Control_TempHum_v1/ci.json b/NodeX_Zigbee_Fan_Control_TempHum_v1/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/NodeX_Zigbee_Fan_Control_TempHum_v1/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/SHT31test/SHT31test.ino b/SHT31test/SHT31test.ino new file mode 100644 index 0000000..9e4a8a6 --- /dev/null +++ b/SHT31test/SHT31test.ino @@ -0,0 +1,73 @@ +/*************************************************** + This is an example for the SHT31-D Humidity & Temp Sensor + + Designed specifically to work with the SHT31-D sensor from Adafruit + ----> https://www.adafruit.com/products/2857 + + These sensors use I2C to communicate, 2 pins are required to + interface + ****************************************************/ + +#include +#include +#include "Adafruit_SHT31.h" + +bool enableHeater = false; +uint8_t loopCnt = 0; + +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +void setup() { + Serial.begin(9600); + Serial.println("Start"); + + while (!Serial) + delay(10); // will pause Zero, Leonardo, etc until serial console opens + + Serial.println("SHT31 test"); + if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr + Serial.println("Couldn't find SHT31"); + while (1) delay(1); + } + + Serial.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) + Serial.println("ENABLED"); + else + Serial.println("DISABLED"); +} + + +void loop() { + float t = sht31.readTemperature(); + float h = sht31.readHumidity(); + + if (! isnan(t)) { // check if 'is not a number' + Serial.print("Temp *C = "); Serial.print(t); Serial.print("\t\t"); + } else { + Serial.println("Failed to read temperature"); + } + + if (! isnan(h)) { // check if 'is not a number' + Serial.print("Hum. % = "); Serial.println(h); + } else { + Serial.println("Failed to read humidity"); + } + + delay(1000); + + // Toggle heater enabled state every 30 seconds + // An ~3.0 degC temperature increase can be noted when heater is enabled + if (loopCnt >= 30) { + enableHeater = !enableHeater; + sht31.heater(enableHeater); + Serial.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) + Serial.println("ENABLED"); + else + Serial.println("DISABLED"); + + loopCnt = 0; + } + loopCnt++; +} diff --git a/Telaire_T6713_test2/Telaire_T6713_test2.ino b/Telaire_T6713_test2/Telaire_T6713_test2.ino new file mode 100644 index 0000000..08b144e --- /dev/null +++ b/Telaire_T6713_test2/Telaire_T6713_test2.ino @@ -0,0 +1,63 @@ +// https://www.14core.com/wiring-the-telaire-t6713-t67xx-a-carbon-dioxide-co2-sensor/ + +#include //Import Arduino Wire Library +#define T6713_Address 0x15 //T6713 i2C Address + +int data [4]; +int ppmValue; + +void setup(){ + Serial.begin(9600); + Serial.println("14CORE | T67XX / AN161 CO2 Sensor Test Code"); + Serial.println("Initializing..............................."); + delay(2000); + Serial.println("Starting i2C Communicate ADDR 0x15........."); + Wire.begin(8, 14); + delay(1000); +} + +void loop(){ +int ppmValue = readSensor(); +if (ppmValue >= 0) { + Serial.println("CO2-Carbon Dioxide Read Value > "); + Serial.println(ppmValue); +} else { + Serial.println("ERROR | Failed to communicate to the sensor"); +} + delay(2000); +} + +int readSensor(){ + Wire.beginTransmission(T6713_Address); + Wire.write(0x04); + Wire.write(0x13); + Wire.write(0x8B); + Wire.write(0x00); + Wire.write(0x01); + Wire.endTransmission(); + delay(2000); + Wire.requestFrom(T6713_Address, 4); //Request 4 bytes from the sensor + data[0] = Wire.read(); + data[1] = Wire.read(); + data[2] = Wire.read(); + data[3] = Wire.read(); + Serial.println("FUNCTION CODE >"); + Serial.println(data[0], HEX); + Serial.println(""); + Serial.println("BYTE COUNT > "); + Serial.println(data[1], HEX); + Serial.println(""); + Serial.println("MOST SIGNIFICANT BIT > 0x"); + Serial.println(data[2],HEX); + Serial.println(""); + Serial.println("LEAST SIGNIFICANT BIT > 0x"); + Serial.println(data[3],HEX); + ppmValue = (((data[2] & 0x3F ) << 8) | data[3]); + Serial.println("CO2-Carbon Dioxide Read Value > "); + Serial.println(ppmValue); +} + + + + + diff --git a/ThinkInk_tricolor_waveshare_13338_working/.theia/launch.json b/ThinkInk_tricolor_waveshare_13338_working/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/ThinkInk_tricolor_waveshare_13338_working/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/ThinkInk_tricolor_waveshare_13338_working/ThinkInk_tricolor_waveshare_13338_working.ino b/ThinkInk_tricolor_waveshare_13338_working/ThinkInk_tricolor_waveshare_13338_working.ino new file mode 100644 index 0000000..a5ef966 --- /dev/null +++ b/ThinkInk_tricolor_waveshare_13338_working/ThinkInk_tricolor_waveshare_13338_working.ino @@ -0,0 +1,157 @@ +// https://www.waveshare.com/product/1.54inch-e-paper-module-b.htm +// https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)_Manual#ESP32.2F8266 +// https://learn.adafruit.com/adafruit-1-54-eink-display-breakouts/arduino-usage + + + + + + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#ifdef ARDUINO_ADAFRUIT_FEATHER_RP2040_THINKINK // detects if compiling for + // Feather RP2040 ThinkInk +#define EPD_DC PIN_EPD_DC // ThinkInk 24-pin connector DC +#define EPD_CS PIN_EPD_CS // ThinkInk 24-pin connector CS +#define EPD_BUSY PIN_EPD_BUSY // ThinkInk 24-pin connector Busy +#define SRAM_CS -1 // use onboard RAM +#define EPD_RESET PIN_EPD_RESET // ThinkInk 24-pin connector Reset +#define EPD_SPI &SPI1 // secondary SPI for ThinkInk +#else +#define EPD_DC 16 +#define EPD_CS 17 +#define EPD_BUSY 22 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS -1 +#define EPD_RESET 23 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI +#endif + +// 1.54" 152x152 Tricolor EPD with ILI0373 chipset +// ThinkInk_154_Tricolor_Z17 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); + +// 1.54" 152x152 Tricolor EPD with SSD1680 chipset +// ThinkInk_154_Tricolor_RW display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); + +// 1.54" 200x200 Tricolor EPD with SSD1681 chipset +ThinkInk_154_Tricolor_Z90 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +EPD_BUSY, EPD_SPI); + +// 2.13" Tricolor EPD with SSD1680 chipset +// ThinkInk_213_Tricolor_RW display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, +// EPD_SPI); + +// 2.13" Tricolor EPD with IL0373 chipset +// ThinkInk_213_Tricolor_Z16 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); + +// 2.7" Tricolor Featherwing or Breakout with IL91874 chipset +// ThinkInk_270_Tricolor_C44 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); + +// 2.7" Tricolor Featherwing or Breakout with EK79686 chipset +// ThinkInk_270_Tricolor_Z70 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); + +// 2.9" Tricolor Featherwing or Breakout with IL0373 chipset +// ThinkInk_290_Tricolor_Z10 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); +// 2.9" Tricolor Featherwing or Breakout with UC8151D chipset +// ThinkInk_290_Tricolor_Z13 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); +// 2.9" Tricolor Featherwing or Breakout with SSD1680 chipset and negative +// offset +// ThinkInk_290_Tricolor_Z94 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); + +// ThinkInk_420_Tricolor_RW display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +// EPD_BUSY, EPD_SPI); ThinkInk_420_Tricolor_Z21 display(EPD_DC, EPD_RESET, +// EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI); + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/black/white"); + display.begin(THINKINK_TRICOLOR); + + display.setRotation(2); + // 0: Default (0°) + // 1: Rotate 90° clockwise + // 2: Rotated 180° + // 3: Rotated 270° clockwise + +} + +void loop() { + Serial.println("Banner demo"); + display.clearBuffer(); + display.setTextSize(3); + display.setCursor((display.width() - 144) / 2, (display.height() - 24) / 2); + display.setTextColor(EPD_BLACK); + display.print("Tri"); + display.setTextColor(EPD_RED); + display.print("Color"); + display.display(); // refresh the screen + display.powerDown(); // save power + + delay(15000); + + Serial.println("Color rectangle demo"); + display.clearBuffer(); + display.fillRect(display.width() / 3, 0, display.width() / 3, + display.height(), EPD_BLACK); + display.fillRect((display.width() * 2) / 3, 0, display.width() / 3, + display.height(), EPD_RED); + display.display(); // refresh the screen + display.powerDown(); // save power + + delay(15000); + + Serial.println("Text demo"); + // large block of text + display.clearBuffer(); + display.setTextSize(1); + testdrawtext( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " + "adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, " + "fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor " + "neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet " + "ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a " + "tortor imperdiet posuere. ", + EPD_BLACK); + display.display(); // refresh the screen + display.powerDown(); // save power + + delay(15000); + + display.clearBuffer(); + for (int16_t i = 0; i < display.width(); i += 4) { + display.drawLine(0, 0, i, display.height() - 1, EPD_BLACK); + } + for (int16_t i = 0; i < display.height(); i += 4) { + display.drawLine(display.width() - 1, 0, 0, i, EPD_RED); + } + display.display(); // refresh the screen + display.powerDown(); // save power + + delay(15000); +} + +void testdrawtext(const char *text, uint16_t color) { + display.setCursor(0, 0); + display.setTextColor(color); + display.setTextWrap(true); + display.print(text); +} diff --git a/Zigbee_CarbonDioxide_Sensor__test/README.md b/Zigbee_CarbonDioxide_Sensor__test/README.md new file mode 100644 index 0000000..88c8bf0 --- /dev/null +++ b/Zigbee_CarbonDioxide_Sensor__test/README.md @@ -0,0 +1,72 @@ +# Arduino-ESP32 Carbon dioxide (CO2) Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) simple sensor device type with carbon dioxide measuring. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Pressure + Flow Sensor Functions + + * After this board first starts up, it would be configured locally to report the carbon dioxide on every 30 seconds. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured carbon dioxide to the network. + +## Hardware Required + +* A USB cable for power supply and programming + +### Configure the Project + +In this example, the internal temperature sensor is used to demonstrate reading of the carbon dioxide sensors. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Zigbee_CarbonDioxide_Sensor__test/Zigbee_CarbonDioxide_Sensor__test.ino b/Zigbee_CarbonDioxide_Sensor__test/Zigbee_CarbonDioxide_Sensor__test.ino new file mode 100644 index 0000000..3d8c08a --- /dev/null +++ b/Zigbee_CarbonDioxide_Sensor__test/Zigbee_CarbonDioxide_Sensor__test.ino @@ -0,0 +1,109 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee carbon dioxide sensor. + * + * The example demonstrates how to use Zigbee library to create a end device carbon dioxide sensor. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee carbon dioxide sensor configuration */ +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; + +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Optional: set Zigbee device name and model + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "ZigbeeCarbonDioxideSensor"); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; // 30 seconds + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + 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(); + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); +} + +void loop() { + static uint32_t timeCounter = 0; + // Read carbon dioxide sensor every 2s + if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s + // Read sensor value - here is chip temperature used + 300 as a dummy value for demonstration + uint16_t carbon_dioxide_value = 300 + (uint16_t)temperatureRead(); + Serial.printf("Updating carbon dioxide sensor value to %d ppm\r\n", carbon_dioxide_value); + zbCarbonDioxideSensor.setCarbonDioxide(carbon_dioxide_value); + } + + // Checking button for factory reset and reporting + 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(); + } + } + zbCarbonDioxideSensor.report(); + } + delay(100); +} diff --git a/Zigbee_CarbonDioxide_Sensor__test/ci.json b/Zigbee_CarbonDioxide_Sensor__test/ci.json new file mode 100644 index 0000000..7b7ccef --- /dev/null +++ b/Zigbee_CarbonDioxide_Sensor__test/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/Zigbee_On_Off_Light_fan_control_testv1/.theia/launch.json b/Zigbee_On_Off_Light_fan_control_testv1/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/Zigbee_On_Off_Light_fan_control_testv1/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Zigbee_On_Off_Light_fan_control_testv1/README.md b/Zigbee_On_Off_Light_fan_control_testv1/README.md new file mode 100644 index 0000000..e74c750 --- /dev/null +++ b/Zigbee_On_Off_Light_fan_control_testv1/README.md @@ -0,0 +1,70 @@ +# Arduino-ESP32 Zigbee On/Off Light Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) on/off light. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with Zigbee_On_Off_switch example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the Zigbee_On_Off_Light example + +### Configure the Project + +Set the LED GPIO by changing the `LED_PIN` definition. By default, the LED_PIN is `RGB_BUILTIN`. +By default, the `rgbLedWrite` function is used to control the LED. You can change it to digitalWrite to control a simple LED. + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Zigbee_On_Off_Light_fan_control_testv1/Zigbee_On_Off_Light_fan_control_testv1.ino b/Zigbee_On_Off_Light_fan_control_testv1/Zigbee_On_Off_Light_fan_control_testv1.ino new file mode 100644 index 0000000..7ba61cc --- /dev/null +++ b/Zigbee_On_Off_Light_fan_control_testv1/Zigbee_On_Off_Light_fan_control_testv1.ino @@ -0,0 +1,202 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates simple Zigbee light bulb. + * + * The example demonstrates how to use Zigbee library to create a end device light bulb. + * The light bulb is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee light bulb configuration */ +#define ZIGBEE_LIGHT_ENDPOINT 10 +//uint8_t led = LED_BUILTIN; +uint8_t led = 6; +uint8_t button = BOOT_PIN; + +#define TEMP_SENSOR_ENDPOINT_NUMBER 11 + +ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/********************* RGB LED functions **************************/ +void setLED(bool value) { + // Serial.println("setLED called"); + digitalWrite(led, value); +} + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + // Read temperature sensor value + // float tsens_value = temperatureRead(); + float tsens_value = random(180, 300) / 10.0; + // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(tsens_value); + + float humidity = random(300, 700) / 10.0; + zbTempSensor.setHumidity(humidity); + + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(1000); + } +} +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature; + + // Simulate temperature between 18.0°C and 30.0°C + float temperature = random(180, 300) / 10.0; + // Simulate humidity between 30.0% and 70.0% + float humidity = random(300, 700) / 10.0; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(100); + + // Put device to deep sleep + // Serial.println("Going to sleep now"); + // esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init LED and turn it OFF (if LED_PIN == RGB_BUILTIN, the rgbLedWrite() will be used under the hood) + pinMode(led, OUTPUT); + digitalWrite(led, LOW); + + // Init button for factory reset + pinMode(button, INPUT_PULLUP); + + //Optional: set Zigbee device name and model + zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); + + // Set callback function for light change + zbLight.onLightChange(setLED); + + //Add endpoint to Zigbee Core + Serial.println("Adding ZigbeeLight endpoint to Zigbee Core"); + Zigbee.addEndpoint(&zbLight); + + + + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // For battery powered devices, it can be better to set timeout for Zigbee Begin to lower value to save battery + // If the timeout has been reached, the network channel mask will be reset and the device will try to connect again after reset (scanning all channels) + Zigbee.setTimeout(10000); // Set timeout for Zigbee Begin to 10s (default is 30s) + + + + + // When all EPs are registered, start Zigbee. By default acts as ZIGBEE_END_DEVICE + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin()) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor.setReporting(0, 10, 0); + + +} + +void loop() { + // 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(); + } + } + // Toggle light by pressing the button + zbLight.setLight(!zbLight.getLightState()); + // Call the function to measure temperature and put the device to sleep + // meausureAndSleep(); + // zbTempSensor.reportTemperature(); + zbTempSensor.report(); + } + delay(100); +} diff --git a/Zigbee_On_Off_Light_fan_control_testv1/ci.json b/Zigbee_On_Off_Light_fan_control_testv1/ci.json new file mode 100644 index 0000000..ceacc36 --- /dev/null +++ b/Zigbee_On_Off_Light_fan_control_testv1/ci.json @@ -0,0 +1,7 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y", + "CONFIG_ZB_ENABLED=y" + ] +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy---old/README.md b/Zigbee_Temp_Hum_Sensor_Sleepy---old/README.md new file mode 100644 index 0000000..d88b01c --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy---old/README.md @@ -0,0 +1,75 @@ +# Arduino-ESP32 Zigbee Temperature and Humidity Sensor Sleepy Device Example + +This example demonstrates how to use the Zigbee library to create an end device temperature/humidity sensor and use it as a Home Automation (HA) extended temperature sensor. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Temperature Sensor Functions + +1. Initialize a Zigbee temperature and humidity sensor. +2. Measure temperature and humidity values. +3. Report the measured values to the Zigbee network. +4. Put the device to sleep to save power. + +## Hardware Required + +* ESP32-H2 or ESP32-C6 development board +* A USB cable for power supply and programming + +### Configure the Project + +In this example, to demonstrate the functionality the chip temperature is used and reported as temperature and humidity. +Set the Button GPIO by changing the `BUTTON_PIN` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy---old/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/Zigbee_Temp_Hum_Sensor_Sleepy---old/Zigbee_Temp_Hum_Sensor_Sleepy.ino new file mode 100644 index 0000000..2454a66 --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy---old/Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -0,0 +1,132 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +#define BUTTON_PIN 9 //Boot button for C6/H2 +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 55 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + + //log_d("Teeeeeest2"); + + // Measure temperature sensor value + float temperature = temperatureRead(); + + // Use temperature value as humidity value to demonstrate both temperature and humidity + //float humidity = temperature; + //float humidity = analogRead(10); // or digitalRead(GPIO_PIN) + float humidity = 50; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.reportTemperature(); + zbTempSensor.reportHumidity(); + + log_d("Temperature: %.2f°C, Humidity: %.2f%", temperature, humidity); + + // Put device to deep sleep + esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + // Init button switch + pinMode(BUTTON_PIN, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensorTest"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + //log_d("Teeeeeest1"); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // When all EPs are registered, start Zigbee in End Device mode + Zigbee.begin(&zigbeeConfig, false); + + // Wait for Zigbee to start + while (!Zigbee.isStarted()) { + delay(100); + } + + // Delay 5s to allow establishing connection with coordinator, needed for sleepy devices + delay(5000); +} + +void loop() { + // Checking button for factory reset + if (digitalRead(BUTTON_PIN) == LOW) { // Push button pressed + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(BUTTON_PIN) == LOW) { + delay(50); + if ((millis() - startTime) > 3000) { + // If key pressed for more than 3secs, factory reset Zigbee and reboot + Zigbee.factoryReset(); + } + } + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy---old/ci.json b/Zigbee_Temp_Hum_Sensor_Sleepy---old/ci.json new file mode 100644 index 0000000..7b7ccef --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy---old/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino b/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino new file mode 100644 index 0000000..bea350c --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy/Zigbee_Temp_Hum_Sensor_Sleepy.ino @@ -0,0 +1,139 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 55 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + // Measure temperature sensor value + float temperature = temperatureRead(); + + // Use temperature value as humidity value to demonstrate both temperature and humidity + float humidity = temperature * 2; + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(100); + + // Put device to deep sleep + Serial.println("Going to sleep now"); + esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensorTest"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 99); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); +} + +void loop() { + // 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(); + } + } + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11/.theia/launch.json b/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11/.theia/launch.json new file mode 100644 index 0000000..fef7b06 --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11/.theia/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + }, + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + } + ] +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11.ino b/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11.ino new file mode 100644 index 0000000..3e97d23 --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11/Zigbee_Temp_Hum_Sensor_Sleepy_DHT11.ino @@ -0,0 +1,164 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +#include "DHT.h" +#define DHTPIN 17 // Digital pin connected to the DHT sensor +//https://github.com/adafruit/DHT-sensor-library/blob/master/examples/DHTtester/DHTtester.ino +#define DHTTYPE DHT11 // DHT 11 +DHT dht(DHTPIN, DHTTYPE); + + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature * 2; + + // Use DHT11 sensor + // Read temperature as Celsius (the default) + float temperature = dht.readTemperature(); + // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) + float humidity = dht.readHumidity(); + //float humidity = 43; + + // Check if any reads failed and exit early (to try again). + if (isnan(humidity) || isnan(temperature)) { + Serial.println(F("Failed to read from DHT sensor!")); + return; + } + + delay(100); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(100); + + // Put device to deep sleep + Serial.println("Going to sleep now"); + //esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor_Node14"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 99); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + dht.begin(); + Serial.println(F("DHTxx test!")); + + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); +} + +void loop() { + // 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(); + } + } + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D/.theia/launch.json b/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D/.theia/launch.json new file mode 100644 index 0000000..fef7b06 --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D/.theia/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + }, + { + "cwd": "${workspaceFolder}", + "executable": "./bin/executable.elf", + "name": "Debug with JLink", + "request": "launch", + "type": "cortex-debug", + "device": "", + "runToEntryPoint": "main", + "showDevDebugOutput": "none", + "servertype": "jlink" + } + ] +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D.ino b/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D.ino new file mode 100644 index 0000000..b9c88a2 --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D/Zigbee_Temp_Hum_Sensor_Sleepy_SHT31D.ino @@ -0,0 +1,198 @@ +//Seeedstudio Xiao ESP32-C6 + + + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + + +#include +#include +#include "Adafruit_SHT31.h" +bool enableHeater = false; +uint8_t loopCnt = 0; +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +// #define LED_PIN LED_BUILTIN +// #define BUTTON_PIN 9 // ESP32-C6/H2 Boot button + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + // Measure temperature sensor value + // float temperature = temperatureRead(); + float temperature = 22; + // Use temperature value as humidity value to demonstrate both temperature and humidity + // float humidity = temperature * 2; + + // float temperature = sht31.readTemperature(); + float humidity = sht31.readHumidity(); + //float humidity = 43; + delay(100); + + // Check if any reads failed and exit early (to try again). + if (! isnan(temperature)) { // check if 'is not a number' + Serial.print("Temp *C = "); Serial.print(temperature); Serial.print("\t\t"); + } else { + Serial.println("Failed to read temperature"); + return; + } + + if (! isnan(humidity)) { // check if 'is not a number' + Serial.print("Hum. % = "); Serial.println(humidity); + } else { + Serial.println("Failed to read humidity"); + return; + } + + delay(100); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + // zbTempSensor.setHumidity(humidity); + delay(100); + + // Report temperature and humidity values + zbTempSensor.report(); + delay(100); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + delay(5000); + + // Put device to deep sleep + Serial.println("Going to sleep now"); + // esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor_Node15"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 99); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + // zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + + + Serial.println("SHT31 test"); + if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr + Serial.println("Couldn't find SHT31"); + while (1) delay(1); + } + Serial.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) + Serial.println("ENABLED"); + else + Serial.println("DISABLED"); + + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); +} + +void loop() { + Serial.print("button state == LOW: "); + Serial.println(digitalRead(button) == LOW); + // 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(); + } + } + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_test2/README.md b/Zigbee_Temp_Hum_Sensor_Sleepy_test2/README.md new file mode 100644 index 0000000..afaa12c --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_test2/README.md @@ -0,0 +1,75 @@ +# Arduino-ESP32 Zigbee Temperature and Humidity Sensor Sleepy Device Example + +This example demonstrates how to use the Zigbee library to create an end device temperature/humidity sensor and use it as a Home Automation (HA) extended temperature sensor. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Temperature Sensor Functions + +1. Initialize a Zigbee temperature and humidity sensor. +2. Measure temperature and humidity values. +3. Report the measured values to the Zigbee network. +4. Put the device to sleep to save power. + +## Hardware Required + +* ESP32-H2 or ESP32-C6 development board +* A USB cable for power supply and programming + +### Configure the Project + +In this example, to demonstrate the functionality the chip temperature is used and reported as temperature and humidity. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_test2/Zigbee_Temp_Hum_Sensor_Sleepy_test2.ino b/Zigbee_Temp_Hum_Sensor_Sleepy_test2/Zigbee_Temp_Hum_Sensor_Sleepy_test2.ino new file mode 100644 index 0000000..ffe7e4d --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_test2/Zigbee_Temp_Hum_Sensor_Sleepy_test2.ino @@ -0,0 +1,195 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device. + * + * The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor. + * The sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include +#include +#include "Adafruit_SHT31.h" +#include "Zigbee.h" + +bool enableHeater = false; +uint8_t loopCnt = 0; +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +/* Zigbee temperature + humidity sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */ + +uint8_t button = BOOT_PIN; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +void meausureAndSleep() { + // Measure temperature sensor value + //float temperature = temperatureRead(); + // Use temperature value as humidity value to demonstrate both temperature and humidity + //float humidity = temperature; + + float temperature = round(sht31.readTemperature() * 10) / 10.0; + float humidity = round(sht31.readHumidity() * 10) / 10.0; + + if (isnan(temperature) || isnan(humidity)) { + Serial.println("ERROR: Failed to read temperature/humidity!"); + return; + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + zbTempSensor.setHumidity(humidity); + + // Report temperature and humidity values + zbTempSensor.report(); + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Add small delay to allow the data to be sent before going to sleep + // delay(1000); + + // Put device to deep sleep + Serial.println("Going to sleep now"); + delay(1000 * TIME_TO_SLEEP); + //esp_deep_sleep_start(); +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + + // Configure the wake up source and set to wake up every 5 seconds + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + + // Set Zigbee rejoin behavior + // Zigbee.setRejoinMode(ZIGBEE_REJOIN_WITHOUT_DISCOVERY); // Try rejoining without rediscovering the network + // Zigbee.enableRejoin(true); // Allow automatic rejoining if disconnected + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensorTest_Nodexy"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 5000; + + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("ERROR: Zigbee failed to start! Rebooting..."); + delay(1000); + ESP.restart(); + } + + Serial.println("Connecting to Zigbee network..."); + unsigned long startTime = millis(); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + if (millis() - startTime > 10000) { // 10s timeout + Serial.println("\nERROR: Failed to connect to Zigbee! Rebooting..."); + delay(1000); + ESP.restart(); + } + } + Serial.println(); + Serial.println("Successfully connected to Zigbee network"); + + + + Serial.println("SHT31 test"); + if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr + Serial.println("Couldn't find SHT31"); + while (1) delay(1); + } else { + Serial.println("SHT31 sensor initialized successfully"); + Serial.print("Temp *C = "); Serial.print(sht31.readTemperature()); Serial.print("\t\t"); + Serial.print("Hum. % = "); Serial.println(sht31.readHumidity()); + } + Serial.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) + Serial.println("ENABLED"); + else + Serial.println("DISABLED"); + + + // Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices + delay(1000); +} + +void loop() { + // 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(); + } + } + } + + // Ensure the Zigbee network is connected before reporting + if (!Zigbee.connected()) { + Serial.println("Lost connection to Zigbee network. Attempting to rejoin..."); + //if (!Zigbee.rejoinNetwork()) { + // Serial.println("Rejoin failed! Restarting device..."); + // ESP.restart(); + //} + ESP.restart(); + Serial.println("Successfully rejoined Zigbee network."); + } + + // Call the function to measure temperature and put the device to sleep + meausureAndSleep(); + //delay(100); +} diff --git a/Zigbee_Temp_Hum_Sensor_Sleepy_test2/ci.json b/Zigbee_Temp_Hum_Sensor_Sleepy_test2/ci.json new file mode 100644 index 0000000..7b7ccef --- /dev/null +++ b/Zigbee_Temp_Hum_Sensor_Sleepy_test2/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/Zigbee_Temperature_Sensor__test/README.md b/Zigbee_Temperature_Sensor__test/README.md new file mode 100644 index 0000000..577bd7c --- /dev/null +++ b/Zigbee_Temperature_Sensor__test/README.md @@ -0,0 +1,79 @@ +# Arduino-ESP32 Zigbee Temperature Sensor Example + +This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) temperature sensor. + +# Supported Targets + +Currently, this example supports the following targets. + +| Supported Targets | ESP32-C6 | ESP32-H2 | +| ----------------- | -------- | -------- | + +## Temperature Sensor Functions + +Note: + * This board means the board (e.g. ESP32-H2 / C6) loaded with `Zigbee_Temperature_Sensor` example. + * The remote board means the board (e.g. ESP32-H2 / C6) loaded with `Zigbee_Thermostat` example. + +Functions: + * After this board first starts up, it would be configured locally to report the temperature on 1 degree change and no periodic reporting to the remote board. + * By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured temperature to the remote board. + +## Hardware Required + +* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with `Zigbee_Thermostat` example) +* A USB cable for power supply and programming +* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the `Zigbee_Temperature_Sensor` example + +### Configure the Project + +In this example, the internal temperature sensor task is reading the chip temperature. +Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)` +* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs` +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. +* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`. + +## Troubleshooting + +If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator. +You can do the following: + +* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`. +* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack. + +By default, the coordinator network is closed after rebooting or flashing new firmware. +To open the network you have 2 options: + +* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`. +* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join. + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf) +* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/Zigbee_Temperature_Sensor__test/Zigbee_Temperature_Sensor__test.ino b/Zigbee_Temperature_Sensor__test/Zigbee_Temperature_Sensor__test.ino new file mode 100644 index 0000000..d372ca7 --- /dev/null +++ b/Zigbee_Temperature_Sensor__test/Zigbee_Temperature_Sensor__test.ino @@ -0,0 +1,223 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee temperature sensor. + * + * The example demonstrates how to use Zigbee library to create a end device temperature sensor. + * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include +#include +#include "Adafruit_SHT31.h" +#include "Zigbee.h" + +bool enableHeater = false; +uint8_t loopCnt = 0; +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +/* Zigbee temperature sensor configuration */ +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; + +#define LED_PIN LED_BUILTIN // Onboard LED pin (change if needed) +#define REPORT_INTERVAL 1 // Report interval in seconds + +// Optional Time cluster variables +struct tm timeinfo; +struct tm *localTime; +int32_t timezone; + +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + +/************************ Temp sensor *****************************/ +static void temp_sensor_value_update(void *arg) { + for (;;) { + // Read temperature sensor value + //float tsens_value = temperatureRead(); + //int randomNumber = random(10, 50); // Generates a random number between 10 and 49 + //Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + + //float temperature = sht31.readTemperature(); + //float humidity = sht31.readHumidity(); + float temperature = round(sht31.readTemperature() * 10) / 10.0; + float humidity = round(sht31.readHumidity() * 1) / 1.0; + + // Check if any reads failed and exit early (to try again). + if (! isnan(temperature)) { // check if 'is not a number' + Serial.print("Temp *C = "); Serial.print(temperature); Serial.print("\t\t"); + } else { + Serial.println("Failed to read temperature"); + return; + } + + if (! isnan(humidity)) { // check if 'is not a number' + Serial.print("Hum. % = "); Serial.println(humidity); + } else { + Serial.println("Failed to read humidity"); + return; + } + + // Update temperature value in Temperature sensor EP + zbTempSensor.setTemperature(temperature); + //zbTempSensor.setHumidity(humidity); + delay(100); + //zbTempSensor.reportTemperature(); + + // Double-flash LED + for (int i = 0; i < 2; i++) { + digitalWrite(LED_PIN, LOW); + delay(100); // LED ON + digitalWrite(LED_PIN, HIGH); + delay(100); // LED OFF + } + + // delay(10000); + vTaskDelay(pdMS_TO_TICKS(REPORT_INTERVAL * 1000)); // Delay without blocking + + } +} + +/********************* Arduino functions **************************/ +void setup() { + Serial.begin(115200); + + // Init button switch + pinMode(button, INPUT_PULLUP); + pinMode(LED_PIN, OUTPUT); + + // Optional: set Zigbee device name and model + zbTempSensor.setManufacturerAndModel("Espressif", "ZigbeeTempSensor"); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + + // Set power source to battery and set battery percentage to measured value (now 100% for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime + zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 99); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + // Optional: Time cluster configuration (default params, as this device will revieve time from coordinator) + zbTempSensor.addTimeCluster(); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + if (!Zigbee.begin(&zigbeeConfig, false)) { + // 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(); + + // Optional: If time cluster is added, time can be read from the coordinator + timeinfo = zbTempSensor.getTime(); + timezone = zbTempSensor.getTimezone(); + + Serial.println("UTC time:"); + Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); + + time_t local = mktime(&timeinfo) + timezone; + localTime = localtime(&local); + + Serial.println("Local time with timezone:"); + Serial.println(localTime, "%A, %B %d %Y %H:%M:%S"); + + + Serial.println("SHT31 test"); + if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr + Serial.println("Couldn't find SHT31"); + while (1) delay(1); + } else { + Serial.println("SHT31 sensor initialized successfully"); + Serial.print("Temp *C = "); Serial.print(sht31.readTemperature()); Serial.print("\t\t"); + Serial.print("Hum. % = "); Serial.println(sht31.readHumidity()); + } + Serial.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) + Serial.println("ENABLED"); + else + Serial.println("DISABLED"); + + delay(100); + + + // Start Temperature sensor reading task + xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + zbTempSensor.setReporting(1, 0, 1); + //zbTempSensor.setReporting(0, 10, 0); + //zbTempSensor.setReporting(0, 0, 0); + + +} + +void loop() { + // 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(); + } + } + //zbTempSensor.reportTemperature(); + //zbTempSensor.report(); + } + //zbTempSensor.report(); + delay(100); +} diff --git a/Zigbee_Temperature_Sensor__test/ci.json b/Zigbee_Temperature_Sensor__test/ci.json new file mode 100644 index 0000000..7b7ccef --- /dev/null +++ b/Zigbee_Temperature_Sensor__test/ci.json @@ -0,0 +1,6 @@ +{ + "fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed", + "requires": [ + "CONFIG_SOC_IEEE802154_SUPPORTED=y" + ] +} diff --git a/Zigbee_gas_sensor_test1/Zigbee_gas_sensor_test1.ino b/Zigbee_gas_sensor_test1/Zigbee_gas_sensor_test1.ino new file mode 100644 index 0000000..b5652e1 --- /dev/null +++ b/Zigbee_gas_sensor_test1/Zigbee_gas_sensor_test1.ino @@ -0,0 +1,95 @@ +// Zigbee_TVOCSensor.ino +// ESP32-C6 with ESP-ZB Zigbee stack: reports Humidity and TVOC (Air Quality) +// Works with Zigbee2MQTT using standard clusters + +#include +#include "esp_adc/adc_oneshot.h" +#include "esp_zigbee_core.h" +#include "esp_zigbee_zcl.h" + +#define HUMIDITY_ENDPOINT 1 +#define TVOC_ENDPOINT 2 +#define TVOC_ADC_CHANNEL ADC_CHANNEL_6 // GPIO34 (ADC1_CH6) + +// Humidity attribute value (fixed dummy) +static uint16_t humidity_value = 5500; // 55.00% (ZCL expects 0.01% units) + +// TVOC attribute value (calculated from ADC) +static uint16_t tvoc_value = 0; // In ppb or raw ADC units + +// === HUMIDITY SENSOR CLUSTER === +ZB_ZCL_DECLARE_ATTRIB_LIST(humidity_sensor_attr_list, + ZB_ZCL_SET_ATTRIBUTE(HUMIDITY_VALUE_ID, ZB_ZCL_ATTR_TYPE_U16, ZB_ZCL_ATTR_ACCESS_READ_ONLY | ZB_ZCL_ATTR_ACCESS_REPORTING, &humidity_value) +); + +ESP_ZB_DECLARE_HA_SENSOR_EP(humidity_ep, HUMIDITY_ENDPOINT, + ESP_ZB_AF_HA_PROFILE_ID, + ESP_ZB_HA_HUMIDITY_SENSOR_DEVICE_ID, + humidity_sensor_attr_list +); + +// === TVOC SENSOR USING AIR QUALITY CLUSTER === +ZB_ZCL_DECLARE_ATTRIB_LIST(tvoc_sensor_attr_list, + ZB_ZCL_SET_ATTRIBUTE(ZB_ZCL_ATTR_AIR_QUALITY_MEASUREMENT_MEASURED_VALUE_ID, ZB_ZCL_ATTR_TYPE_U16, ZB_ZCL_ATTR_ACCESS_READ_ONLY | ZB_ZCL_ATTR_ACCESS_REPORTING, &tvoc_value) +); + +ESP_ZB_DECLARE_SENSOR_EP(tvoc_ep, TVOC_ENDPOINT, + ESP_ZB_AF_HA_PROFILE_ID, + ESP_ZB_HA_SENSOR_DEVICE_ID, + tvoc_sensor_attr_list, + ZB_ZCL_CLUSTER_ID_AIR_QUALITY_MEASUREMENT +); + +// ADC handle +adc_oneshot_unit_handle_t adc_handle; + +void init_adc() { + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = ADC_UNIT_1, + }; + adc_oneshot_new_unit(&init_config, &adc_handle); + + adc_oneshot_chan_cfg_t config = { + .atten = ADC_ATTEN_DB_11, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + adc_oneshot_config_channel(adc_handle, TVOC_ADC_CHANNEL, &config); +} + +uint16_t read_tvoc() { + int raw = 0; + adc_oneshot_read(adc_handle, TVOC_ADC_CHANNEL, &raw); + float voltage = raw / 4095.0 * 3.3; + return static_cast(voltage * 100); // Example conversion to ppb +} + +void update_sensor_data() { + tvoc_value = read_tvoc(); + humidity_value = 5500; // Simulated value (replace with real sensor if needed) + + esp_zb_zcl_report_attr(HUMIDITY_ENDPOINT, ZB_ZCL_CLUSTER_ID_REL_HUMIDITY_MEASUREMENT, + ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_MEASURED_VALUE_ID); + + esp_zb_zcl_report_attr(TVOC_ENDPOINT, ZB_ZCL_CLUSTER_ID_AIR_QUALITY_MEASUREMENT, + ZB_ZCL_ATTR_AIR_QUALITY_MEASUREMENT_MEASURED_VALUE_ID); +} + +void setup() { + Serial.begin(115200); + init_adc(); + + esp_zb_init(); + esp_zb_add_endpoint(&humidity_ep); + esp_zb_add_endpoint(&tvoc_ep); + esp_zb_start(true); +} + +void loop() { + static unsigned long last = 0; + unsigned long now = millis(); + if (now - last > 5000) { + update_sensor_data(); + last = now; + } + esp_zb_main_loop_iteration(); +} diff --git a/Zigbee_gas_sensor_test1/config.h b/Zigbee_gas_sensor_test1/config.h new file mode 100644 index 0000000..2695844 --- /dev/null +++ b/Zigbee_gas_sensor_test1/config.h @@ -0,0 +1,20 @@ +#ifndef CONFIG_H +#define CONFIG_H + +// --- Zigbee Configuration --- +#define ZIGBEE_CHANNEL 11 // Your Zigbee channel +#define ZIGBEE_PAN_ID 0x1234 // Your Zigbee PAN ID +#define ZIGBEE_EXTENDED_PAN_ID {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11} // Your Zigbee Extended PAN ID + +// --- Gas Sensor Configuration --- +#define GAS_SENSOR_PIN 4 // The ADC pin connected to the gas sensor +#define RL_VALUE 10000.0 // Load resistance in ohms (e.g., 10k ohm) +#define VCC 3.3 // ESP32 ADC reference voltage (likely 3.3V) +#define HEATER_PIN -1 // Optional heater pin +#define WARM_UP_TIME 60000 // Warm-up time in milliseconds (e.g., 60 seconds) + +// --- ADC Calibration --- +#define DEFAULT_VREF 1100 // Use adc2_vref_to_gpio() to obtain a better estimate +#define NO_OF_SAMPLES 64 // Multisampling + +#endif \ No newline at end of file diff --git a/Zigbee_gas_sensor_test1/gas_sensor.cpp b/Zigbee_gas_sensor_test1/gas_sensor.cpp new file mode 100644 index 0000000..c537538 --- /dev/null +++ b/Zigbee_gas_sensor_test1/gas_sensor.cpp @@ -0,0 +1,88 @@ +#include "gas_sensor.h" +#include // Include Zigbee library here + +GasSensor::GasSensor(uint8_t endpoint) : ZBEndpoint(endpoint), endpoint_(endpoint) {} // Call ZBEndpoint constructor + +void GasSensor::begin() { + Serial.println("Initializing Gas Sensor..."); + + // Optional: set Zigbee device name and model + setManufacturerAndModel("YourManufacturer", "GasSensor_Model_1"); + + initializeADC(); + + // Optional: Configure heater pin + if (HEATER_PIN != -1) { + pinMode(HEATER_PIN, OUTPUT); + digitalWrite(HEATER_PIN, HIGH); // Turn on heater + } + + // Wait for gas sensor to warm up + Serial.print("Warming up gas sensor for "); + Serial.print(WARM_UP_TIME / 1000); + Serial.println(" seconds..."); + delay(WARM_UP_TIME); + initialized_ = true; + Serial.println("Gas sensor warmed up and ready."); +} + +void GasSensor::initializeADC() { + //Characterize ADC at particular attenuations + esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_DEFAULT, DEFAULT_VREF, &adc_chars_); + + //Configure ADC + adc1_config_width(ADC_WIDTH_BIT_DEFAULT); + adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11); // GPIO4 corresponds to ADC1 channel 4 +} + +float GasSensor::readSensorValue() { + // Read the analog value from the gas sensor + uint32_t adc_reading = 0; + //Multisampling + for (int i = 0; i < NO_OF_SAMPLES; i++) { + adc_reading += adc1_get_raw((adc1_channel_t)ADC1_CHANNEL_4); + } + adc_reading /= NO_OF_SAMPLES; + + //Convert adc_reading to voltage in mV + uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, &adc_chars_); + Serial.print("Raw ADC Value: "); + Serial.println(adc_reading); + Serial.print("Converted Voltage: "); + Serial.print(voltage); + Serial.println(" mV"); + // Calculate the voltage at the ADC pin + float voltage_float = (float)voltage / 1000.0; // Convert mV to volts + return voltage_float; +} + +float GasSensor::calculateSensorResistance(float voltage) { + // Calculate the gas sensor resistance (Rs) using the voltage divider formula: + // Vout = VCC * (RL / (RL + Rs)) + // Rs = RL * ((VCC / Vout) - 1) + float rs = RL_VALUE * ((VCC / voltage) - 1); + return rs; +} + +void GasSensor::publishSensorValue(float value) { + // Send the gas sensor value as a Zigbee attribute report + if (!initialized_ || (millis() - lastReportTime_ < REPORT_INTERVAL)) { + return; // Don't report if not initialized or too soon + } + + uint16_t gasValueInt = (uint16_t)(value * 100); // Scale gas value to an integer (e.g., * 100 for two decimal places) + + // Construct the Zigbee attribute report payload + uint8_t payload[5]; + payload[0] = 0x01; // Data type: Unsigned 16-bit integer + payload[1] = (gasValueInt >> 0) & 0xFF; // Least significant byte + payload[2] = (gasValueInt >> 8) & 0xFF; // Most significant byte + payload[3] = 0x00; + payload[4] = 0x00; + + // Send the Zigbee attribute report + Zigbee.sendAttributeReport(endpoint_, GAS_SENSOR_CLUSTER, GAS_SENSOR_ATTRIBUTE, ZB_ZCL_DATA_TYPE_UINT16, payload, sizeof(payload)); + + Serial.println("Gas sensor value sent to Zigbee."); + lastReportTime_ = millis(); +} \ No newline at end of file diff --git a/Zigbee_gas_sensor_test1/gas_sensor.h b/Zigbee_gas_sensor_test1/gas_sensor.h new file mode 100644 index 0000000..bc88727 --- /dev/null +++ b/Zigbee_gas_sensor_test1/gas_sensor.h @@ -0,0 +1,32 @@ +#ifndef GAS_SENSOR_H +#define GAS_SENSOR_H + +#include +#include // Include Zigbee library here +#include +#include "config.h" // Include the configuration file + +class GasSensor : public ZBEndpoint { // Inherit from ZBEndpoint +public: + GasSensor(uint8_t endpoint); // Constructor + void begin(); + float readSensorValue(); + float calculateSensorResistance(float voltage); + void publishSensorValue(float value); + uint8_t getEndpoint() const { return endpoint_; } + +private: + uint8_t endpoint_; // Zigbee Endpoint for this sensor + bool initialized_ = false; // Flag to indicate initialization + unsigned long lastReportTime_ = 0; + esp_adc_cal_characteristics_t adc_chars_; // ADC calibration data + + void initializeADC(); + + // --- Configuration --- + static const uint16_t GAS_SENSOR_CLUSTER = 0xAAAA; // Unique cluster ID for gas sensor + static const uint16_t GAS_SENSOR_ATTRIBUTE = 0x0001; // Unique attribute ID for gas sensor + static const unsigned long REPORT_INTERVAL = 30000; // Report interval in milliseconds +}; + +#endif \ No newline at end of file diff --git a/bme68x_test/bme68x_test.ino b/bme68x_test/bme68x_test.ino new file mode 100644 index 0000000..809193e --- /dev/null +++ b/bme68x_test/bme68x_test.ino @@ -0,0 +1,70 @@ +#include "Arduino.h" +#include "bme68xLibrary.h" +//#include "bsec2.h" + + +Bme68x bme; +//Bsec2 bsec; + + +void setup(void) +{ + Serial.println("Startin setup."); + Wire.begin(14, 8); // SDA, SCL + Wire.setClock(100000); // Set I2C clock speed to 100kHz + Serial.begin(115200); + + while (!Serial) + delay(10); + + /* initializes the sensor based on Wire library */ + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + // Set the temperature profile + //const uint8_t numSteps = 5; + //const uint16_t temperatures[] = {200, 250, 300, 350, 400}; // temperatures in degrees Celsius + //const uint16_t durations[] = {100, 200, 300, 400, 500}; // durations in milliseconds + //bme.setHeaterProfile(numSteps, temperatures, durations); + + + Serial.println("TimeStamp(ms), Temperature(deg C), Pressure(Pa), Humidity(%), Gas resistance(ohm), Status"); +} + +void loop(void) +{ + bme68xData data; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) + { + bme.getData(data); + Serial.print(String(millis()) + ", "); + Serial.print(String(data.temperature) + ", "); + Serial.print(String(data.pressure) + ", "); + Serial.print(String(data.humidity) + ", "); + Serial.print(String(data.gas_resistance) + ", "); + Serial.println(data.status, HEX); + delay(1000); + } +} diff --git a/c4001_esp32c6_test/c4001_esp32c6_test.ino b/c4001_esp32c6_test/c4001_esp32c6_test.ino new file mode 100644 index 0000000..d73d5f6 --- /dev/null +++ b/c4001_esp32c6_test/c4001_esp32c6_test.ino @@ -0,0 +1,176 @@ +/*! + * @file mRangeVelocity.ino + * @brief radar measurement demo + * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) + * @license The MIT License (MIT) + * @author ZhixinLiu(zhixin.liu@dfrobot.com) + * @version V1.0 + * @date 2024-02-02 + * @url https://github.com/dfrobot/DFRobot_C4001 + */ + +#include "DFRobot_C4001.h" + +//#define I2C_COMMUNICATION //use I2C for communication, but use the serial port for communication if the line of codes were masked + +#ifdef I2C_COMMUNICATION +/* + * DEVICE_ADDR_0 = 0x2A default iic_address + * DEVICE_ADDR_1 = 0x2B + */ +DFRobot_C4001_I2C radar(&Wire, DEVICE_ADDR_0); +#else +/* --------------------------------------------------------------------------------------------------------------------- + * board | MCU | Leonardo/Mega2560/M0 | UNO | ESP8266 | ESP32 | microbit | m0 | + * VCC | 3.3V/5V | VCC | VCC | VCC | VCC | X | vcc | + * GND | GND | GND | GND | GND | GND | X | gnd | + * RX | TX | Serial1 TX1 | 5 | 5/D6 | D2 | X | tx1 | + * TX | RX | Serial1 RX1 | 4 | 4/D7 | D3 | X | rx1 | + * ----------------------------------------------------------------------------------------------------------------------*/ +/* Baud rate cannot be changed */ +#if defined(ARDUINO_AVR_UNO) || defined(ESP8266) +SoftwareSerial mySerial(4, 5); +DFRobot_C4001_UART radar(&mySerial, 9600); +#elif defined(ESP32) +DFRobot_C4001_UART radar(&Serial1, 9600, /*rx*/ 17, /*tx*/ 16); +#else +DFRobot_C4001_UART radar(&Serial1, 9600); +#endif +#endif + + + + + + +// Current sensor mode +// eExitMode (0x00) = presence detection +// eSpeedMode (0x01) = speed & range measurement +// DFRobot_C4001::eMode_t currentMode = DFRobot_C4001::eExitMode; +DFRobot_C4001::eMode_t currentMode = DFRobot_C4001::eExitMode; // <- Fixed line + + +void setModePresence() { + radar.setSensorMode(DFRobot_C4001::eExitMode); // presence mode + currentMode = DFRobot_C4001::eExitMode; + Serial.println("Switched to PRESENCE mode"); +} + +void setModeSpeed() { + radar.setSensorMode(DFRobot_C4001::eSpeedMode); // speed mode + currentMode = DFRobot_C4001::eSpeedMode; + Serial.println("Switched to SPEED mode"); +} + + +void handleSerialCommands() { + // Read commands from USB serial monitor + while (Serial.available() > 0) { + char c = Serial.read(); + if (c == 'P' || c == 'p') { + setModePresence(); + } else if (c == 'S' || c == 's') { + setModeSpeed(); + } + } +} + + + + +void setup() { + Serial.begin(115200); + while (!Serial) + ; + while (!radar.begin()) { + Serial.println("NO Deivces !"); + delay(1000); + } + Serial.println("Device connected!"); + + // speed Mode + // radar.setSensorMode(eSpeedMode); + + // Default: presence mode + // setModePresence(); + setModeSpeed(); + Serial.println("Send 'P' for presence mode, 'S' for speed mode."); + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); +} + +void loop() { + handleSerialCommands(); + + // Read radar data when available + if (radar.available()) { + DFRobot_C4001::sSensorStatus_t status = radar.getStatus(); + + if (currentMode == DFRobot_C4001::eExitMode) { + // Presence mode: simple presence / motion state + bool motion = radar.motionDetection(); + uint8_t exist = radar.getStatus().workStatus; // or radar.getStatus().workStatus / exist depending on your lib version + + Serial.print("Mode: PRESENCE, "); + Serial.print("Motion: "); + Serial.print(motion ? "YES" : "NO"); + Serial.print(" WorkStatus: "); + Serial.println(status.workStatus); + + } else if (currentMode == DFRobot_C4001::eSpeedMode) { + // Speed mode: target number, speed, range, energy + uint8_t num = radar.getTargetNumber(); + float speed = radar.getTargetSpeed(); + float range = radar.getTargetRange(); + uint32_t energy = radar.getTargetEnergy(); + + Serial.print("Mode: SPEED, Targets: "); + Serial.print(num); + Serial.print(" Speed(m/s): "); + Serial.print(speed, 2); + Serial.print(" Range(m): "); + Serial.print(range, 2); + Serial.print(" Energy: "); + Serial.println(energy); + } + } + + // Small delay to avoid spamming the serial port + delay(100); +} diff --git a/epaper_v1/epaper_v1.ino b/epaper_v1/epaper_v1.ino new file mode 100644 index 0000000..0986469 --- /dev/null +++ b/epaper_v1/epaper_v1.ino @@ -0,0 +1,148 @@ +// Waveshare 1.54” ePaper display (GDEH0154D67) +// https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B) + + +#include +#include +#include +#include +#include +#include + +// === Pin Definitions === +#define EPD_CS 17 // Chip Select +#define EPD_DC 16 // Data/Command +#define EPD_RST 23 // Reset +#define EPD_BUSY 22 // Busy + +// SPI pins (custom mapping if needed) +#define EPD_MOSI 18 // SPI MOSI (DIN) +#define EPD_SCK 19 // SPI Clock (CLK) + +// Optional: define MISO if your board or library needs it (not used by display) +#define EPD_MISO -1 // ePaper doesn't use MISO + + +// === GxEPD2 Display object (1.54" 200x200) === +// GxEPD2_BW display(GxEPD2_154_D67( +// EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); +// 3-color 1.54" e-paper class (200x200 resolution) +// GxEPD2_3C display(GxEPD2_154c(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); +GxEPD2_3C display( + GxEPD2_154c(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)); + + + +// Optional: replace with RTC if available (e.g. DS3231 via RTClib) +unsigned long lastUpdate = 0; +unsigned long refreshInterval = 30000; // 30 seconds +int counter = 0; + +// Timekeeping +unsigned long bootMillis; +int hours = 12, minutes = 0, seconds = 0; + +// Helper: format two digits +String formatDigits(int digits) { + if (digits < 10) return "0" + String(digits); + return String(digits); +} + + +// ====== 🔧 Wait for BUSY Pin Helper ====== +void waitWhileBusy(const char* label) { + Serial.print("🕒 Waiting for BUSY ("); + Serial.print(label); + Serial.println(")..."); + uint32_t start = millis(); + while (digitalRead(EPD_BUSY)) { + if (millis() - start > 10000) { + Serial.println("⛔ BUSY Timeout!"); + break; + } + delay(10); + } + Serial.println("✅ BUSY cleared."); +} + +// Setup the screen with initial static content +void drawInitialScreen() { + Serial.println("🖥️ Drawing initial screen..."); + display.setFullWindow(); + Serial.println("debug 0"); + display.firstPage(); + do { + Serial.println("debug 1"); + display.fillScreen(GxEPD_WHITE); + Serial.println("debug 2"); + display.setFont(&FreeMonoBold12pt7b); + Serial.println("debug 3"); + display.setTextColor(GxEPD_BLACK); + Serial.println("debug 4"); + display.setCursor(30, 60); + display.print("Counter:"); + } while (display.nextPage()); + Serial.println("✅ Initial screen drawn."); +} + +// Draw the counter value with partial refresh +void drawCounter() { + Serial.print("🔢 Updating counter to: "); + Serial.println(counter); + + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%d", counter); + + // Define the area to refresh + display.setPartialWindow(30, 80, 140, 40); + display.firstPage(); + do { + display.fillRect(30, 80, 140, 40, GxEPD_WHITE); // Clear previous text + display.setCursor(30, 110); + display.setTextColor(GxEPD_RED); // Use red for the counter + display.print(buffer); + } while (display.nextPage()); + + Serial.println("✅ Counter updated."); +} + +void setup() { + Serial.begin(115200); + delay(100); + delay(2000); + Serial.println("🚀 Starting ePaper test..."); + + + pinMode(EPD_BUSY, INPUT); + pinMode(EPD_RST, OUTPUT); + pinMode(EPD_DC, OUTPUT); + pinMode(EPD_CS, OUTPUT); + + + // Initialize SPI with custom pins BEFORE display.init() + SPI.begin(EPD_SCK, EPD_MISO, EPD_MOSI, EPD_CS); // SCK, MISO, MOSI, SS + + + Serial.println("🔌 Initializing display..."); + display.init(115200); // optional: set SPI frequency + display.setRotation(1); + display.setFont(&FreeMonoBold12pt7b); + // display.setTextColor(GxEPD_BLACK); + + Serial.println("🖼️ Display initialized"); + waitWhileBusy("post-init"); + + drawInitialScreen(); + // drawTime(); // first time display + drawCounter(); + lastUpdate = millis(); + +} + +void loop() { + if (millis() - lastUpdate >= refreshInterval) { + counter++; + drawCounter(); + lastUpdate = millis(); + } +} diff --git a/may24a_water_level/may24a_water_level.ino b/may24a_water_level/may24a_water_level.ino new file mode 100644 index 0000000..a994d47 --- /dev/null +++ b/may24a_water_level/may24a_water_level.ino @@ -0,0 +1,87 @@ +#include + +#define SERIAL Serial + +// === CONFIGURE HERE === +#define SDA_PIN 19 // I2C SDA pin +#define SCL_PIN 17 // I2C SCL pin +#define SOIL_SENSOR_PIN A0 // Analog pin for soil sensor + +#define WATER_THRESHOLD 100 +#define ATTINY1_HIGH_ADDR 0x78 // High 12 sections +#define ATTINY2_LOW_ADDR 0x77 // Low 8 sections + +// Soil sensor calibration values (adjust for your soil type) +#define SOIL_WET 1500 // Raw value when soil is wet +#define SOIL_DRY 4095 // Raw value when soil is dry + +// Buffers for I2C sensor data +uint8_t low_data[8] = {0}; +uint8_t high_data[12] = {0}; + +void setup() { + SERIAL.begin(115200); + delay(100); + Wire.begin(SDA_PIN, SCL_PIN); + delay(100); +} + +// Read capacitive soil sensor and map to 0–100% +int getSoilMoisturePercent() { + int raw = analogRead(SOIL_SENSOR_PIN); + int percent = map(raw, SOIL_DRY, SOIL_WET, 0, 100); + percent = constrain(percent, 0, 100); + return percent; +} + +// Read a block of data over I2C +void getSectionData(uint8_t addr, uint8_t* buffer, size_t length) { + Wire.requestFrom(addr, (uint8_t)length); + size_t i = 0; + while (Wire.available() && i < length) { + buffer[i++] = Wire.read(); + } + delay(5); +} + +// Compute water level from sensor data +int getWaterLevelPercent() { + getSectionData(ATTINY2_LOW_ADDR, low_data, 8); + getSectionData(ATTINY1_HIGH_ADDR, high_data, 12); + + uint32_t touch_val = 0; + uint8_t level = 0; + + for (int i = 0; i < 8; i++) { + if (low_data[i] > WATER_THRESHOLD) + touch_val |= 1 << i; + } + + for (int i = 0; i < 12; i++) { + if (high_data[i] > WATER_THRESHOLD) + touch_val |= (uint32_t)1 << (8 + i); + } + + while (touch_val & 0x01) { + level++; + touch_val >>= 1; + } + + return level * 5; // 20 levels × 5 = 100% +} + +void loop() { + int soilPercent = getSoilMoisturePercent(); + int waterLevelPercent = getWaterLevelPercent(); + + SERIAL.print("Soil Moisture: "); + SERIAL.print(soilPercent); + SERIAL.println("%"); + + SERIAL.print("Water Level: "); + SERIAL.print(waterLevelPercent); + SERIAL.println("%"); + + SERIAL.println("----------------------------"); + delay(2000); +} diff --git a/mr60bha2_mmwave_OTA_firmware_upgrade/mr60bha2_mmwave_OTA_firmware_upgrade.ino b/mr60bha2_mmwave_OTA_firmware_upgrade/mr60bha2_mmwave_OTA_firmware_upgrade.ino new file mode 100644 index 0000000..3d568b0 --- /dev/null +++ b/mr60bha2_mmwave_OTA_firmware_upgrade/mr60bha2_mmwave_OTA_firmware_upgrade.ino @@ -0,0 +1,37 @@ +#include +#include "Seeed_Arduino_mmWave.h" + +// If the board is an ESP32, include the HardwareSerial library and create a +// HardwareSerial object for the mmWave serial communication +#ifdef ESP32 +# include +HardwareSerial mmWaveSerial(0); +#else +// Otherwise, define mmWaveSerial as Serial1 +# define mmWaveSerial Serial1 +#endif + +void setup() { + // Initialize the serial communication for debugging + Serial.begin(115200); + while (!Serial) { + ; // Wait for Serial to initialize + } + + // Initialize the mmWaveSerial communication + mmWaveSerial.begin(115200); +} + +void loop() { + // Check if there is data available from mmWaveSerial + while (mmWaveSerial.available() > 0) { + char receivedChar = mmWaveSerial.read(); + Serial.write(receivedChar); // Forward data to Serial + } + + // Check if there is data available from Serial + while (Serial.available() > 0) { + char receivedChar = Serial.read(); + mmWaveSerial.write(receivedChar); // Forward data to mmWaveSerial + } +} \ No newline at end of file diff --git a/simple_fan_control_v1/simple_fan_control_v1.ino b/simple_fan_control_v1/simple_fan_control_v1.ino new file mode 100644 index 0000000..aec553d --- /dev/null +++ b/simple_fan_control_v1/simple_fan_control_v1.ino @@ -0,0 +1,30 @@ +#define FAN_PIN 6 // GPIO4 controls the 2N7000 (fan switch) +#define LED_PIN 15 // Onboard LED on Beetle ESP32-C6 + +void setup() { + Serial.begin(115200); + delay(1000); // Give time for serial monitor to open + + pinMode(FAN_PIN, OUTPUT); + pinMode(LED_PIN, OUTPUT); + + // Ensure both fan and LED are off at startup + digitalWrite(FAN_PIN, LOW); + digitalWrite(LED_PIN, LOW); + + Serial.println("System initialized. Starting toggle test every 5 seconds."); +} + +void loop() { + // Turn fan and LED ON + digitalWrite(FAN_PIN, HIGH); + digitalWrite(LED_PIN, HIGH); + Serial.println("Fan ON, LED ON"); + delay(5000); + + // Turn fan and LED OFF + digitalWrite(FAN_PIN, LOW); + digitalWrite(LED_PIN, LOW); + Serial.println("Fan OFF, LED OFF"); + delay(5000); +} diff --git a/simple_fan_control_v2/simple_fan_control_v2.ino b/simple_fan_control_v2/simple_fan_control_v2.ino new file mode 100644 index 0000000..5310701 --- /dev/null +++ b/simple_fan_control_v2/simple_fan_control_v2.ino @@ -0,0 +1,54 @@ +#define FAN_PIN 6 // GPIO4 to control fan via MOSFET +#define LED_PIN 15 // Onboard LED +#define PWM_RESOLUTION 12 // 12-bit (0–4095) +#define PWM_FREQ 5000 // 5 kHz +#define DUTY_MIN 0 +#define DUTY_MAX 4095 +#define FADE_TIME 3000 // Time to fade in/out (ms) + +bool fade_in = true; +bool fade_ended = false; + +void ARDUINO_ISR_ATTR FAN_FADE_ISR() { + fade_ended = true; +} + +void setup() { + Serial.begin(115200); + delay(1000); + + pinMode(LED_PIN, OUTPUT); + + // Attach PWM to fan pin using Seeed's extended API + ledcAttach(FAN_PIN, PWM_FREQ, PWM_RESOLUTION); + + // Start fade in + ledcFade(FAN_PIN, DUTY_MIN, DUTY_MAX, FADE_TIME); + digitalWrite(LED_PIN, HIGH); + Serial.println("Fan Fade in started."); + + delay(FADE_TIME); + + // Fade out with interrupt to continue loop + ledcFadeWithInterrupt(FAN_PIN, DUTY_MAX, DUTY_MIN, FADE_TIME, FAN_FADE_ISR); + digitalWrite(LED_PIN, LOW); + Serial.println("Fan Fade out started."); +} + +void loop() { + if (fade_ended) { + fade_ended = false; + + if (fade_in) { + ledcFadeWithInterrupt(FAN_PIN, DUTY_MIN, DUTY_MAX, FADE_TIME, FAN_FADE_ISR); + digitalWrite(LED_PIN, HIGH); + Serial.println("Fan Fade in started."); + fade_in = false; + } else { + ledcFadeWithInterrupt(FAN_PIN, DUTY_MAX, DUTY_MIN, FADE_TIME, FAN_FADE_ISR); + digitalWrite(LED_PIN, LOW); + Serial.println("Fan Fade out started."); + fade_in = true; + } + } +} diff --git a/simple_fan_control_v3/simple_fan_control_v3.ino b/simple_fan_control_v3/simple_fan_control_v3.ino new file mode 100644 index 0000000..73ba420 --- /dev/null +++ b/simple_fan_control_v3/simple_fan_control_v3.ino @@ -0,0 +1,63 @@ +#include +#include +#include + +#define FAN_PIN 4 + +// Handler with correct signature +void on_off_cluster_handler(zb_bufid_t bufid) { + zb_zcl_parsed_hdr_t *cmd_info = ZB_BUF_GET_PARAM(bufid, zb_zcl_parsed_hdr_t); + + if (cmd_info->cmd_id == ZB_ZCL_CMD_ON_OFF_ON) { + digitalWrite(FAN_PIN, HIGH); + Serial.println("Zigbee: FAN ON"); + } else if (cmd_info->cmd_id == ZB_ZCL_CMD_ON_OFF_OFF) { + digitalWrite(FAN_PIN, LOW); + Serial.println("Zigbee: FAN OFF"); + } else if (cmd_info->cmd_id == ZB_ZCL_CMD_ON_OFF_TOGGLE) { + digitalWrite(FAN_PIN, !digitalRead(FAN_PIN)); + Serial.println("Zigbee: FAN TOGGLE"); + } + + zb_buf_free(bufid); +} + +void setup() { + Serial.begin(115200); + pinMode(FAN_PIN, OUTPUT); + digitalWrite(FAN_PIN, LOW); + + Serial.println("Zigbee Fan Device starting..."); + + esp_zb_cfg_t zb_config = ESP_ZB_DEFAULT_CONFIG(); + esp_zb_init(&zb_config); + + // Setup On/Off cluster (example) + esp_zb_on_off_cluster_cfg_t on_off_cfg = ESP_ZB_DEFAULT_ON_OFF_CLUSTER_CONFIG(); + esp_zb_cluster_list_t *cluster_list = esp_zb_on_off_cluster_create(&on_off_cfg); + + esp_zb_endpoint_config_t ep_cfg = { + .endpoint = 10, + .profile_id = ZB_AF_HA_PROFILE_ID, + .device_id = ZB_HA_ON_OFF_SWITCH_DEVICE_ID, + .device_version = 1, + .input_clusters = cluster_list, + .input_cluster_count = 1, + .output_clusters = nullptr, + .output_cluster_count = 0, + }; + + esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create(); + esp_zb_ep_list_add_ep(ep_list, &ep_cfg); + esp_zb_device_register(ep_list); + + // Register the command callback + esp_zb_zcl_on_off_cmd_handler_register(on_off_cluster_handler); + + // Start Zigbee stack + esp_zb_start(true); +} + +void loop() { + // Zigbee runs in background RTOS task +} diff --git a/sketch_dec6a/sketch_dec6a.ino b/sketch_dec6a/sketch_dec6a.ino new file mode 100644 index 0000000..fb49e8c --- /dev/null +++ b/sketch_dec6a/sketch_dec6a.ino @@ -0,0 +1,133 @@ +/* + * ESP32-C6 Zigbee Router with DHT11 Sensor + * + * Logic: + * 1. Initialize as a Zigbee Router (ZR). + * 2. Create an endpoint with Temperature and Humidity clusters. + * 3. Read DHT11 sensor periodically. + * 4. Update and report values to the Zigbee network. + * + * Libraries required: + * - EspZigbee (Standard with ESP32 Board package v3.0.0+) + * - DHT sensor library by Adafruit (Install via Library Manager) + */ + +#include "Zigbee.h" +#include "DHT.h" + +// --- Hardware Config --- +#define DHTPIN 17 // Pin connected to DHT11 Data +#define DHTTYPE DHT11 // Sensor type +#define DHTPOWER 4 // GPIO pin to power the sensor + +// --- Zigbee Config --- +// Identify the endpoint (arbitrary number, 1-240) +#define SENSOR_ENDPOINT_NUM 10 + +// --- Global Objects --- +DHT dht(DHTPIN, DHTTYPE); + +// Define the Zigbee Temperature Sensor object +// Note: Depending on the specific library version, this helper class +// might primarily handle Temperature. We will configure it to report. +ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(SENSOR_ENDPOINT_NUM); + +// Timer for reporting +unsigned long lastReportTime = 0; +const unsigned long REPORT_INTERVAL = 10000; // Report every 10 seconds + +void setup() { + Serial.begin(115200); + + pinMode(DHTPOWER, OUTPUT); + digitalWrite(DHTPOWER, HIGH); // Power on the sensor + + // Initialize DHT Sensor + dht.begin(); + Serial.println("DHT11 Sensor Initialized"); + + // --- Zigbee Setup --- + + // 1. Set Manufacturer and Model details (visible in Home Assistant/Zigbee2MQTT) + zbTempSensor.setManufacturerAndModel("Espressif", "ESP32C6-Router-Temp"); + + // 2. Add the Temperature and Humidity clusters to the endpoint + // The default ZigbeeTempSensor includes the Temperature Measurement cluster. + // We explicitly try to set the sensor config. + // Note: If you need a dedicated Humidity cluster separate from this helper, + // you might need to use the generic EspZigbee::ZigbeeEP helper, but + // most modern helpers support adding standard clusters. + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor.setMinMaxValue(10, 50); + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor.setTolerance(0.1); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor.addHumiditySensor(0, 100, 1); + + + + + // 3. Add Endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor); + + // 4. Initialize Zigbee as a ROUTER + // ZIGBEE_ROUTER: Mains-powered, always on, routes packets for other devices. + // Serial.println("Starting Zigbee as Router..."); + // if (!Zigbee.begin(ZIGBEE_ROUTER)) { + // Serial.println("Zigbee failed to start! Restarting..."); + // delay(1000); + // ESP.restart(); + // } + // Serial.println("Zigbee Started. Waiting for network..."); + + // Zigbee.factoryReset(); + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in Router mode + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + 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("Connected"); + +} + +void loop() { + // Check if enough time has passed to report data + if (millis() - lastReportTime > REPORT_INTERVAL) { + lastReportTime = millis(); + + // 1. Read Sensor + float temp = dht.readTemperature(); + float hum = dht.readHumidity(); + + // Check if read failed + if (isnan(temp) || isnan(hum)) { + Serial.println("Failed to read from DHT sensor!"); + return; + } + + Serial.printf("Temp: %.1f C, Humidity: %.1f %%\n", temp, hum); + + // 2. Update Zigbee Clusters + // The ZigbeeTempSensor class updates the local attribute + zbTempSensor.setTemperature(temp); + + // Note: If your specific version of ZigbeeTempSensor does not support setHumidity, + // you may need to add a separate Humidity endpoint or use raw attribute setting. + // However, recent ESP32-Arduino versions often bundle these. + zbTempSensor.setHumidity(hum); // Uncomment if supported by your version + + // 3. Report Values + // This triggers a report attribute command to the coordinator + zbTempSensor.report(); + } +} diff --git a/sketch_dec6b/.theia/launch.json b/sketch_dec6b/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/sketch_dec6b/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/sketch_dec6b/sketch_dec6b.ino b/sketch_dec6b/sketch_dec6b.ino new file mode 100644 index 0000000..77ebe22 --- /dev/null +++ b/sketch_dec6b/sketch_dec6b.ino @@ -0,0 +1,864 @@ +// Xiao ESP32-C6 + +// uploading new script +// Zigbee connection establishment --> ....... +// force remove deivce from Z2M with permit join OFF +// swich permit JOIN ON +// restart ESP32 +// leave permit jion on until configuration finished + + + + + +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates Zigbee occupancy sensor. + * + * The example demonstrates how to use Zigbee library to create a end device occupancy sensor. + * The occupancy sensor is a Zigbee end device, which is reporting data to the Zigbee network. + * Tested with PIR sensor HC-SR501 connected to GPIO4. + * + * Proper Zigbee mode must be selected in Tools->Zigbee mode + * and also the correct partition scheme must be selected in Tools->Partition Scheme. + * + * Please check the README.md for instructions and more detailed description. + * + * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/) + */ + +// #ifndef ZIGBEE_MODE_ED +// #error "Zigbee end device mode is not selected in Tools->Zigbee mode" +// #endif + +#define DEBUG_TRACE + +#include "Zigbee.h" +// #include + +// #define SENSOR_RX 17 // ESP32 RX connected to sensor TX +// #define SENSOR_TX 16 // ESP32 TX connected to sensor RX +// HardwareSerial mmWaveSerial(1); // UART2 + + + +/* Zigbee occupancy sensor configuration */ +// #define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 +uint8_t button = BOOT_PIN; +// uint8_t sensor_pin = 23; // connected to GPIO2 of the sensor; HIGH in case of presence detection + +// Fade LED PIN (replace with LED_BUILTIN constant for the built-in LED) +// #define LED_PIN D5 +const int ledPin = LED_BUILTIN; + +// ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + + +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 18 +#define SDA_PIN 20 + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 10 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +// #define TEMP_SENSOR_ENDPOINT_NUMBER_2 12 +// ZigbeeTempSensor zbTempSensor2 = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER_2); + +// #define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 13 +// ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 11 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + +/* BME280 sensor */ +//BME280I2C sensor; +Bme68x bme; + + +int errorCount = 0; // Initialize an error counter +const int maxErrors = 5; // Maximum number of allowed errors before restart + + +/************************ Temp sensor *****************************/ +static void bme680_sensor_value_update(void *arg) { + for (;;) { + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + uint8_t percentage; + + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + + errorCount++; + Serial.println("Failed to read data from BME680!"); + if (errorCount >= maxErrors) { + Serial.println("Too many errors! Restarting..."); + ESP.restart(); // Restart the ESP32 after too many errors + } + } + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_BME68X.setTemperature(temperature); + zbTempSensor_BME68X.setHumidity(humidity); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + zbAnalogDevice_BME68X.setAnalogInput(round(gasResistance / 1000.0)); + // zbAnalogDevice_BME68X.reportAnalogInput(); + + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + Serial.printf("BME680: Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + + + +// #include +#include "Adafruit_SHT4x.h" +#include "Adafruit_SGP40.h" + +// --- Hardware Config --- +// #define I2C_SDA_PIN 6 // Default C6 SDA (Adjust if using a specific board like Seeed Xiao) +// #define I2C_SCL_PIN 7 // Default C6 SCL +// If using standard DevKit, you can often just use Wire.begin() without pins + +// --- Objects --- +Adafruit_SHT4x sht4; +Adafruit_SGP40 sgp; + +// Define a Zigbee Endpoint for Environmental Data +#define ENDPOINT_ENV 12 +// ZigbeeTempSensor zbEnvSensor_sgp40_sht40(ENDPOINT_ENV); +ZigbeeTempSensor zbEnvSensor_sgp40_sht40 = ZigbeeTempSensor(ENDPOINT_ENV); + + +#define SGP_ANALOG_DEVICE_ENDPOINT_NUMBER 13 +ZigbeeAnalog zbAnalogDevice_sgp40_sht40 = ZigbeeAnalog(SGP_ANALOG_DEVICE_ENDPOINT_NUMBER); + + + +static void sgp40_sht40_sensor_value_update(void *arg) { + for (;;) { + + float currentTemp(NAN), currentHum(NAN); + uint16_t currentRaw(NAN); + int32_t currentVOC(NAN); + // uint8_t percentage; + + // Prepare the BME680 for measurement + // bme68xData data; + // int8_t rslt; + + // bme.setOpMode(BME68X_FORCED_MODE); + // delayMicroseconds(bme.getMeasDur()); + + // if (bme.fetchData()) { + // bme.getData(data); + // temperature = data.temperature; // Temperature in °C + // humidity = data.humidity; // Humidity in % + // pressure = data.pressure; // Pressure in hPa + // gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + // } else { + // //Serial.println("Failed to read data from BME680!"); + // //return; // Exit if reading failed + + // errorCount++; + // Serial.println("Failed to read data from BME680!"); + // if (errorCount >= maxErrors) { + // Serial.println("Too many errors! Restarting..."); + // ESP.restart(); // Restart the ESP32 after too many errors + // } + // } + Serial.println("Starting readout of SHT40"); + + // --- 1. Read SHT40 (Temp/Hum) --- + sensors_event_t humidity, temp; + sht4.getEvent(&humidity, &temp); // Populate temp and humidity objects + + currentTemp = temp.temperature; + currentHum = humidity.relative_humidity; + + Serial.print("Temperature: "); Serial.print(currentTemp); Serial.println(" degrees C"); + Serial.print("Humidity: "); Serial.print(currentHum); Serial.println("% rH"); + + + Serial.println("Starting readout of SGP40"); + // --- 2. Read SGP40 (VOC) --- + // SGP40 requires precise Temp/Hum for accurate compensation. + // We pass the raw SHT40 values directly to the SGP40 algorithm. + currentRaw = sgp.measureRaw(currentTemp, currentHum); + currentVOC = sgp.measureVocIndex(currentTemp, currentHum); + + Serial.print("Raw measurement: "); + Serial.println(currentRaw); + Serial.print("Voc Index: "); + Serial.println(currentVOC); + + + // // Temp: Cluster 0x0402, Attribute 0x0000 (MeasuredValue), Type INT16, Value = Temp * 100 + // int16_t zigbeeTemp = (int16_t)(currentTemp * 100); + // zbEnvSensor_sgp40_sht40.reportAttribute(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT, + // ESP_ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID, + // ESP_ZB_ZCL_ATTR_TYPE_S16, + // &zigbeeTemp); + + // // Humidity: Cluster 0x0405, Attribute 0x0000 (MeasuredValue), Type UINT16, Value = Hum * 100 + // uint16_t zigbeeHum = (uint16_t)(currentHum * 100); + // zbEnvSensor_sgp40_sht40.reportAttribute(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY, + // ESP_ZB_ZCL_ATTR_REL_HUMIDITY_MEASUREMENT_VALUE_ID, + // ESP_ZB_ZCL_ATTR_TYPE_U16, + // &zigbeeHum); + + // // VOC (Analog Input): Cluster 0x000C, Attribute 0x0055 (PresentValue), Type SINGLE (Float) + // // Using Analog Input Present Value for VOC + // float zigbeeVOC = (float)currentVOC; + // zbEnvSensor_sgp40_sht40.reportAttribute(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, + // ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, + // ESP_ZB_ZCL_ATTR_TYPE_SINGLE, + // &zigbeeVOC); + + // Serial.printf("T: %.2f C | H: %.2f %% | VOC Index: %d\n", zigbeeTemp, zigbeeHum, zigbeeVOC); + + Serial.println("finished readout of SGP40"); + + // // Update temperature and humidity values in Temperature sensor EP + zbEnvSensor_sgp40_sht40.setTemperature(currentTemp); + zbEnvSensor_sgp40_sht40.setHumidity(currentHum); + + // // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); // Assuming you have a method for gas resistance + zbAnalogDevice_sgp40_sht40.setAnalogInput(round(currentRaw / 1000.0)); + // // zbAnalogDevice_BME68X.reportAnalogInput(); + + Serial.println("finished setting values"); + + // Report values + // zbTempSensor.report(); + // zbTempSensor.reportBatteryPercentage(); + + // zbCarbonDioxideSensor.setCarbonDioxide(gasResistance); + // zbCarbonDioxideSensor.report(); + + #ifdef DEBUG_TRACE + //Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", currentTemp, currentHum, currentVOC); + // Serial.printf("SGP/SHT: T: %.2f C | H: %.2f %% | Raw SGP: %d | VOC Index: %d\n", currentTemp, currentHum, currentRaw, currentVOC); + + #endif + + + + + // // Read temperature sensor value + // // float tsens_value = temperatureRead(); + // float tsens_value = random(180, 300) / 10.0; + // // Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value); + // // Update temperature value in Temperature sensor EP + // zbTempSensor.setTemperature(tsens_value); + // zbTempSensor2.setTemperature(tsens_value); + + // float humidity = random(300, 700) / 10.0; + // zbTempSensor.setHumidity(humidity); + // zbTempSensor2.setHumidity(humidity); + + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", tsens_value, humidity); + + delay(10000); + } +} + + + + + + + + + +// Internal Led flash +void flashLED() { + // Turn on LED for 100ms + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); +} + + + + + + +// #define ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT 9 +// uint8_t illuminance_sensor_pin = 1; // Insert the analog pin to which the sensor (e.g. photoresistor) is connected + +// ZigbeeIlluminanceSensor zbIlluminanceSensor = ZigbeeIlluminanceSensor(ZIGBEE_ILLUMINANCE_SENSOR_ENDPOINT); + +// /********************* Illuminance sensor **************************/ +// static void illuminance_sensor_value_update(void *arg) { +// for (;;) { +// // read the raw analog value from the sensor +// int lsens_analog_raw = analogRead(illuminance_sensor_pin); +// Serial.printf("[Illuminance Sensor] raw analog value: %d\r\n", lsens_analog_raw); + +// // conversion into zigbee raw illuminance value (typically between 0 in darkness and 50000 in direct sunlight) +// // depends on the value range of the raw analog sensor values and will need calibration for correct lux values +// // for demonstration purpose map the 12-bit ADC value (0-4095) to Zigbee illuminance range (0-50000) +// int lsens_illuminance_raw = map(lsens_analog_raw, 0, 4095, 0, 50000); +// Serial.printf("[Illuminance Sensor] raw illuminance value: %d\r\n", lsens_illuminance_raw); + +// // according to zigbee documentation the formular 10^(lsens_illuminance_raw/10000)-1 can be used to calculate lux value from raw illuminance value +// // Note: Zigbee2MQTT seems to be using the formular 10^(lsens_illuminance_raw/10000) instead (without -1) +// int lsens_illuminance_lux = round(pow(10, (lsens_illuminance_raw / 10000.0)) - 1); +// Serial.printf("[Illuminance Sensor] lux value: %d lux\r\n", lsens_illuminance_lux); + +// // Update illuminance in illuminance sensor EP +// zbIlluminanceSensor.setIlluminance(lsens_illuminance_raw); // use raw illuminance here! + +// delay(10000); // reduce delay (in ms), if you want your device to react more quickly to changes in illuminance +// } +// } + + + + + + +// // 1. Define the task function (Global scope, outside setup/loop) +// void pirTask(void * parameter) { +// // Move the static variable here. It doesn't need to be 'static' anymore +// // because this function only runs once and stays in the loop below. +// bool occupancy = false; + +// // 2. Infinite Loop: Tasks must never return! +// for(;;) { +// // --- Your Original Logic Start --- +// if (digitalRead(sensor_pin) == HIGH && !occupancy) { +// zbOccupancySensor.setOccupancy(true); +// zbOccupancySensor.report(); +// occupancy = true; +// analogWrite(ledPin, 0); +// Serial.println("GPIO2 HIGH"); +// } else if (digitalRead(sensor_pin) == LOW && occupancy) { +// zbOccupancySensor.setOccupancy(false); +// zbOccupancySensor.report(); +// occupancy = false; +// analogWrite(ledPin, 255); +// Serial.println("GPIO2 LOW"); +// } +// // --- Your Original Logic End --- + +// // 3. CRITICAL: Delay to yield control +// // Polling a PIR every 50ms is plenty fast and saves CPU. +// vTaskDelay(50 / portTICK_PERIOD_MS); +// } +// } + + +// const char* commands[] = { +// "getRange", +// "getSensitivity", +// "getLatency", +// "getUart", +// "getGpioMode 2", +// "getLedMode 1", +// "getEcho", +// "getUartOutput 1", +// "getUartOutput 2", +// // "sensorStop", +// // "sensorStart", +// // "saveConfig", +// // "resetCfg", +// // "resetSystem", +// "getHWV", +// "getSWV", +// "getOutput" +// }; + +// const int numCommands = sizeof(commands) / sizeof(commands[0]); + +// String line = ""; + + +// bool sendCommandAndWaitForDone(String command, Stream &sensorSerial, unsigned long timeout = 1000) { +// // Send the command +// sensorSerial.println(command); +// Serial.print("Sending: "); +// Serial.println(command); + +// // Wait for "Done" response +// unsigned long startTime = millis(); +// String response; + +// while (millis() - startTime < timeout) { +// while (sensorSerial.available()) { +// char c = sensorSerial.read(); +// Serial.write(c); // Print response to Serial Monitor +// response += c; + +// // If "Done" is found in the response, return success +// if (response.indexOf("Done") >= 0) { +// Serial.println("✓ Done received."); +// return true; +// } + +// // Optional: detect "Error" for debugging +// if (response.indexOf("Error") >= 0) { +// Serial.println("✗ Error received."); +// return false; +// } +// } +// } + +// Serial.println("✗ Timeout waiting for Done."); +// return false; +// } + +// void turnOnSensor(int sensitivity) { +// Serial.println("=== Turning On Sensor ==="); + +// sendCommandAndWaitForDone("sensorStop", mmWaveSerial); +// sendCommandAndWaitForDone("resetCfg", mmWaveSerial); // Optional + +// // sendCommandAndWaitForDone("setUartOutput 1 0", mmWaveSerial); // Disable $JYBSS +// // sendCommandAndWaitForDone("setUartOutput 2 1", mmWaveSerial); // Enable $JYRPO +// sendCommandAndWaitForDone("setUartOutput 1 1", mmWaveSerial); // Enable $JYBSS +// sendCommandAndWaitForDone("setUartOutput 2 0", mmWaveSerial); // Disable $JYRPO + +// sendCommandAndWaitForDone("setSensitivity " + String(sensitivity), mmWaveSerial); +// sendCommandAndWaitForDone("setRange 0 3", mmWaveSerial); +// sendCommandAndWaitForDone("setLatency 0.025 0.5", mmWaveSerial); + +// sendCommandAndWaitForDone("setEcho 1", mmWaveSerial); // Enable echo — sensor prints back commands and shows leapMMW:/> prompt (default). +// sendCommandAndWaitForDone("setLedMode 1 1", mmWaveSerial); // LED off +// sendCommandAndWaitForDone("setGpioMode 2 1", mmWaveSerial); // GPIO2 high when presence + +// sendCommandAndWaitForDone("saveConfig", mmWaveSerial); +// sendCommandAndWaitForDone("sensorStart", mmWaveSerial); +// } + + + + + + + + + +void setup() { +#ifdef DEBUG_TRACE + Serial.begin(115200); + // mmWaveSerial.begin(115200, SERIAL_8N1, SENSOR_RX, SENSOR_TX); + // delay(100); // Give sensor time to boot + + Serial.println(); + Serial.println("Tutoduino Zigbee temperature sensor start!"); +#endif + + + // turnOnSensor(5); // initialization of mmwave sensor + + // for (int i = 0; i < numCommands; i++) { + // const char* cmd = commands[i]; + // sendCommandAndWaitForDone(cmd, mmWaveSerial); + // delay(10); // small delay before next command (optional) + // } + + + + // Optional: configure analog input + analogSetAttenuation(ADC_11db); // set analog to digital converter (ADC) attenuation to 11 dB (up to ~3.3V input) + analogReadResolution(12); // set analog read resolution to 12 bits (value range from 0 to 4095), 12 is default + + + + // // Init button + PIR sensor + // pinMode(button, INPUT_PULLUP); + // pinMode(sensor_pin, INPUT_PULLUP); + // pinMode(ledPin, OUTPUT); + + // analogWrite(ledPin, 255); // pin, dutyCycle + + // // Optional: set Zigbee device name and model + // zbOccupancySensor.setManufacturerAndModel("Espressif", "Node11_bme680_sht40_sgp40"); + + // // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + // zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_MAINS); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + + + + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + + + + // Optional: set Zigbee device name and model + zbTempSensor_BME68X.setManufacturerAndModel("Espressif", "Node11_bme680_sht40_sgp40"); + + // Optional: Set power source (choose between ZB_POWER_SOURCE_MAINS and ZB_POWER_SOURCE_BATTERY), defaults to unknown + zbTempSensor_BME68X.setPowerSource(ZB_POWER_SOURCE_MAINS); + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_BME68X.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_BME68X.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + + + + // // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + // zbTempSensor2.setMinMaxValue(10, 50); + + // // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + // zbTempSensor2.setTolerance(1); + + // // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // // Add humidity cluster to the temperature sensor device with min, max and tolerance values + // zbTempSensor2.addHumiditySensor(0, 100, 1); + + // // Add endpoint to Zigbee Core + // Zigbee.addEndpoint(&zbTempSensor2); + + + + + + + // // Set minimum and maximum carbon dioxide measurement value in ppm + // zbCarbonDioxideSensor.setMinMaxValue(0, 150000000); + // // Add endpoints to Zigbee Core + // Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + // // Set minimum and maximum for raw illuminance value (0 min and 50000 max equals to 0 lux - 100,000 lux) + // zbIlluminanceSensor.setMinMaxValue(0, 50000); + + // // Optional: Set tolerance for raw illuminance value + // zbIlluminanceSensor.setTolerance(1); + + // // Add endpoint to Zigbee Core + // Serial.println("Adding Zigbee illuminance sensor endpoint to Zigbee Core"); + // Zigbee.addEndpoint(&zbIlluminanceSensor); + + + + + + + Serial.println("Initializing SHT40..."); + if (!sht4.begin(&Wire)) { + Serial.println("SHT40 not found! Check wiring."); + while (1) delay(10); + } + sht4.setPrecision(SHT4X_HIGH_PRECISION); + sht4.setHeater(SHT4X_NO_HEATER); + + Serial.println("Initializing SGP40..."); + if (!sgp.begin(&Wire)) { + Serial.println("SGP40 not found! Check wiring."); + while (1) delay(10); + } + + // --- 2. Configure Zigbee Endpoint --- + + // Set Manufacturer/Model + // zbEnvSensor.setManufacturerAndModel("Espressif", "ESP32C6-Env-Sensor"); + + // // A. Add Temperature Cluster (Standard) + // zbEnvSensor_sgp40_sht40.addCluster(ESP_ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT); + + // // B. Add Humidity Cluster + // // We manually add this cluster to the endpoint + // zbEnvSensor_sgp40_sht40.addCluster(ESP_ZB_ZCL_CLUSTER_ID_REL_HUMIDITY); + + // // C. Add Analog Input Cluster (for VOC Index) + // // We use Analog Input (0x000C) as a generic container for the VOC value (0-500) + // zbEnvSensor_sgp40_sht40.addCluster(ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT); + + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbEnvSensor_sgp40_sht40.setMinMaxValue(0, 50); + + // Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbEnvSensor_sgp40_sht40.setTolerance(1); + + // Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration) + // The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin() + // zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbEnvSensor_sgp40_sht40.addHumiditySensor(0, 100, 1); + + // Register the endpoint + Zigbee.addEndpoint(&zbEnvSensor_sgp40_sht40); + + + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_sgp40_sht40.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_sgp40_sht40); + + + + + + + + + // Create a default Zigbee configuration for End Device + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); +#ifdef DEBUG_TRACE + Serial.println("Starting Zigbee"); +#endif + // When all EPs are registered, start Zigbee in End Device mode + // if (!Zigbee.begin(&zigbeeConfig, false)) { + if (!Zigbee.begin(ZIGBEE_ROUTER)) { +#ifdef DEBUG_TRACE + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting ESP32!"); +#endif + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } +#ifdef DEBUG_TRACE + Serial.println("Connecting to network"); +#endif + while (!Zigbee.connected()) { +#ifdef DEBUG_TRACE + Serial.print("."); +#endif + delay(100); + } +#ifdef DEBUG_TRACE + Serial.println("Successfully connected to Zigbee network"); +#endif + + + + + + + + // // 4. Create the task + // xTaskCreate( + // pirTask, // Function to call + // "PIR_Check", // Name for debugging + // 4096, // Stack size (bytes) - Zigbee operations need space! + // NULL, // Parameter to pass + // 1, // Priority (1 is standard, higher numbers = higher priority) + // NULL // Task handle + // ); + + + + // Start Temperature sensor reading task + xTaskCreate(bme680_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (temp change in 0,1 °C) + // if min = 1 and max = 0, reporting is sent only when temperature changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change + // zbTempSensor.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(0, 15, 1); + // zbTempSensor2.setReporting(0, 15, 0); + + + // zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbAnalogDevice_BME68X.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + + // Start illuminance sensor reading task + // xTaskCreate(illuminance_sensor_value_update, "illuminance_sensor_update", 2048, NULL, 10, NULL); + + // Set reporting schedule for illuminance value measurement in seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta + // if min = 1 and max = 0, delta = 1000, reporting is sent when raw illuminance value changes by 1000, but at most once per second + // if min = 0 and max = 10, delta = 1000, reporting is sent every 10 seconds or if raw illuminance value changes by 1000 + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of illuminance change + // Note: On pairing with Zigbee Home Automation or Zigbee2MQTT the reporting schedule will most likely be overwritten with their default settings + // zbIlluminanceSensor.setReporting(1, 0, 1); + + + + xTaskCreate(sgp40_sht40_sensor_value_update, "sgp40_sht40_sensor_value_update", 2048, NULL, 10, NULL); + zbEnvSensor_sgp40_sht40.setReporting(0, 15, 1); + + zbAnalogDevice_sgp40_sht40.setAnalogInputReporting(0, 15, 10); // report every 30 seconds if value changes by 10 + + + +} + +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; + // analogWrite(ledPin, 0); + // Serial.println("GPIO2 HIGH"); + // } else if (digitalRead(sensor_pin) == LOW && occupancy) { + // zbOccupancySensor.setOccupancy(false); + // zbOccupancySensor.report(); + // occupancy = false; + // analogWrite(ledPin, 255); + // Serial.println("GPIO2 LOW"); + // } + + // 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(); + } + } + // force report of illuminance when button is pressed + // zbIlluminanceSensor.report(); + zbTempSensor_BME68X.report(); + // zbCarbonDioxideSensor.report(); + zbAnalogDevice_BME68X.reportAnalogInput(); + // zbEnvSensor_sgp40_sht40.report(); + + } + delay(100); +} diff --git a/sketch_nov29b/sketch_nov29b.ino b/sketch_nov29b/sketch_nov29b.ino new file mode 100644 index 0000000..371018d --- /dev/null +++ b/sketch_nov29b/sketch_nov29b.ino @@ -0,0 +1,206 @@ +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/1000, /*trig*/1000)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(1)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(2)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/10, /*keep*/4)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + + + + + + + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + + + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + +void setup() { + Serial.begin(115200); + while (!Serial); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); +} + +void loop() { + handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + if (currentMode == eExitMode) { + // PRESENCE MODE + if (radar.motionDetection()) { + Serial.println("MOTION DETECTED"); + } + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + delay(100); +} diff --git a/sketch_nov29c/.theia/launch.json b/sketch_nov29c/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/sketch_nov29c/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/sketch_nov29c/sketch_nov29c.ino b/sketch_nov29c/sketch_nov29c.ino new file mode 100644 index 0000000..aa76793 --- /dev/null +++ b/sketch_nov29c/sketch_nov29c.ino @@ -0,0 +1,304 @@ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + + +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds - adjust as needed +const unsigned long TRIGGER_DELAY = 10 // 10 -> 100 ms + + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/1000, /*trig*/1000)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(1)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(2)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/TRIGGER_DELAY, /*keep*/OCCUPANCY_TIMEOUT)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + + + + + + + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + + + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + +void setup() { + Serial.begin(115200); + while (!Serial); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + + + + + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + 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!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + +} + +void loop() { + handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + + if (currentMode == eExitMode) { + // PRESENCE MODE + // static bool occupancy = false; + // bool occupancyNow = radar.motionDetection(); + // Serial.println(occupancyNow); + // // if (radar.motionDetection() == 1 && !occupancy) { + // if (occupancyNow != lastOccupancy) { + // Serial.println("MOTION DETECTED"); + // zbOccupancySensor.setOccupancy(occupancyNow); + // zbOccupancySensor.report(); + // // occupancy = true; + // lastOccupancy = occupancyNow; + // // } else if (radar.motionDetection() == 0 && occupancy) { + // // } else if (radar.motionDetection() == 0) { + // // Serial.println("MOTION ENDED"); + // // zbOccupancySensor.setOccupancy(false); + // // zbOccupancySensor.report(); + // // occupancy = false; + // } + // PRESENCE MODE - proper state machine + bool motionNow = radar.motionDetection(); + Serial.println(motionNow); + Serial.println(lastOccupancy); + Serial.println(millis() - occupancyStartTime); + + if (motionNow && !lastOccupancy) { + // Motion STARTED → Set occupancy ON + Serial.println("MOTION DETECTED → OCCUPANCY ON"); + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + + } else if (motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + Serial.println("Motion still present → timeout reset"); + occupancyStartTime = millis(); + + } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // TIMEOUT → Clear occupancy + Serial.println("OCCUPANCY TIMEOUT → OFF"); + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + + } else if (!motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + Serial.println("Motion ended → timeout started"); + // occupancyStartTime = millis(); + } + + + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + delay(100); +} diff --git a/sketch_nov29d/sketch_nov29d.ino b/sketch_nov29d/sketch_nov29d.ino new file mode 100644 index 0000000..965eb6d --- /dev/null +++ b/sketch_nov29d/sketch_nov29d.ino @@ -0,0 +1,575 @@ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds - adjust as needed +const unsigned long TRIGGER_DELAY = 10; // 10 -> 100 ms + + + + + + + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +#include +// DFRobot_SCD4X SCD4X(&Wire, /*i2cAddr = */SCD4X_I2C_ADDR); + +// Define your custom SCL/SDA pins +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin +// Create custom I2C instance +TwoWire sharedI2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) +// SCD41 with custom I2C +DFRobot_SCD4X SCD4X(&sharedI2C, SCD4X_I2C_ADDR); + + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 12 +ZigbeeTempSensor zbTempSensor_SCD4X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + + + + + + + + +// #include +// Bme68x bme; +// TwoWire BME68X_I2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) +// #include // BME680 library +// DFRobot_BME680_I2C bme680(0x76); // 0x76 +#include +#include "Adafruit_BME680.h" +Adafruit_BME680 bme680; + +unsigned long bme_report_time = millis(); + +#define TEMP_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 14 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + + + + + + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/1000, /*trig*/1000)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(1)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(2)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/TRIGGER_DELAY, /*keep*/OCCUPANCY_TIMEOUT)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + + + + + + + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + + + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + +void setup() { + Serial.begin(115200); + while (!Serial); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + + + + // Initialize custom I2C with YOUR pins + // SCD41_I2C.begin(SCD41_SDA_PIN, SCD41_SCL_PIN, 100000); // 100kHz standard + // Initialize SHARED I2C bus ONCE + sharedI2C.begin(I2C_SDA_PIN, I2C_SCL_PIN, 100000); + + while( !SCD4X.begin() ){ + Serial.println("Communication with device failed, please check connection"); + delay(3000); + } + Serial.println("SCD4x: Begin ok!"); + SCD4X.enablePeriodMeasure(SCD4X_STOP_PERIODIC_MEASURE); + + SCD4X.setTempComp(4.0); + float temp = 0; + temp = SCD4X.getTempComp(); + Serial.print("The current temperature compensation value : "); + Serial.print(temp); + Serial.println(" C"); + + SCD4X.setSensorAltitude(540); + uint16_t altitude = 0; + altitude = SCD4X.getSensorAltitude(); + Serial.print("Set the current environment altitude : "); + Serial.print(altitude); + Serial.println(" m"); + + SCD4X.enablePeriodMeasure(SCD4X_START_PERIODIC_MEASURE); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_SCD4X.setMinMaxValue(10, 50); + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_SCD4X.setTolerance(1); + // Optional: Time cluster configuration (default params, as this device will revieve time from coordinator) + // zbTempSensor.addTimeCluster(); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_SCD4X.addHumiditySensor(0, 100, 1); + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_SCD4X); + + + + + + // // Init BME680 + // if (bme680.begin(sharedI2C) != 0) { + // Serial.println("BME680 init failed!"); + // } else { + // Serial.println("BME680 ready!"); + // } + // Wire.begin(SCD41_SDA_PIN, SCD41_SCL_PIN); + // Wire.setClock(100000); // Set I2C clock speed to 100kHz + // // Initialize the BME680 + // bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme.begin(BME68X_I2C_ADDR_HIGH, &BME68X_I2C); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme680.begin() + // // Set up the BME680 + // // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // // bme.setOversampling(T2, OS_2X); + // // bme.setOversampling(T1, OS_16X); + // // bme.setOversampling(H1, OS_2X); + // // bme.setFilter(FILTER_SIZE_3); + // // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + // if(bme.checkStatus()) + // { + // if (bme.checkStatus() == BME68X_ERROR) + // { + // Serial.println("Sensor error:" + bme.statusString()); + // return; + // } + // else if (bme.checkStatus() == BME68X_WARNING) + // { + // Serial.println("Sensor Warning:" + bme.statusString()); + // } + // } + // /* Set the default configuration for temperature, pressure and humidity */ + // bme.setTPH(); + // /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + // bme.setHeaterProf(300, 100); + + // bme68xData data; + // bme.setOpMode(BME68X_FORCED_MODE); + + + Serial.println("Connecting to BME680..."); + + // Note the syntax: .begin(Address, TwoWirePointer) + if (!bme680.begin(0x77, &sharedI2C)) { + Serial.println("BME680 not found at 0x77, trying 0x76..."); + if (!bme680.begin(0x76, &sharedI2C)) { + Serial.println("BME680 Init Failed! Check wiring."); + while (1); + } + } + Serial.println("BME680 initialized via TwoWire."); + // BME680 Settings + bme680.setTemperatureOversampling(BME680_OS_8X); + bme680.setHumidityOversampling(BME680_OS_2X); + bme680.setPressureOversampling(BME680_OS_4X); + bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); + bme680.setGasHeater(320, 150); + + zbTempSensor_BME68X.setMinMaxValue(-20, 80); + zbTempSensor_BME68X.setTolerance(1); + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + // Set analog resolution to 10 bits + // analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + // zbAnalogDevice_BME68X.addAnalogInput(); + // // Add endpoints to Zigbee Core + // Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + 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!"); + } + Serial.println("Connecting to network"); + while (!Zigbee.connected()) { + Serial.print("."); + delay(100); + } + Serial.println(); + + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbTempSensor_SCD4X.setReporting(1, 0, 1); + // zbTempSensor_BME68X.setReporting(1, 0, 1); + // zbAnalogDevice.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 + +} + +void loop() { + handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + + if (currentMode == eExitMode) { + // PRESENCE MODE + // static bool occupancy = false; + // bool occupancyNow = radar.motionDetection(); + // Serial.println(occupancyNow); + // // if (radar.motionDetection() == 1 && !occupancy) { + // if (occupancyNow != lastOccupancy) { + // Serial.println("MOTION DETECTED"); + // zbOccupancySensor.setOccupancy(occupancyNow); + // zbOccupancySensor.report(); + // // occupancy = true; + // lastOccupancy = occupancyNow; + // // } else if (radar.motionDetection() == 0 && occupancy) { + // // } else if (radar.motionDetection() == 0) { + // // Serial.println("MOTION ENDED"); + // // zbOccupancySensor.setOccupancy(false); + // // zbOccupancySensor.report(); + // // occupancy = false; + // } + // PRESENCE MODE - proper state machine + bool motionNow = radar.motionDetection(); + Serial.println(motionNow); + Serial.println(lastOccupancy); + Serial.println(millis() - occupancyStartTime); + + if (motionNow && !lastOccupancy) { + // Motion STARTED → Set occupancy ON + Serial.println("MOTION DETECTED → OCCUPANCY ON"); + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + + } else if (motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + Serial.println("Motion still present → timeout reset"); + occupancyStartTime = millis(); + + } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // TIMEOUT → Clear occupancy + Serial.println("OCCUPANCY TIMEOUT → OFF"); + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + + } else if (!motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + Serial.println("Motion ended → timeout started"); + // occupancyStartTime = millis(); + } + + + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + + + if(SCD4X.getDataReadyStatus()) { + DFRobot_SCD4X::sSensorMeasurement_t data; + SCD4X.readMeasurement(&data); + + Serial.print("Carbon dioxide concentration : "); + Serial.print(data.CO2ppm); + Serial.println(" ppm"); + + Serial.print("Environment temperature : "); + Serial.print(data.temp); + Serial.println(" C"); + + Serial.print("Relative humidity : "); + Serial.print(data.humidity); + Serial.println(" RH"); + + Serial.println(); + + zbCarbonDioxideSensor.setCarbonDioxide(data.CO2ppm); + zbCarbonDioxideSensor.report(); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_SCD4X.setTemperature(data.temp); + zbTempSensor_SCD4X.setHumidity(data.humidity); + // Report temperature and humidity values + zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + Serial.print("SCD41 reported."); + + + } + + + // float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + // bme68xData data_BME68X; + // delayMicroseconds(bme.getMeasDur()); + // Serial.print("Debug 1."); + // if (bme.fetchData()) { + // bme.getData(data_BME68X); + // temperature = data_BME68X.temperature; // Temperature in °C + // humidity = data_BME68X.humidity; // Humidity in % + // pressure = data_BME68X.pressure; // Pressure in hPa + // gasResistance = data_BME68X.gas_resistance; // Gas resistance in ohms + // // errorCount = 0; // Reset error count on successful read + + // // zbTempSensor_BME68X.setTemperature(temperature); + // // zbTempSensor_BME68X.setHumidity(humidity); + // // // Report temperature and humidity values + // // zbTempSensor_BME68X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + + // // zbAnalogDevice_BME68X.setAnalogInput(gasResistance); + // // zbAnalogDevice_BME68X.reportAnalogInput(); + + // Serial.print("BME68X reported."); + + // } + + // Read BME680 (temperature, humidity, pressure, gas) + // if (bme680.performReading()) { + // Serial.printf("BME680 - T:%.1f°C H:%.1f%% P:%.0fhPa G:%.0f kOhm\n", + // bme680.getTemperature(), bme680.getHumidity(), + // bme680.getPressure() / 100.0, bme680.getGas_resistance() / 1000.0); + // Serial.print("BME68X reported."); + // } + bool bmeReady = bme680.performReading(); + if (bmeReady && (millis() - bme_report_time > 5000)) { + Serial.print("BME680 -> Gas: "); Serial.print(bme680.gas_resistance / 1000.0); + Serial.print(" KOhms | Temp: "); Serial.print(bme680.temperature); Serial.println(" C"); + bme_report_time = millis(); + } else { + Serial.println("BME680 -> Waiting..."); + } + + + + + delay(100); +} diff --git a/sketch_nov30a/sketch_nov30a.ino b/sketch_nov30a/sketch_nov30a.ino new file mode 100644 index 0000000..846be18 --- /dev/null +++ b/sketch_nov30a/sketch_nov30a.ino @@ -0,0 +1,106 @@ +#include +#include +#include +#include "Adafruit_BME680.h" + +// --- Configuration --- +#define SDA_PIN 6 +#define SCL_PIN 20 + +// 1. Define the TwoWire instance we want to use +// On ESP32, 'Wire' is the default TwoWire instance (I2C bus 0). +// We use a reference here to show how you would treat it as a generic TwoWire object. +TwoWire myI2C = TwoWire(0); + +// Create sensor instances +// SensirionI2cScd4x scd4x; +Adafruit_BME680 bme; + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println("Initializing Custom TwoWire I2C..."); + + // 2. Initialize the TwoWire instance with specific pins + // calling myI2C->begin() is the same as calling Wire.begin() + // myI2C->begin(SDA_PIN, SCL_PIN); + myI2C.begin(SDA_PIN, SCL_PIN, 100000); + + + // // --- Initialize SCD41 --- + // // Sensirion library accepts the TwoWire object by REFERENCE (no & symbol) + // scd4x.begin(*myI2C, 0x62); + + // // Check SCD41 + // uint16_t error; + // char errorMessage[256]; + // scd4x.stopPeriodicMeasurement(); + + // error = scd4x.startPeriodicMeasurement(); + // if (error) { + // Serial.print("SCD41 Error: "); + // errorToString(error, errorMessage, 256); + // Serial.println(errorMessage); + // } else { + // Serial.println("SCD41 initialized via TwoWire."); + // } + + // --- Initialize BME680 --- + // Adafruit library accepts the TwoWire object by POINTER (needs & symbol if not already a pointer) + // We try address 0x77 first (common for generic modules), then 0x76 (Adafruit default) + + Serial.println("Connecting to BME680..."); + + // Note the syntax: .begin(Address, TwoWirePointer) + if (!bme.begin(0x77, &myI2C)) { + Serial.println("BME680 not found at 0x77, trying 0x76..."); + if (!bme.begin(0x76, &myI2C)) { + Serial.println("BME680 Init Failed! Check wiring."); + while (1); + } + } + Serial.println("BME680 initialized via TwoWire."); + + // BME680 Settings + bme.setTemperatureOversampling(BME680_OS_8X); + bme.setHumidityOversampling(BME680_OS_2X); + bme.setPressureOversampling(BME680_OS_4X); + bme.setIIRFilterSize(BME680_FILTER_SIZE_3); + bme.setGasHeater(320, 150); +} + +void loop() { + // Read SCD41 + uint16_t co2 = 0; + float temp_scd = 0, hum_scd = 0; + bool scdReady = false; + + // if (scd4x.getDataReadyStatus()) { + // uint16_t error = scd4x.readMeasurement(co2, temp_scd, hum_scd); + // if (!error && co2 != 0) scdReady = true; + // } + + // Read BME680 + bool bmeReady = bme.performReading(); + + // Output + Serial.println("\n--- Readings ---"); + + // if (scdReady) { + // Serial.print("SCD41 -> CO2: "); Serial.print(co2); + // Serial.print(" ppm | Temp: "); Serial.print(temp_scd); Serial.println(" C"); + // } else { + // Serial.println("SCD41 -> Waiting..."); + // } + + if (bmeReady) { + Serial.print("BME680 -> Gas: "); Serial.print(bme.gas_resistance / 1000.0); + Serial.print(" KOhms | Temp: "); Serial.print(bme.temperature); Serial.println(" C"); + } else { + Serial.println("BME680 -> Waiting..."); + } + + Serial.println("Loop"); + delay(1000); +} \ No newline at end of file diff --git a/sketch_nov30b/sketch_nov30b.ino b/sketch_nov30b/sketch_nov30b.ino new file mode 100644 index 0000000..c4d4d35 --- /dev/null +++ b/sketch_nov30b/sketch_nov30b.ino @@ -0,0 +1,240 @@ +/* + * THIS FILE IS AUTOMATICALLY GENERATED + * + * Generator: sensirion-driver-generator 1.1.2 + * Product: scd4x + * Model-Version: 2.0 + */ +/* + * Copyright (c) 2025, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +// macro definitions +// make sure that we use the proper definition of NO_ERROR +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#define NO_ERROR 0 + +#define SDA_PIN 6 +#define SCL_PIN 20 + +SensirionI2cScd4x sensor; + +static char errorMessage[64]; +static int16_t error; + + + +#include +Bme68x bme; + + +void PrintUint64(uint64_t& value) { + Serial.print("0x"); + Serial.print((uint32_t)(value >> 32), HEX); + Serial.print((uint32_t)(value & 0xFFFFFFFF), HEX); +} + +void setup() { + + Serial.begin(115200); + while (!Serial) { + delay(100); + } + Wire.begin(SDA_PIN, SCL_PIN); + sensor.begin(Wire, SCD41_I2C_ADDR_62); + + uint64_t serialNumber = 0; + delay(30); + // Ensure sensor is in clean state + error = sensor.wakeUp(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute wakeUp(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + error = sensor.stopPeriodicMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute stopPeriodicMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + error = sensor.reinit(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute reinit(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + } + // Read out information about the sensor + error = sensor.getSerialNumber(serialNumber); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getSerialNumber(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + Serial.print("serial number: "); + PrintUint64(serialNumber); + Serial.println(); + // + // If temperature offset and/or sensor altitude compensation + // is required, you should call the respective functions here. + // Check out the header file for the function definitions. + // Start periodic measurements (5sec interval) + error = sensor.startPeriodicMeasurement(); + if (error != NO_ERROR) { + Serial.print("Error trying to execute startPeriodicMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + // + // If low-power mode is required, switch to the low power + // measurement function instead of the standard measurement + // function above. Check out the header file for the definition. + // For SCD41, you can also check out the single shot measurement example. + // + + + + + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + + + +} + +void loop() { + + bool dataReady = false; + uint16_t co2Concentration = 0; + float temperature = 0.0; + float relativeHumidity = 0.0; + // + // Slow down the sampling to 0.2Hz. + // + delay(5000); + error = sensor.getDataReadyStatus(dataReady); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getDataReadyStatus(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + while (!dataReady) { + delay(100); + error = sensor.getDataReadyStatus(dataReady); + if (error != NO_ERROR) { + Serial.print("Error trying to execute getDataReadyStatus(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + } + // + // If ambient pressure compenstation during measurement + // is required, you should call the respective functions here. + // Check out the header file for the function definition. + error = + sensor.readMeasurement(co2Concentration, temperature, relativeHumidity); + if (error != NO_ERROR) { + Serial.print("Error trying to execute readMeasurement(): "); + errorToString(error, errorMessage, sizeof errorMessage); + Serial.println(errorMessage); + return; + } + // + // Print results in physical units. + Serial.print("CO2 concentration [ppm]: "); + Serial.print(co2Concentration); + Serial.println(); + Serial.print("Temperature [°C]: "); + Serial.print(temperature); + Serial.println(); + Serial.print("Relative Humidity [RH]: "); + Serial.print(relativeHumidity); + Serial.println(); + + Serial.println("---------------------------"); + + float bme_temperature(NAN), bme_humidity(NAN), bme_pressure(NAN), bme_gasResistance(NAN); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + if (bme.fetchData()) { + bme.getData(data); + bme_temperature = data.temperature; // Temperature in °C + bme_humidity = data.humidity; // Humidity in % + bme_pressure = data.pressure; // Pressure in hPa + bme_gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", bme_temperature, bme_humidity, bme_gasResistance); + + } else { + Serial.println("BME680 -> Waiting..."); + } + + + + + + + + + + + + +} \ No newline at end of file diff --git a/sketch_nov30d/sketch_nov30d.ino b/sketch_nov30d/sketch_nov30d.ino new file mode 100644 index 0000000..bb979b3 --- /dev/null +++ b/sketch_nov30d/sketch_nov30d.ino @@ -0,0 +1,751 @@ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds - adjust as needed +const unsigned long TRIGGER_DELAY = 10; // 10 -> 100 ms + + + + + + +// Define your custom SCL/SDA pins +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin +// Create custom I2C instance +// TwoWire sharedI2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) + + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +// #include +// // DFRobot_SCD4X SCD4X(&Wire, /*i2cAddr = */SCD4X_I2C_ADDR); +// // SCD41 with custom I2C +// DFRobot_SCD4X SCD4X(&sharedI2C, SCD4X_I2C_ADDR); + +#include +#include +#include + +SensirionI2cScd4x scd41; + + + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 12 +ZigbeeTempSensor zbTempSensor_SCD4X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + + + + + + + +// --- BME680 Settings --- + +#include +Bme68x bme; +// TwoWire BME68X_I2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) +// #include // BME680 library +// DFRobot_BME680_I2C bme680(0x76); // 0x76 +// #include +// #include "Adafruit_BME680.h" +// Adafruit_BME680 bme680; +unsigned long bme_report_time = millis(); + +#define TEMP_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 14 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + + + + +// --- T6713 Settings --- +#define T6713_ADDR 0x15 +// T6713 Register Addresses (Modbus) +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +unsigned long t6713_report_time = millis(); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713 15 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_T6713 = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713); + + + + + + + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/500, /*trig*/500)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(8)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(8)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/TRIGGER_DELAY, /*keep*/OCCUPANCY_TIMEOUT)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + + + + + + + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + + + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + +void setup() { + Serial.begin(115200); + while (!Serial); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + + + + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + // Initialize custom I2C with YOUR pins + // SCD41_I2C.begin(SCD41_SDA_PIN, SCD41_SCL_PIN, 100000); // 100kHz standard + // Initialize SHARED I2C bus ONCE + // sharedI2C.begin(I2C_SDA_PIN, I2C_SCL_PIN, 100000); + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + scd41.begin(Wire, SCD41_I2C_ADDR_62); + + // while( !SCD4X.begin() ){ + // Serial.println("Communication with device failed, please check connection"); + // delay(3000); + // } + scd41.stopPeriodicMeasurement(); + Serial.println("SCD4x: Begin ok!"); + scd41.startPeriodicMeasurement(); + + // SCD4X.setTempComp(4.0); + // float temp = 0; + // temp = SCD4X.getTempComp(); + // Serial.print("The current temperature compensation value : "); + // Serial.print(temp); + // Serial.println(" C"); + + // SCD4X.setSensorAltitude(540); + // uint16_t altitude = 0; + // altitude = SCD4X.getSensorAltitude(); + // Serial.print("Set the current environment altitude : "); + // Serial.print(altitude); + // Serial.println(" m"); + + // SCD4X.enablePeriodMeasure(SCD4X_START_PERIODIC_MEASURE); + + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_SCD4X.setMinMaxValue(10, 50); + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_SCD4X.setTolerance(1); + // Optional: Time cluster configuration (default params, as this device will revieve time from coordinator) + // zbTempSensor.addTimeCluster(); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_SCD4X.addHumiditySensor(0, 100, 1); + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_SCD4X); + + + + + + + Serial.println("Connecting to BME680..."); + + // // Init BME680 + // if (bme680.begin(sharedI2C) != 0) { + // Serial.println("BME680 init failed!"); + // } else { + // Serial.println("BME680 ready!"); + // } + // Wire.begin(SCD41_SDA_PIN, SCD41_SCL_PIN); + // Wire.setClock(100000); // Set I2C clock speed to 100kHz + // // Initialize the BME680 + // bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme.begin(BME68X_I2C_ADDR_HIGH, &BME68X_I2C); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme680.begin() + // // Set up the BME680 + // // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // // bme.setOversampling(T2, OS_2X); + // // bme.setOversampling(T1, OS_16X); + // // bme.setOversampling(H1, OS_2X); + // // bme.setFilter(FILTER_SIZE_3); + // // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + // if(bme.checkStatus()) + // { + // if (bme.checkStatus() == BME68X_ERROR) + // { + // Serial.println("Sensor error:" + bme.statusString()); + // return; + // } + // else if (bme.checkStatus() == BME68X_WARNING) + // { + // Serial.println("Sensor Warning:" + bme.statusString()); + // } + // } + // /* Set the default configuration for temperature, pressure and humidity */ + // bme.setTPH(); + // /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + // bme.setHeaterProf(300, 100); + + // bme68xData data; + // bme.setOpMode(BME68X_FORCED_MODE); + + + // Note the syntax: .begin(Address, TwoWirePointer) + // if (!bme680.begin(0x77, &sharedI2C)) { + // Serial.println("BME680 not found at 0x77, trying 0x76..."); + // if (!bme680.begin(0x76, &sharedI2C)) { + // Serial.println("BME680 Init Failed! Check wiring."); + // while (1); + // } + // } + // Serial.println("BME680 initialized via TwoWire."); + // // BME680 Settings + // bme680.setTemperatureOversampling(BME680_OS_8X); + // bme680.setHumidityOversampling(BME680_OS_2X); + // bme680.setPressureOversampling(BME680_OS_4X); + // bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); + // bme680.setGasHeater(320, 150); + + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + /* Set the default configuration for temperature, pressure and humidity */ + // setTPH(uint8_t os_temp, uint8_t os_pres, uint8_t os_hum); BME68X_OS_NONE, BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X, BME68X_OS_16X + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensor_BME68X.setMinMaxValue(-20, 80); + zbTempSensor_BME68X.setTolerance(1); + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + // Set analog resolution to 10 bits + // analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + + + // TRUE = Normal Home/Office use + // FALSE = Greenhouse / Constantly occupied + configureT6713(true); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor_T6713.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor_T6713); + + + + + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + // Increase keep-alive to 5 seconds (default is often 3000ms) + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 5000; + // zigbeeConfig.nwk_cfg.zed_cfg.ed_timeout = ESP_ZB_ED_AGING_TIMEOUT_256MIN; // 4 hours; How long the parent remembers this device. + + // 1. Our custom config (zigbeeConfig) + // 2. false = Do NOT erase NVS (keep network credentials) + // 3. true = Start automatically (optional, defaults to true) + if (!Zigbee.begin(&zigbeeConfig, false)) { + 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(); + + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbTempSensor_SCD4X.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(1, 0, 1); + // zbAnalogDevice.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 + +} + + + + +void loop() { + handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + + if (currentMode == eExitMode) { + // PRESENCE MODE + // static bool occupancy = false; + // bool occupancyNow = radar.motionDetection(); + // Serial.println(occupancyNow); + // // if (radar.motionDetection() == 1 && !occupancy) { + // if (occupancyNow != lastOccupancy) { + // Serial.println("MOTION DETECTED"); + // zbOccupancySensor.setOccupancy(occupancyNow); + // zbOccupancySensor.report(); + // // occupancy = true; + // lastOccupancy = occupancyNow; + // // } else if (radar.motionDetection() == 0 && occupancy) { + // // } else if (radar.motionDetection() == 0) { + // // Serial.println("MOTION ENDED"); + // // zbOccupancySensor.setOccupancy(false); + // // zbOccupancySensor.report(); + // // occupancy = false; + // } + // PRESENCE MODE - proper state machine + bool motionNow = radar.motionDetection(); + // Serial.println(motionNow); + // Serial.println(lastOccupancy); + // Serial.println(millis() - occupancyStartTime); + + if (motionNow && !lastOccupancy) { + // Motion STARTED → Set occupancy ON + Serial.println("MOTION DETECTED → OCCUPANCY ON"); + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + + } else if (motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion still present → timeout reset"); + occupancyStartTime = millis(); + + } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // TIMEOUT → Clear occupancy + Serial.println("OCCUPANCY TIMEOUT → OFF"); + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + + } else if (!motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion ended → timeout started"); + // occupancyStartTime = millis(); + } + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + + + // --- Read SCD41 --- + uint16_t co2_scd = 0; + float temperature_scd = 0.0f; + float humidity_scd = 0.0f; + bool scdReady = false; + + uint16_t error = scd41.readMeasurement(co2_scd, temperature_scd, humidity_scd); + if (error == 0 && co2_scd != 0) { + scdReady = true; + } + + if (scdReady) { + Serial.print("[SCD41] CO2: "); Serial.print(co2_scd); Serial.print(" ppm"); + Serial.print(" | Temp: "); Serial.print(temperature_scd); Serial.print(" C"); + Serial.print(" | Hum: "); Serial.print(humidity_scd); Serial.println(" %"); + + zbCarbonDioxideSensor.setCarbonDioxide(co2_scd); + zbCarbonDioxideSensor.report(); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_SCD4X.setTemperature(temperature_scd); + zbTempSensor_SCD4X.setHumidity(humidity_scd); + // Report temperature and humidity values + zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + } + // else { + // Serial.println("[SCD41] Waiting for measurement..."); + // } + + + // if(SCD4X.getDataReadyStatus()) { + // DFRobot_SCD4X::sSensorMeasurement_t data; + // SCD4X.readMeasurement(&data); + + // Serial.print("Carbon dioxide concentration : "); + // Serial.print(data.CO2ppm); + // Serial.println(" ppm"); + + // Serial.print("Environment temperature : "); + // Serial.print(data.temp); + // Serial.println(" C"); + + // Serial.print("Relative humidity : "); + // Serial.print(data.humidity); + // Serial.println(" RH"); + + // Serial.println(); + + // zbCarbonDioxideSensor.setCarbonDioxide(data.CO2ppm); + // zbCarbonDioxideSensor.report(); + + // // Update temperature and humidity values in Temperature sensor EP + // zbTempSensor_SCD4X.setTemperature(data.temp); + // zbTempSensor_SCD4X.setHumidity(data.humidity); + // // Report temperature and humidity values + // zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + + // } + + + // Serial.println("---------------------------"); + + float bme_temperature(NAN), bme_humidity(NAN), bme_pressure(NAN), bme_gasResistance(NAN); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + // delay(bme.getMeasDur(BME68X_FORCED_MODE) / 1000 + 50); + if (bme.fetchData() && (millis() - bme_report_time > 5000)) { + bme.getData(data); + bme_temperature = data.temperature; // Temperature in °C + bme_humidity = data.humidity; // Humidity in % + bme_pressure = data.pressure; // Pressure in hPa + bme_gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + Serial.printf("[BME680] temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", bme_temperature, bme_humidity, bme_gasResistance); + + zbTempSensor_BME68X.setTemperature(bme_temperature); + zbTempSensor_BME68X.setHumidity(bme_humidity); + // Report temperature and humidity values + zbTempSensor_BME68X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + + zbAnalogDevice_BME68X.setAnalogInput(bme_gasResistance); + zbAnalogDevice_BME68X.reportAnalogInput(); + + // Serial.print("BME68X reported."); + bme_report_time = millis(); + } + // else { + // Serial.println("BME680 -> Waiting..."); + // } + + + + + + // --- Read T6713 (CO2) --- + int co2_t6713 = readT6713(); + if ((co2_t6713 >= 0) && (millis() - t6713_report_time > 5000)) { + Serial.print("T6713 | CO2: "); Serial.print(co2_t6713); Serial.println(" ppm"); + zbCarbonDioxideSensor_T6713.setCarbonDioxide(co2_t6713); + zbCarbonDioxideSensor_T6713.report(); + t6713_report_time = millis(); + } + // else { + // Serial.println("T6713 | Read Error"); + // } + + + delay(100); +} + + + + + + +// Helper function for T6713 +int readT6713() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); // Address High + Wire.write(0x8B); // Address Low + Wire.write(0x00); + Wire.write(0x01); // Length (1 register) + if (Wire.endTransmission() != 0) return -1; + + delay(10); // Processing delay + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Skip Func & Len + byte high = Wire.read(); + byte low = Wire.read(); + return (high << 8) | low; + } + return -1; +} + + +void configureT6713(bool enableABC) { + // 1. Wait for Sensor Warm-up (at least 500ms after power on, datasheet says much longer for accuracy) + delay(1000); + + // 2. Check Status Register (Optional but good practice) + // We read register 0x138A (5002) to check for errors/warmup + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); + Wire.write(0x13); Wire.write(0x8A); // Address 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Func, Len + uint16_t status = (Wire.read() << 8) | Wire.read(); + // Bit 3 is Warm-up mode. If 1, sensor is still warming up. + if (status & 0x08) { + Serial.println("T6713: Warming up..."); + } + } + + // 3. Configure ABC Logic (Automatic Background Calibration) + // Write to Register 0x03EE (1006). Value: 0xFF00 = Enable, 0x0000 = Disable + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Function: Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + + byte error = Wire.endTransmission(); + if (error == 0) { + Serial.print("T6713: ABC Logic set to "); + Serial.println(enableABC ? "ON" : "OFF"); + } else { + Serial.println("T6713: Failed to set ABC Logic"); + } + + // 4. Wait for the write to "stick" + delay(100); +} + diff --git a/sketch_nov30e/sketch_nov30e.ino b/sketch_nov30e/sketch_nov30e.ino new file mode 100644 index 0000000..ec76e5e --- /dev/null +++ b/sketch_nov30e/sketch_nov30e.ino @@ -0,0 +1,96 @@ +#include + +// Default I2C Address for T6713 is 0x15 (decimal 21) +#define T6713_ADDR 0x15 +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin + +#include +#ifndef BME68X_I2C_ADDR + #define BME68X_I2C_ADDR 0x76 // Change to 0x77 if sensor not found +#endif +Bme68x bme; + +void setup() { + Serial.begin(115200); + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); // Join I2C bus + + Serial.println("Initializing Sensors..."); + + // 1. Initialize BME680 + bme.begin(BME68X_I2C_ADDR, Wire); + if(bme.checkStatus()) { + Serial.println("BME680 Error: " + bme.statusString()); + if (bme.checkStatus() == BME68X_ERROR) { + Serial.println("Check wiring or I2C address (0x76 vs 0x77)"); + while(1); // Halt if BME fails + } + } + Serial.println("BME680 Found!"); + + // Configure BME680 for "Forced Mode" (On-Demand) + bme.setTPH(); // Set default oversampling for Temp, Pres, Hum + + // Configure Heater for Gas Measurement (300°C for 100ms) + bme.setHeaterProf(300, 100); + + Serial.println("Sensors Ready. Starting Loop..."); + delay(2000); // Let sensor warm up +} + + + + +void loop() { + Serial.println("-----------------------------"); + + // --- Read T6713 (CO2) --- + int co2 = readT6713(); + if (co2 >= 0) { + Serial.print("T6713 | CO2: "); Serial.print(co2); Serial.println(" ppm"); + } else { + Serial.println("T6713 | Read Error"); + } + + // --- Read BME680 (Temp, Hum, Pres, Gas) --- + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); // Trigger measurement + + // Wait for measurement to complete (depends on heater duration) + delay(bme.getMeasDur(BME68X_FORCED_MODE) / 1000 + 50); + + if (bme.fetchData()) { + bme.getData(data); + Serial.print("BME680 | Temp: "); Serial.print(data.temperature); Serial.println(" C"); + Serial.print("BME680 | Hum: "); Serial.print(data.humidity); Serial.println(" %"); + Serial.print("BME680 | Pres: "); Serial.print(data.pressure / 100.0); Serial.println(" hPa"); + Serial.print("BME680 | Gas: "); Serial.print(data.gas_resistance / 1000.0); Serial.println(" kOhm"); + } else { + Serial.println("BME680 | Failed to fetch data"); + } + + // Wait 5 seconds before next cycle + delay(5000); +} + +// Helper function for T6713 +int readT6713() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); // Address High + Wire.write(0x8B); // Address Low + Wire.write(0x00); + Wire.write(0x01); // Length (1 register) + if (Wire.endTransmission() != 0) return -1; + + delay(10); // Processing delay + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Skip Func & Len + byte high = Wire.read(); + byte low = Wire.read(); + return (high << 8) | low; + } + return -1; +} \ No newline at end of file diff --git a/telaire_t6713_test1/TelaireT6713.cpp b/telaire_t6713_test1/TelaireT6713.cpp new file mode 100644 index 0000000..8c66b6d --- /dev/null +++ b/telaire_t6713_test1/TelaireT6713.cpp @@ -0,0 +1,112 @@ +#include "TelaireT6713.h" + +TelaireT6713::TelaireT6713(uint8_t address, uint8_t sda, uint8_t scl) + : _address(address), _sda(sda), _scl(scl) {} + +void TelaireT6713::setI2CPins(uint8_t sda, uint8_t scl) { + _sda = sda; + _scl = scl; +} + +void TelaireT6713::setAddress(uint8_t address) { + _address = address; +} + +void TelaireT6713::begin() { + Wire.begin(_sda, _scl); + delay(1000); + Serial.println("Telaire T6713 Initialized."); + printSensorStatus(); +} + +int TelaireT6713::readCO2(bool debug) { + int data[4]; + + Wire.beginTransmission(_address); + Wire.write(0x04); Wire.write(0x13); Wire.write(0x8B); + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + + delay(2000); + + Wire.requestFrom(_address, (uint8_t)4); + if (Wire.available() < 4) { + if (debug) Serial.println("Error: Less than 4 bytes received"); + return -1; + } + + data[0] = Wire.read(); + data[1] = Wire.read(); + data[2] = Wire.read(); + data[3] = Wire.read(); + + if (debug) { + Serial.print("FUNC: 0x"); Serial.println(data[0], HEX); + Serial.print("BYTE COUNT: 0x"); Serial.println(data[1], HEX); + Serial.print("MSB: 0x"); Serial.println(data[2], HEX); + Serial.print("LSB: 0x"); Serial.println(data[3], HEX); + } + + int ppm = ((data[2] & 0x3F) << 8) | data[3]; + return ppm; +} + +void TelaireT6713::enableABC() { + uint8_t cmd[] = { 0x05, 0x03, 0xEE, 0xFF, 0x00 }; + sendCommand(cmd, sizeof(cmd)); + Serial.println("ABC Enabled."); +} + +void TelaireT6713::disableABC() { + uint8_t cmd[] = { 0x05, 0x03, 0xEE, 0x00, 0x00 }; + sendCommand(cmd, sizeof(cmd)); + Serial.println("ABC Disabled."); +} + +void TelaireT6713::printSensorStatus() { + uint8_t statusCmd[] = { 0x04, 0x13, 0x8A, 0x00, 0x01 }; + sendCommand(statusCmd, sizeof(statusCmd)); + delay(100); + + uint8_t response[4]; + if (!readBytes(response, 4)) { + Serial.println("Failed to read sensor status."); + return; + } + + uint8_t msb = response[2]; + uint8_t lsb = response[3]; + + Serial.print("Sensor status: "); + if (msb == 0x00 && lsb == 0x00) Serial.println("No error."); + else if (msb == 0x00 && lsb == 0x01) Serial.println("Error condition."); + else if (msb == 0x00 && lsb == 0x02) Serial.println("Flash error."); + else if (msb == 0x00 && lsb == 0x03) Serial.println("Calibration error."); + else if (msb == 0x04 && lsb == 0x00) Serial.println("Reboot."); + else if (msb == 0x08 && lsb == 0x00) Serial.println("Warm-up mode."); + else if (msb == 0x80 && lsb == 0x00) Serial.println("Single point calibration."); + else { + Serial.print("Unknown status (0x"); + Serial.print(msb, HEX); + Serial.print(" 0x"); + Serial.print(lsb, HEX); + Serial.println(")"); + } +} + +void TelaireT6713::sendCommand(const uint8_t* cmd, size_t len) { + Wire.beginTransmission(_address); + for (size_t i = 0; i < len; ++i) { + Wire.write(cmd[i]); + } + Wire.endTransmission(); +} + +bool TelaireT6713::readBytes(uint8_t* buffer, size_t length) { + Wire.requestFrom(_address, (uint8_t)length); + size_t i = 0; + while (Wire.available() && i < length) { + buffer[i++] = Wire.read(); + } + return i == length; +} diff --git a/telaire_t6713_test1/TelaireT6713.h b/telaire_t6713_test1/TelaireT6713.h new file mode 100644 index 0000000..7c00c5e --- /dev/null +++ b/telaire_t6713_test1/TelaireT6713.h @@ -0,0 +1,26 @@ +#ifndef TELAIRE_T6713_H +#define TELAIRE_T6713_H + +#include +#include + +class TelaireT6713 { + public: + TelaireT6713(uint8_t address = 0x15, uint8_t sda = 8, uint8_t scl = 14); + void begin(); + int readCO2(bool debug = false); + void enableABC(); + void disableABC(); + void printSensorStatus(); + void setI2CPins(uint8_t sda, uint8_t scl); + void setAddress(uint8_t address); + + private: + uint8_t _address; + uint8_t _sda, _scl; + + void sendCommand(const uint8_t* cmd, size_t len); + bool readBytes(uint8_t* buffer, size_t length); +}; + +#endif diff --git a/telaire_t6713_test1/telaire_t6713_test1.ino b/telaire_t6713_test1/telaire_t6713_test1.ino new file mode 100644 index 0000000..5e18294 --- /dev/null +++ b/telaire_t6713_test1/telaire_t6713_test1.ino @@ -0,0 +1,96 @@ +#include "TelaireT6713.h" +#include "Arduino.h" +#include + +// Define the I2C pins +#define SCL_PIN 8 +#define SDA_PIN 14 + +#define POWER_PIN 21 // GPIO pin to power the sensor + + +TelaireT6713 co2Sensor; +Bme68x bme; + +void setup() { + Serial.begin(115200); + delay(1000); + + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); // Power on the sensor(s) + + // Telaire CO2 sensor init + co2Sensor.setI2CPins(17, 16); + co2Sensor.setAddress(0x15); + co2Sensor.begin(); + co2Sensor.enableABC(); + + + Wire.begin(SDA_PIN, SCL_PIN); + Wire.setClock(100000); // Set I2C clock speed to 100kHz + // Initialize the BME680 + bme.begin(BME68X_I2C_ADDR_LOW, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // Set up the BME680 + // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // bme.setOversampling(T2, OS_2X); + // bme.setOversampling(T1, OS_16X); + // bme.setOversampling(H1, OS_2X); + // bme.setFilter(FILTER_SIZE_3); + // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + if(bme.checkStatus()) + { + if (bme.checkStatus() == BME68X_ERROR) + { + Serial.println("Sensor error:" + bme.statusString()); + return; + } + else if (bme.checkStatus() == BME68X_WARNING) + { + Serial.println("Sensor Warning:" + bme.statusString()); + } + } + /* Set the default configuration for temperature, pressure and humidity */ + bme.setTPH(); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + +} + + +void loop() { + int co2ppm = co2Sensor.readCO2(); + if (co2ppm >= 0) { + Serial.print("CO2: "); Serial.print(co2ppm); Serial.println(" ppm"); + } else { + Serial.println("CO2 read error"); + } + + float temperature(NAN), humidity(NAN), pressure(NAN), gasResistance(NAN); + // Prepare the BME680 for measurement + bme68xData data; + int8_t rslt; + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; // Temperature in °C + humidity = data.humidity; // Humidity in % + pressure = data.pressure; // Pressure in hPa + gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + } else { + //Serial.println("Failed to read data from BME680!"); + //return; // Exit if reading failed + } + + Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", temperature, humidity, gasResistance); + + + + Serial.println("---------------------------"); + delay(2000); +} diff --git a/test_boot_pin/test_boot_pin.ino b/test_boot_pin/test_boot_pin.ino new file mode 100644 index 0000000..7ee138e --- /dev/null +++ b/test_boot_pin/test_boot_pin.ino @@ -0,0 +1,11 @@ +// Connect a 10kΩ resistor between GPIO9 and GND. + +void setup() { + Serial.begin(115200); + pinMode(BOOT_PIN, INPUT_PULLUP); +} +void loop() { + Serial.println(digitalRead(BOOT_PIN)); + Serial.println(BOOT_PIN); + delay(500); +} diff --git a/waveshare_eink_sensor_readings/.theia/launch.json b/waveshare_eink_sensor_readings/.theia/launch.json new file mode 100644 index 0000000..7e4253b --- /dev/null +++ b/waveshare_eink_sensor_readings/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/waveshare_eink_sensor_readings/waveshare_eink_sensor_readings.ino b/waveshare_eink_sensor_readings/waveshare_eink_sensor_readings.ino new file mode 100644 index 0000000..e6c963d --- /dev/null +++ b/waveshare_eink_sensor_readings/waveshare_eink_sensor_readings.ino @@ -0,0 +1,132 @@ +// https://www.waveshare.com/product/1.54inch-e-paper-module-b.htm +// https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)_Manual#ESP32.2F8266 +// https://learn.adafruit.com/adafruit-1-54-eink-display-breakouts/arduino-usage + + + + + + +/*************************************************** + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_ThinkInk.h" + +#define EPD_DC 16 +#define EPD_CS 17 +#define EPD_BUSY 22 // can set to -1 to not use a pin (will wait a fixed delay) +#define SRAM_CS -1 +#define EPD_RESET 23 // can set to -1 and share with microcontroller Reset! +#define EPD_SPI &SPI // primary SPI + +// 1.54" 200x200 Tricolor EPD with SSD1681 chipset +ThinkInk_154_Tricolor_Z90 display(EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, +EPD_BUSY, EPD_SPI); + +// Timing variables +unsigned long lastUpdate = 0; +const unsigned long updateInterval = 60000; // 10 seconds + +// Dummy sensor values +int dummyCycle = 0; + + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + Serial.println("Adafruit EPD full update test in red/black/white"); + display.begin(THINKINK_TRICOLOR); + + display.setRotation(0); + // 0: Default (0°) + // 1: Rotate 90° clockwise + // 2: Rotated 180° + // 3: Rotated 270° clockwise + +} + +void loop() { + if (millis() - lastUpdate > updateInterval) { + lastUpdate = millis(); + dummyCycle++; + updateDisplay(); + } +} + + +void updateDisplay() { + // Generate dummy sensor values + int gas = 300 + (dummyCycle * 13) % 400; + int light = 200 + (dummyCycle * 29) % 800; + float temp = 15 + (dummyCycle * 0.75); + float humid = 45 + int(dummyCycle * 1.5) % 50; + int soil = 600 - (dummyCycle * 17) % 500; + bool waterPresent = dummyCycle % 2 == 0; + + display.clearBuffer(); + display.setTextColor(EPD_BLACK); + display.setTextSize(2); // double size text + + // Cell coords and spacing + const int leftX = 0; + const int rightX = 100; + const int rowHeight = 66; + + // ======== ROW 0 ======== + // Gas icon (left, top) + display.fillCircle(leftX + 20, 18, 6, EPD_BLACK); + display.fillCircle(leftX + 33, 16, 5, EPD_BLACK); + display.fillCircle(leftX + 45, 18, 6, EPD_BLACK); + display.setCursor(leftX + 55, 10); display.print("Gas:"); + display.setCursor(leftX + 55, 34); display.print(gas); + + // Light icon (right, top) + display.drawCircle(rightX + 20, 18, 6, EPD_BLACK); + for (int i = 0; i < 360; i += 45) { + int dx = 12 * cos(radians(i)); + int dy = 12 * sin(radians(i)); + display.drawLine(rightX + 20, 18, rightX + 20 + dx, 18 + dy, EPD_BLACK); + } + display.setCursor(rightX + 55, 10); display.print("Light:"); + display.setCursor(rightX + 55, 34); display.print(light); + + // ======== ROW 1 ======== + // Temp icon (left) + display.drawRect(leftX + 20, rowHeight + 10, 8, 26, EPD_BLACK); + display.fillCircle(leftX + 24, rowHeight + 42, 7, EPD_BLACK); + display.setCursor(leftX + 55, rowHeight + 10); display.print("Temp:"); + display.setCursor(leftX + 55, rowHeight + 34); display.print(temp, 1); display.print("C"); + + // Humidity icon (right) + display.drawTriangle(rightX + 24, rowHeight + 10, rightX + 14, rowHeight + 40, rightX + 34, rowHeight + 40, EPD_BLACK); + display.drawCircle(rightX + 24, rowHeight + 35, 7, EPD_BLACK); + display.setCursor(rightX + 55, rowHeight + 10); display.print("Humidity:"); + display.setCursor(rightX + 55, rowHeight + 34); display.print(humid, 1); display.print("%"); + + // ======== ROW 2 ======== + // Soil icon (left) + display.drawLine(leftX + 30, 2 * rowHeight + 15, leftX + 30, 2 * rowHeight + 50, EPD_BLACK); + display.drawCircle(leftX + 22, 2 * rowHeight + 30, 7, EPD_BLACK); + display.drawCircle(leftX + 38, 2 * rowHeight + 30, 7, EPD_BLACK); + display.setCursor(leftX + 55, 2 * rowHeight + 20); display.print("Soil:"); + display.setCursor(leftX + 55, 2 * rowHeight + 48); display.print(soil); + + // Water icon (right) + display.drawRect(rightX + 22, 2 * rowHeight + 15, 20, 35, EPD_BLACK); + display.drawLine(rightX + 22, 2 * rowHeight + 25, rightX + 42, 2 * rowHeight + 25, EPD_BLACK); + display.drawLine(rightX + 22, 2 * rowHeight + 35, rightX + 42, 2 * rowHeight + 35, EPD_BLACK); + display.setCursor(rightX + 55, 2 * rowHeight + 20); display.print("Water:"); + display.setCursor(rightX + 55, 2 * rowHeight + 48); display.print(waterPresent ? "Yes" : "No"); + + // Update display & power down + display.display(); + display.powerDown(); +}