Initial commit of existing code
This commit is contained in:
commit
59defedb8e
|
|
@ -0,0 +1,3 @@
|
|||
*.hex
|
||||
build/
|
||||
.DS_Store
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef LEAPMMW_RADAR_H
|
||||
#define LEAPMMW_RADAR_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// hs2xx3a.h
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef MMWAVE_RADAR_CUSTOM_H
|
||||
#define MMWAVE_RADAR_CUSTOM_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
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
|
||||
|
|
@ -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 <DFRobot_mmWave_Radar.h>
|
||||
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#include <HardwareSerial.h>
|
||||
|
||||
#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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
#include <HardwareSerial.h>
|
||||
|
||||
#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 <par1> <par2> [<par3> <par4>]
|
||||
// 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,<par1>,<par2>,<par3>,<par4>*
|
||||
// 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,<par1>,<par2>,<par3>,<par4>,<par5>,<par6>,<par7>*
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
#include <Wire.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -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 <functional>
|
||||
|
||||
bool withI2C(std::function<bool(void)> 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));
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
// #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 <bme68xLibrary.h>
|
||||
|
||||
// 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 <Wire.h>
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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 <functional>
|
||||
bool withI2C(std::function<bool(void)> 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));
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#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();
|
||||
}
|
||||
|
|
@ -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 <Zigbee.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_SHT31.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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 <functional>
|
||||
bool withI2C(std::function<bool(void)> 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));
|
||||
}
|
||||
|
|
@ -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 <functional>
|
||||
bool withI2C(std::function<bool(void)> 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));
|
||||
}
|
||||
|
|
@ -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 <BME280I2C.h>
|
||||
//#include <Wire.h>
|
||||
#include "Arduino.h"
|
||||
#include <bme68xLibrary.h>
|
||||
#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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef TELAIRE_T6713_H
|
||||
#define TELAIRE_T6713_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 <Wire.h>
|
||||
#include <SensirionI2cScd4x.h>
|
||||
#include <bme68xLibrary.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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 <functional>
|
||||
|
||||
bool withI2C(std::function<bool(void)> 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));
|
||||
}
|
||||
|
|
@ -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.h>
|
||||
// // DFRobot_SCD4X SCD4X(&Wire, /*i2cAddr = */SCD4X_I2C_ADDR);
|
||||
// // SCD41 with custom I2C
|
||||
// DFRobot_SCD4X SCD4X(&sharedI2C, SCD4X_I2C_ADDR);
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SensirionI2cScd4x.h>
|
||||
#include <Wire.h>
|
||||
|
||||
SensirionI2cScd4x scd41;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define TEMP_SENSOR_ENDPOINT_NUMBER 12
|
||||
ZigbeeTempSensor zbTempSensor_SCD4X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --- BME680 Settings ---
|
||||
|
||||
#include <bme68xLibrary.h>
|
||||
Bme68x bme;
|
||||
// TwoWire BME68X_I2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1)
|
||||
// #include <DFRobot_BME680.h> // BME680 library
|
||||
// DFRobot_BME680_I2C bme680(0x76); // 0x76
|
||||
// #include <Adafruit_Sensor.h>
|
||||
// #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);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <BME280I2C.h>
|
||||
//#include <Wire.h>
|
||||
#include "Arduino.h"
|
||||
#include <bme68xLibrary.h>
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
// #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 <bme68xLibrary.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <BME280I2C.h>
|
||||
//#include <Wire.h>
|
||||
#include "Arduino.h"
|
||||
#include <bme68xLibrary.h>
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <BME280I2C.h>
|
||||
//#include <Wire.h>
|
||||
#include "Arduino.h"
|
||||
#include <bme68xLibrary.h>
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <BME280I2C.h>
|
||||
//#include <Wire.h>
|
||||
#include "Arduino.h"
|
||||
#include <bme68xLibrary.h>
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
#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 <bme68xLibrary.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr",
|
||||
"requires": [
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
#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 <bme68xLibrary.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <HardwareSerial.h>
|
||||
|
||||
#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 <bme68xLibrary.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <bme68xLibrary.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <bme68xLibrary.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee_zczr,ZigbeeMode=zczr",
|
||||
"requires": [
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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 <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#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++;
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// https://www.14core.com/wiring-the-telaire-t6713-t67xx-a-carbon-dioxide-co2-sensor/
|
||||
|
||||
#include <Wire.h> //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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue