From 631e7c590f9f93e5c0c1912e783a49bb43e6a35c Mon Sep 17 00:00:00 2001 From: Bora Date: Sun, 28 Dec 2025 15:37:05 +0100 Subject: [PATCH] Initial commit of existing code --- .gitignore | 3 + .../Node16_bme680_t6713_router_v2.ino | 413 +++++++++ .../Node17_bme680_scd41_t6713_c4001_v1.ino | 786 ++++++++++++++++++ sketch_nov30e/sketch_nov30e.ino | 96 +++ 4 files changed, 1298 insertions(+) create mode 100644 .gitignore create mode 100644 Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino create mode 100644 Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino create mode 100644 sketch_nov30e/sketch_nov30e.ino diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c1bef2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.hex +build/ +.DS_Store diff --git a/Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino b/Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino new file mode 100644 index 0000000..018ab1f --- /dev/null +++ b/Node16_bme680_t6713_router_v2/Node16_bme680_t6713_router_v2.ino @@ -0,0 +1,413 @@ +// DFRobot Beetle ESP32-C6 Partition Scheme: Zigbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZR/ZC (coordinator,router) +// LED: GPIO15, on when HIGH + + +// DFRobot FireBeetle2 ESP32-C6 +// Partition Scheme: Zigbee ZCZR 4MB with spiffs +// Zigbee Mode: Zigbee ZR/ZC (coordinator,router) +// LED: LED_BUILTIN, on when HIGH +// Node16: BME680 + T6713 only + +#ifndef ZIGBEE_MODE_ZCZR +#error Zigbee coordinator/router mode is not selected in Tools->Zigbee mode +#endif + +#define DEBUG_TRACE // Comment out DEBUG_TRACE to reduce normal-path logging + +#include "Zigbee.h" +#include "Wire.h" +#include "bme68xLibrary.h" + +// ----------------------------------------------------------------------------- +// Hardware definitions (shared I2C bus) +// ----------------------------------------------------------------------------- + +#define LED_PIN LED_BUILTIN +#define I2C_SDA_PIN 17 +#define I2C_SCL_PIN 16 + +#define POWER_PIN 21 // GPIO pin to power the sensor + +// T6713 I2C address and registers +#define T6713_ADDR 0x15 +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +// Endpoint numbers (BME680 + T6713 only) +#define BME_TEMP_ENDPOINT 10 +#define BME_ANALOG_ENDPOINT 11 +#define T6713_CO2_ENDPOINT 12 + +// Sensor objects (BME680 + T6713 only) +Bme68x bme; +ZigbeeTempSensor zbTempSensorBME(BME_TEMP_ENDPOINT); +ZigbeeAnalog zbAnalogBME(BME_ANALOG_ENDPOINT); +ZigbeeCarbonDioxideSensor zbCo2T6713(T6713_CO2_ENDPOINT); + +// ----------------------------------------------------------------------------- +// Health watchdog globals (BME + T6713 only) +// ----------------------------------------------------------------------------- + +SemaphoreHandle_t i2cMutex; +bool bmeFirstOk = false; +bool t6713FirstOk = false; + +// Last-change tracking (BME + T6713 only) +float lastTempBme = NAN, lastHumBme = NAN, lastGasRes = NAN; +unsigned long lastTempBmeChangeMs = 0, lastHumBmeChangeMs = 0, lastGasResChangeMs = 0; +int lastCo2T6713 = -1; +unsigned long lastCo2T6713ChangeMs = 0; +unsigned long lastZigbeeOkMs = 0; + +// Error counters (BME + T6713 only) +int bmeErrorCount = 0, t6713ErrorCount = 0; +const int maxI2cErrors = 10; + +// Watchdog thresholds +const unsigned long WATCHDOG_PERIOD_MS = 10000; // 10s +const unsigned long SENSOR_STUCK_TIMEOUT_MS = 30UL * 60UL * 1000UL; // 30min +const unsigned long ZIGBEE_DOWN_TIMEOUT_MS = 10UL * 60UL * 1000UL; // 10min + +// ----------------------------------------------------------------------------- +// Zigbee health touch after successful reports +// ----------------------------------------------------------------------------- + +inline void zigbeeHealthTouch() { + if (Zigbee.connected()) lastZigbeeOkMs = millis(); +} + +// ----------------------------------------------------------------------------- +// Helper: I2C guarded execution (use mutex) +// ----------------------------------------------------------------------------- + +#include +bool withI2C(std::function fn, uint32_t timeoutMs = 100) { + if (xSemaphoreTake(i2cMutex, pdMS_TO_TICKS(timeoutMs)) == pdTRUE) { + bool ok = fn(); + xSemaphoreGive(i2cMutex); + return ok; + } + return false; +} + +// ----------------------------------------------------------------------------- +// T6713 helper functions (unchanged) +// ----------------------------------------------------------------------------- + +int readT6713() { + int result = -1; + bool ok = withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); Wire.write(0x8B); // 0x138B + Wire.write(0x00); Wire.write(0x01); + if (Wire.endTransmission() != 0) return false; + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() >= 4) { + Wire.read(); Wire.read(); // skip func+len + byte high = Wire.read(); + byte low = Wire.read(); + result = (high << 8) | low; + return true; + } + return false; + }); + if (!ok) result = -1; + return result; +} + +void configureT6713(bool enableABC) { + delay(1000); + // Optional status check + withI2C([&]() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); Wire.write(0x13); Wire.write(0x8A); // 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() >= 4) { + Wire.read(); Wire.read(); + uint16_t status = (Wire.read() << 8) | Wire.read(); +#ifdef DEBUG_TRACE + if (status == 0x08) Serial.println("T6713 Warming up..."); +#endif + } + return true; + }); + + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + withI2C([&]() -> bool { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + byte error = Wire.endTransmission(); + if (error == 0) { +#ifdef DEBUG_TRACE + Serial.print("T6713 ABC Logic set to "); Serial.println(enableABC ? "ON" : "OFF"); +#endif + } else { +#ifdef DEBUG_TRACE + Serial.println("T6713 Failed to set ABC Logic"); +#endif + } + return (error == 0); + }); + delay(100); +} + +// ----------------------------------------------------------------------------- +// BME68x task (endpoint 10/11) +// ----------------------------------------------------------------------------- + +static void bme680sensorvalueupdate(void *arg) { + for (;;) { + float temperature = NAN, humidity = NAN, gasResistance = NAN; + bme68xData data; + bool ok = withI2C([&]() { + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + if (bme.fetchData()) { + bme.getData(data); + temperature = data.temperature; + humidity = data.humidity; + gasResistance = data.gas_resistance; + return true; + } + return false; + }); + + if (ok) { + bmeErrorCount = 0; + unsigned long now = millis(); + if (!bmeFirstOk) { + bmeFirstOk = true; + lastTempBme = temperature; lastHumBme = humidity; lastGasRes = gasResistance; + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = now; + } else { + if (temperature != lastTempBme) { lastTempBme = temperature; lastTempBmeChangeMs = now; } + if (humidity != lastHumBme) { lastHumBme = humidity; lastHumBmeChangeMs = now; } + if (gasResistance != lastGasRes) { lastGasRes = gasResistance; lastGasResChangeMs = now; } + } + + zbTempSensorBME.setTemperature(temperature); + zbTempSensorBME.setHumidity(humidity); + zigbeeHealthTouch(); + + zbAnalogBME.setAnalogInput(round(gasResistance)); + zigbeeHealthTouch(); + +#ifdef DEBUG_TRACE + Serial.printf("BME68x T:%.2fC H:%.2f%% Gas:%.2f ohm\n", temperature, humidity, gasResistance); +#endif + } else { + bmeErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("BME68x read error or I2C busy."); +#endif + if (bmeErrorCount >= maxI2cErrors) { + Serial.println("BME68x too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// T6713 task (endpoint 15) +// ----------------------------------------------------------------------------- + +static void t6713sensorvalueupdate(void *arg) { + for (;;) { + int co2t6713 = readT6713(); + if (co2t6713 >= 0) { + t6713ErrorCount = 0; + unsigned long now = millis(); + if (!t6713FirstOk) { + t6713FirstOk = true; + lastCo2T6713 = co2t6713; + lastCo2T6713ChangeMs = now; + } else if (co2t6713 != lastCo2T6713) { + lastCo2T6713 = co2t6713; + lastCo2T6713ChangeMs = now; +#ifdef DEBUG_TRACE + Serial.print("T6713 CO2: "); Serial.print(co2t6713); Serial.println(" ppm"); +#endif + } + + zbCo2T6713.setCarbonDioxide(co2t6713); + zigbeeHealthTouch(); + } else { + t6713ErrorCount++; +#ifdef DEBUG_TRACE + Serial.println("T6713 read error."); +#endif + if (t6713ErrorCount >= maxI2cErrors) { + Serial.println("T6713 too many errors, restarting..."); + delay(200); ESP.restart(); + } + } + vTaskDelay(pdMS_TO_TICKS(10000)); // 10s + } +} + +// ----------------------------------------------------------------------------- +// Watchdog task (BME + T6713 only) +// ----------------------------------------------------------------------------- + +void watchdogTask(void *param) { + for (;;) { +#ifdef DEBUG_TRACE + Serial.println("Watchdog ran."); +#endif + unsigned long now = millis(); + bool zigbeeBad = !Zigbee.connected() || (now - lastZigbeeOkMs > ZIGBEE_DOWN_TIMEOUT_MS); + bool bmeStuck = bmeFirstOk && ( + (now - lastTempBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastHumBmeChangeMs > SENSOR_STUCK_TIMEOUT_MS) || + (now - lastGasResChangeMs > SENSOR_STUCK_TIMEOUT_MS)); + bool t6713Stuck = t6713FirstOk && (now - lastCo2T6713ChangeMs > SENSOR_STUCK_TIMEOUT_MS); + + if (zigbeeBad || bmeStuck || t6713Stuck) { + Serial.println("Watchdog fault detected, restarting..."); + delay(500); ESP.restart(); + } + vTaskDelay(pdMS_TO_TICKS(WATCHDOG_PERIOD_MS)); + } +} + +// ----------------------------------------------------------------------------- +// setup +// ----------------------------------------------------------------------------- + +void setup() { + Serial.begin(115200); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + + pinMode(POWER_PIN, OUTPUT); + digitalWrite(POWER_PIN, HIGH); // Power on the sensor(s) + + delay(100); + + // I2C init + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + i2cMutex = xSemaphoreCreateMutex(); + + // BME680 init + Serial.println("Connecting to BME680..."); + bme.begin(BME68X_I2C_ADDR_LOW, Wire); // BME68X_I2C_ADDR_LOW, BME68X_I2C_ADDR_HIGH + if (bme.checkStatus() == BME68X_ERROR) { + Serial.println("❌ BME68X_ERROR: " + bme.statusString()); + } else if (bme.checkStatus() == BME68X_WARNING) { + Serial.println("⚠️ BME68X_WARNING: " + bme.statusString()); + } else { + Serial.println("✓ BME68X status OK"); + } + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + bme.setHeaterProf(300, 100); + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensorBME.setManufacturerAndModel("Espressif", "Node16_bme680th"); + zbTempSensorBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbTempSensorBME.setMinMaxValue(-20, 80); + zbTempSensorBME.setTolerance(1); + zbTempSensorBME.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensorBME); + + zbAnalogBME.setManufacturerAndModel("Espressif", "Node16_bme680r"); + zbAnalogBME.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbAnalogBME.addAnalogInput(); + Zigbee.addEndpoint(&zbAnalogBME); + + // T6713 config & endpoint + configureT6713(true); // Enable ABC + zbCo2T6713.setManufacturerAndModel("Espressif", "Node16_t6713"); + zbCo2T6713.setPowerSource(ZB_POWER_SOURCE_MAINS); + zbCo2T6713.setMinMaxValue(0, 10000); + Zigbee.addEndpoint(&zbCo2T6713); + + // Start Zigbee as router + Serial.println("Starting Zigbee..."); + if (!Zigbee.begin(ZIGBEE_ROUTER)) { + Serial.println("Zigbee failed to start! Rebooting..."); + ESP.restart(); + } + Serial.println("Zigbee started successfully! Connecting to network..."); + bool ledState = false; + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + if (millis() - startTime > timeoutMs) { + Serial.println(" timed out (60s). Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, LOW); + Serial.println(" connected!"); + lastZigbeeOkMs = millis(); + + // Create sensor tasks + xTaskCreate(bme680sensorvalueupdate, "bme_task", 4096, NULL, 10, NULL); + xTaskCreate(t6713sensorvalueupdate, "t6713_task", 4096, NULL, 10, NULL); + xTaskCreate(watchdogTask, "watchdog", 4096, NULL, 5, NULL); + + // Reporting configuration (after Zigbee.begin) + zbTempSensorBME.setReporting(60, 0, 0.5); + zbAnalogBME.setAnalogInputReporting(60, 600, 10); + zbCo2T6713.setReporting(30, 300, 10); +} + +// ----------------------------------------------------------------------------- +// loop (light - button reset + test commands) +// ----------------------------------------------------------------------------- + +void loop() { + // Test commands via Serial + if (Serial.available()) { + char cmd = Serial.read(); + switch (cmd) { + case 'Z': // Force Zigbee failure (watchdog test) + Serial.println("SIM Zigbee disconnect test"); + lastZigbeeOkMs = 0; // Watchdog sees Zigbee down + break; + case 'E': // Force stuck sensor detection + Serial.println("SIM Stuck sensor test"); + lastTempBmeChangeMs = lastHumBmeChangeMs = lastGasResChangeMs = 0; + lastCo2T6713ChangeMs = 0; + break; + case 'R': // Manual restart + Serial.println("SIM Manual restart"); + ESP.restart(); + break; + } + } + + // Factory reset on long button press + static uint8_t button = BOOT_PIN; + if (digitalRead(button) == LOW) { // push button pressed + delay(100); // debounce + int startTime = millis(); + while (digitalRead(button) == LOW) { + delay(50); + if (millis() - startTime > 3000) { + Serial.println("Resetting Zigbee to factory and rebooting in 1s."); + delay(1000); + Zigbee.factoryReset(); + ESP.restart(); + } + } + } + + vTaskDelay(pdMS_TO_TICKS(50)); +} diff --git a/Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino b/Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino new file mode 100644 index 0000000..b1d432f --- /dev/null +++ b/Node17_bme680_scd41_t6713_c4001_v1/Node17_bme680_scd41_t6713_c4001_v1.ino @@ -0,0 +1,786 @@ + +#ifndef ZIGBEE_MODE_ED +#error "Zigbee end device mode is not selected in Tools->Zigbee mode" +#endif + +#include "Zigbee.h" + +#define LED_PIN 15 + + +/* Zigbee occupancy sensor configuration */ +#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10 +uint8_t button = BOOT_PIN; +uint8_t sensor_pin = 4; + +ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); + + +#include "DFRobot_C4001.h" + +HardwareSerial RadarSerial(1); +DFRobot_C4001_UART radar(&RadarSerial, 9600, /*rx*/17, /*tx*/16); // ESP32-C6 pins + +eMode_t currentMode = eExitMode; // 0=presence, 1=speed +unsigned long lastSpeedReport = 0; +bool lastOccupancy = false; +unsigned long occupancyStartTime = 0; +const unsigned long OCCUPANCY_TIMEOUT = 4; // 4 -> 2 seconds - adjust as needed +const unsigned long TRIGGER_DELAY = 10; // 10 -> 100 ms + + + + + + +// Define your custom SCL/SDA pins +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin +// Create custom I2C instance +// TwoWire sharedI2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) + + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER 11 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER); + +// #include +// // DFRobot_SCD4X SCD4X(&Wire, /*i2cAddr = */SCD4X_I2C_ADDR); +// // SCD41 with custom I2C +// DFRobot_SCD4X SCD4X(&sharedI2C, SCD4X_I2C_ADDR); + +#include +#include +#include + +SensirionI2cScd4x scd41; + + + + + +#define TEMP_SENSOR_ENDPOINT_NUMBER 12 +ZigbeeTempSensor zbTempSensor_SCD4X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); + + + + + + + +// --- BME680 Settings --- + +#include +Bme68x bme; +// TwoWire BME68X_I2C = TwoWire(0); // I2C0 (or TwoWire(1) for I2C1) +// #include // BME680 library +// DFRobot_BME680_I2C bme680(0x76); // 0x76 +// #include +// #include "Adafruit_BME680.h" +// Adafruit_BME680 bme680; +unsigned long bme_report_time = millis(); + +#define TEMP_SENSOR_ENDPOINT_NUMBER 13 +ZigbeeTempSensor zbTempSensor_BME68X = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER); +#define ANALOG_DEVICE_ENDPOINT_NUMBER 14 +ZigbeeAnalog zbAnalogDevice_BME68X = ZigbeeAnalog(ANALOG_DEVICE_ENDPOINT_NUMBER); + + + + + + +// --- T6713 Settings --- +#define T6713_ADDR 0x15 +// T6713 Register Addresses (Modbus) +#define T6713_REG_ABC_LOGIC 0x03EE +#define T6713_REG_STATUS 0x138A + +unsigned long t6713_report_time = millis(); + +#define CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713 15 +ZigbeeCarbonDioxideSensor zbCarbonDioxideSensor_T6713 = ZigbeeCarbonDioxideSensor(CARBON_DIOXIDE_SENSOR_ENDPOINT_NUMBER_T6713); + + + + + + + +void setPresenceMode() { + radar.setSensorMode(eExitMode); + currentMode = eExitMode; + Serial.println("Switched to PRESENCE mode"); + // Presence mode settings from sample + // radar.setDetectionRange(30, 1000, 1000); // min,max,trig (cm) + // radar.setTrigSensitivity(1); + // radar.setKeepSensitivity(2); + // radar.setDelay(100, 4); // trig,keep + + + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500) + * trig Detection range Maximum distance, unit cm, default trig = max + */ + if(radar.setDetectionRange(/*min*/30, /*max*/500, /*trig*/500)){ + Serial.println("set detection range successfully!"); + } + // set trigger sensitivity 0 - 9 + if(radar.setTrigSensitivity(8)){ + Serial.println("set trig sensitivity successfully!"); + } + + // set keep sensitivity 0 - 9 + if(radar.setKeepSensitivity(8)){ + Serial.println("set keep sensitivity successfully!"); + } + /* + * trig Trigger delay, unit 0.01s, range 0~2s (0~200) + * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000) + */ + if(radar.setDelay(/*trig*/TRIGGER_DELAY, /*keep*/OCCUPANCY_TIMEOUT)){ + Serial.println("set delay successfully!"); + } + + + // get confige params + Serial.print("trig sensitivity = "); + Serial.println(radar.getTrigSensitivity()); + Serial.print("keep sensitivity = "); + Serial.println(radar.getKeepSensitivity()); + + Serial.print("min range = "); + Serial.println(radar.getMinRange()); + Serial.print("max range = "); + Serial.println(radar.getMaxRange()); + Serial.print("trig range = "); + Serial.println(radar.getTrigRange()); + + Serial.print("keep time = "); + Serial.println(radar.getKeepTimerout()); + + Serial.print("trig delay = "); + Serial.println(radar.getTrigDelay()); + + + +} + + + + + + + +void setSpeedMode() { + radar.setSensorMode(eSpeedMode); + currentMode = eSpeedMode; + Serial.println("Switched to SPEED mode"); + // Speed mode settings from sample + // radar.setDetectThres(11, 1200, 10); // min,max,thres (cm) + // radar.setFrettingDetection(eON); + + + + + sSensorStatus_t data; + data = radar.getStatus(); + // 0 stop 1 start + Serial.print("work status = "); + Serial.println(data.workStatus); + + // 0 is exist 1 speed + Serial.print("work mode = "); + Serial.println(data.workMode); + + // 0 no init 1 init success + Serial.print("init status = "); + Serial.println(data.initStatus); + Serial.println(); + + /* + * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal. + * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500) + * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535) + */ + if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) { + Serial.println("set detect threshold successfully"); + } + + // set Fretting Detection + radar.setFrettingDetection(eON); + + // get confige params + Serial.print("min range = "); + Serial.println(radar.getTMinRange()); + Serial.print("max range = "); + Serial.println(radar.getTMaxRange()); + Serial.print("threshold range = "); + Serial.println(radar.getThresRange()); + Serial.print("fretting detection = "); + Serial.println(radar.getFrettingDetection()); + +} + + + +void handleSerialCommands() { + while (Serial.available()) { + char cmd = Serial.read(); + if (cmd == 'P' || cmd == 'p') { + setPresenceMode(); + } else if (cmd == 'S' || cmd == 's') { + setSpeedMode(); + } + } + +} + +void setup() { + Serial.begin(115200); + + pinMode(LED_PIN, OUTPUT); + bool ledState = false; + digitalWrite(LED_PIN, HIGH); + + + // while (!Serial); + // unsigned long start = millis(); + // while (!Serial && millis() - start < 3000); + delay(100); + + RadarSerial.begin(9600, SERIAL_8N1, 17, 16); // C4001 UART (RX=16, TX=17) + + while (!radar.begin()) { + Serial.println("NO Device found!"); + delay(1000); + } + Serial.println("C4001 connected!"); + + // Start in presence mode + setPresenceMode(); + Serial.println("Send 'P' for presence, 'S' for speed mode"); + + + + + + // Optional: set Zigbee device name and model + zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + zbOccupancySensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35); + + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbOccupancySensor); + + + + + + // Initialize custom I2C with YOUR pins + // SCD41_I2C.begin(SCD41_SDA_PIN, SCD41_SCL_PIN, 100000); // 100kHz standard + // Initialize SHARED I2C bus ONCE + // sharedI2C.begin(I2C_SDA_PIN, I2C_SCL_PIN, 100000); + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); + scd41.begin(Wire, SCD41_I2C_ADDR_62); + + // while( !SCD4X.begin() ){ + // Serial.println("Communication with device failed, please check connection"); + // delay(3000); + // } + scd41.stopPeriodicMeasurement(); + Serial.println("SCD4x: Begin ok!"); + scd41.startPeriodicMeasurement(); + + // SCD4X.setTempComp(4.0); + // float temp = 0; + // temp = SCD4X.getTempComp(); + // Serial.print("The current temperature compensation value : "); + // Serial.print(temp); + // Serial.println(" C"); + + // SCD4X.setSensorAltitude(540); + // uint16_t altitude = 0; + // altitude = SCD4X.getSensorAltitude(); + // Serial.print("Set the current environment altitude : "); + // Serial.print(altitude); + // Serial.println(" m"); + + // SCD4X.enablePeriodMeasure(SCD4X_START_PERIODIC_MEASURE); + + zbCarbonDioxideSensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor_Node17"); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor); + + // Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement) + zbTempSensor_SCD4X.setMinMaxValue(10, 50); + // Optional: Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C) + zbTempSensor_SCD4X.setTolerance(1); + // Optional: Time cluster configuration (default params, as this device will revieve time from coordinator) + // zbTempSensor.addTimeCluster(); + // Add humidity cluster to the temperature sensor device with min, max and tolerance values + zbTempSensor_SCD4X.addHumiditySensor(0, 100, 1); + // Add endpoint to Zigbee Core + Zigbee.addEndpoint(&zbTempSensor_SCD4X); + + + + + + + Serial.println("Connecting to BME680..."); + + // // Init BME680 + // if (bme680.begin(sharedI2C) != 0) { + // Serial.println("BME680 init failed!"); + // } else { + // Serial.println("BME680 ready!"); + // } + // Wire.begin(SCD41_SDA_PIN, SCD41_SCL_PIN); + // Wire.setClock(100000); // Set I2C clock speed to 100kHz + // // Initialize the BME680 + // bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme.begin(BME68X_I2C_ADDR_HIGH, &BME68X_I2C); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + // bme680.begin() + // // Set up the BME680 + // // bme.setGasStatus(BME680_ENABLE_GAS_MEAS); + // // bme.setOversampling(T2, OS_2X); + // // bme.setOversampling(T1, OS_16X); + // // bme.setOversampling(H1, OS_2X); + // // bme.setFilter(FILTER_SIZE_3); + // // bme.setGasSettings(320, 25, 0x4, 130, 410, 4, 0x01, 0x10, 0); + // if(bme.checkStatus()) + // { + // if (bme.checkStatus() == BME68X_ERROR) + // { + // Serial.println("Sensor error:" + bme.statusString()); + // return; + // } + // else if (bme.checkStatus() == BME68X_WARNING) + // { + // Serial.println("Sensor Warning:" + bme.statusString()); + // } + // } + // /* Set the default configuration for temperature, pressure and humidity */ + // bme.setTPH(); + // /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + // bme.setHeaterProf(300, 100); + + // bme68xData data; + // bme.setOpMode(BME68X_FORCED_MODE); + + + // Note the syntax: .begin(Address, TwoWirePointer) + // if (!bme680.begin(0x77, &sharedI2C)) { + // Serial.println("BME680 not found at 0x77, trying 0x76..."); + // if (!bme680.begin(0x76, &sharedI2C)) { + // Serial.println("BME680 Init Failed! Check wiring."); + // while (1); + // } + // } + // Serial.println("BME680 initialized via TwoWire."); + // // BME680 Settings + // bme680.setTemperatureOversampling(BME680_OS_8X); + // bme680.setHumidityOversampling(BME680_OS_2X); + // bme680.setPressureOversampling(BME680_OS_4X); + // bme680.setIIRFilterSize(BME680_FILTER_SIZE_3); + // bme680.setGasHeater(320, 150); + + bme.begin(BME68X_I2C_ADDR_HIGH, Wire); // BME68X_I2C_ADDR_HIGH=0x76, BME68X_I2C_ADDR_LOW=0x77 + /* Set the default configuration for temperature, pressure and humidity */ + // setTPH(uint8_t os_temp, uint8_t os_pres, uint8_t os_hum); BME68X_OS_NONE, BME68X_OS_1X, BME68X_OS_2X, BME68X_OS_4X, BME68X_OS_8X, BME68X_OS_16X + bme.setTPH(BME68X_OS_8X, BME68X_OS_2X, BME68X_OS_8X); + /* Set the heater configuration to 300 deg C for 100ms for Forced mode */ + bme.setHeaterProf(300, 100); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + + zbTempSensor_BME68X.setMinMaxValue(-20, 80); + zbTempSensor_BME68X.setTolerance(1); + zbTempSensor_BME68X.addHumiditySensor(0, 100, 1); + Zigbee.addEndpoint(&zbTempSensor_BME68X); + + + // Set analog resolution to 10 bits + // analogReadResolution(10); + // Add analog clusters to Zigbee Analog according your needs + zbAnalogDevice_BME68X.addAnalogInput(); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbAnalogDevice_BME68X); + + + + + + + + // TRUE = Normal Home/Office use + // FALSE = Greenhouse / Constantly occupied + configureT6713(true); + + // Set minimum and maximum carbon dioxide measurement value in ppm + zbCarbonDioxideSensor_T6713.setMinMaxValue(0, 1500); + // Add endpoints to Zigbee Core + Zigbee.addEndpoint(&zbCarbonDioxideSensor_T6713); + + + + + + + + Serial.println("Starting Zigbee..."); + // When all EPs are registered, start Zigbee in End Device mode + esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG(); + // Increase keep-alive to 5 seconds (default is often 3000ms) + zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 5000; + // zigbeeConfig.nwk_cfg.zed_cfg.ed_timeout = ESP_ZB_ED_AGING_TIMEOUT_256MIN; // 4 hours; How long the parent remembers this device. + + // 1. Our custom config (zigbeeConfig) + // 2. false = Do NOT erase NVS (keep network credentials) + // 3. true = Start automatically (optional, defaults to true) + if (!Zigbee.begin(&zigbeeConfig, false)) { + Serial.println("Zigbee failed to start!"); + Serial.println("Rebooting..."); + ESP.restart(); + } else { + Serial.println("Zigbee started successfully!"); + } + Serial.println("Connecting to network"); + // while (!Zigbee.connected()) { + // Serial.print("."); + // delay(100); + // } + // Record the start time + unsigned long startTime = millis(); + const unsigned long timeoutMs = 60000; // 120 seconds + while (!Zigbee.connected()) { + Serial.print("."); + ledState = !ledState; + digitalWrite(LED_PIN, ledState); + delay(100); + + // Check if 120 seconds have passed + if (millis() - startTime > timeoutMs) { + Serial.println("\nConnection timed out (120s). Restarting..."); + ESP.restart(); + } + } + digitalWrite(LED_PIN, LOW); + Serial.println("\nZigbee connected!"); + Serial.println(); + + + // Set reporting interval for carbon dioxide measurement to be done every 30 seconds, must be called after Zigbee.begin() + // min_interval and max_interval in seconds, delta (carbon dioxide change in ppm) + // if min = 1 and max = 0, reporting is sent only when carbon dioxide changes by delta + // if min = 0 and max = 10, reporting is sent every 10 seconds or when carbon dioxide changes by delta + // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change + zbCarbonDioxideSensor.setReporting(0, 30, 0); + zbTempSensor_SCD4X.setReporting(1, 0, 1); + zbTempSensor_BME68X.setReporting(1, 0, 1); + // zbAnalogDevice.setAnalogInputReporting(0, 30, 10); // report every 30 seconds if value changes by 10 + +} + + + + +void loop() { + // handleSerialCommands(); + + // // Remove if (radar.available()) - just read directly + // sSensorStatus_t status = radar.getStatus(); // Always safe to call + + // Serial.print("Status: work="); + // Serial.print(status.workStatus); + // Serial.print(", mode="); + // Serial.print(status.workMode); + // Serial.print(", init="); + // Serial.println(status.initStatus); + + + if (currentMode == eExitMode) { + // PRESENCE MODE + // static bool occupancy = false; + // bool occupancyNow = radar.motionDetection(); + // Serial.println(occupancyNow); + // // if (radar.motionDetection() == 1 && !occupancy) { + // if (occupancyNow != lastOccupancy) { + // Serial.println("MOTION DETECTED"); + // zbOccupancySensor.setOccupancy(occupancyNow); + // zbOccupancySensor.report(); + // // occupancy = true; + // lastOccupancy = occupancyNow; + // // } else if (radar.motionDetection() == 0 && occupancy) { + // // } else if (radar.motionDetection() == 0) { + // // Serial.println("MOTION ENDED"); + // // zbOccupancySensor.setOccupancy(false); + // // zbOccupancySensor.report(); + // // occupancy = false; + // } + // PRESENCE MODE - proper state machine + bool motionNow = radar.motionDetection(); + // Serial.println(motionNow); + // Serial.println(lastOccupancy); + // Serial.println(millis() - occupancyStartTime); + + if (motionNow && !lastOccupancy) { + // Motion STARTED → Set occupancy ON + Serial.println("MOTION DETECTED → OCCUPANCY ON"); + lastOccupancy = true; + occupancyStartTime = millis(); + zbOccupancySensor.setOccupancy(true); + zbOccupancySensor.report(); + + } else if (motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion still present → timeout reset"); + occupancyStartTime = millis(); + + } else if (!motionNow && lastOccupancy && (millis() - occupancyStartTime > OCCUPANCY_TIMEOUT*1000/2)) { + // TIMEOUT → Clear occupancy + Serial.println("OCCUPANCY TIMEOUT → OFF"); + lastOccupancy = false; + zbOccupancySensor.setOccupancy(false); + zbOccupancySensor.report(); + + } else if (!motionNow && lastOccupancy) { + // Motion ENDED → Start timeout timer + // Serial.println("Motion ended → timeout started"); + // occupancyStartTime = millis(); + } + + } else if (currentMode == eSpeedMode) { + // SPEED MODE + Serial.print("Targets: "); + Serial.print(radar.getTargetNumber()); + Serial.print(" | Speed: "); + Serial.print(radar.getTargetSpeed(), 2); + Serial.print(" m/s | Range: "); + Serial.print(radar.getTargetRange(), 2); + Serial.print(" m | Energy: "); + Serial.println(radar.getTargetEnergy()); + } + + + + // --- Read SCD41 --- + uint16_t co2_scd = 0; + float temperature_scd = 0.0f; + float humidity_scd = 0.0f; + bool scdReady = false; + + uint16_t error = scd41.readMeasurement(co2_scd, temperature_scd, humidity_scd); + if (error == 0 && co2_scd != 0) { + scdReady = true; + } + + if (scdReady) { + Serial.print("[SCD41] CO2: "); Serial.print(co2_scd); Serial.print(" ppm"); + Serial.print(" | Temp: "); Serial.print(temperature_scd); Serial.print(" C"); + Serial.print(" | Hum: "); Serial.print(humidity_scd); Serial.println(" %"); + + zbCarbonDioxideSensor.setCarbonDioxide(co2_scd); + zbCarbonDioxideSensor.report(); + + // Update temperature and humidity values in Temperature sensor EP + zbTempSensor_SCD4X.setTemperature(temperature_scd); + zbTempSensor_SCD4X.setHumidity(humidity_scd); + // Report temperature and humidity values + zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + } + // else { + // Serial.println("[SCD41] Waiting for measurement..."); + // } + + + // if(SCD4X.getDataReadyStatus()) { + // DFRobot_SCD4X::sSensorMeasurement_t data; + // SCD4X.readMeasurement(&data); + + // Serial.print("Carbon dioxide concentration : "); + // Serial.print(data.CO2ppm); + // Serial.println(" ppm"); + + // Serial.print("Environment temperature : "); + // Serial.print(data.temp); + // Serial.println(" C"); + + // Serial.print("Relative humidity : "); + // Serial.print(data.humidity); + // Serial.println(" RH"); + + // Serial.println(); + + // zbCarbonDioxideSensor.setCarbonDioxide(data.CO2ppm); + // zbCarbonDioxideSensor.report(); + + // // Update temperature and humidity values in Temperature sensor EP + // zbTempSensor_SCD4X.setTemperature(data.temp); + // zbTempSensor_SCD4X.setHumidity(data.humidity); + // // Report temperature and humidity values + // zbTempSensor_SCD4X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + // // Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity); + + // Serial.print("SCD41 reported."); + + + // } + + + // Serial.println("---------------------------"); + + float bme_temperature(NAN), bme_humidity(NAN), bme_pressure(NAN), bme_gasResistance(NAN); + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); + delayMicroseconds(bme.getMeasDur()); + // delay(bme.getMeasDur(BME68X_FORCED_MODE) / 1000 + 50); + if (bme.fetchData() && (millis() - bme_report_time > 5000)) { + bme.getData(data); + bme_temperature = data.temperature; // Temperature in °C + bme_humidity = data.humidity; // Humidity in % + bme_pressure = data.pressure; // Pressure in hPa + bme_gasResistance = data.gas_resistance; // Gas resistance in ohms + // errorCount = 0; // Reset error count on successful read + Serial.printf("[BME680] temperature: %.2f°C, Humidity: %.2f%%, Gas Resistance: %.2f ohms\r\n", bme_temperature, bme_humidity, bme_gasResistance); + + zbTempSensor_BME68X.setTemperature(bme_temperature); + zbTempSensor_BME68X.setHumidity(bme_humidity); + // Report temperature and humidity values + zbTempSensor_BME68X.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported) + + zbAnalogDevice_BME68X.setAnalogInput(bme_gasResistance); + zbAnalogDevice_BME68X.reportAnalogInput(); + + digitalWrite(LED_PIN, HIGH); + delay(50); + digitalWrite(LED_PIN, LOW); + + // Serial.print("BME68X reported."); + bme_report_time = millis(); + } + // else { + // Serial.println("BME680 -> Waiting..."); + // } + + + + + + // --- Read T6713 (CO2) --- + int co2_t6713 = readT6713(); + if ((co2_t6713 >= 0) && (millis() - t6713_report_time > 5000)) { + Serial.print("T6713 | CO2: "); Serial.print(co2_t6713); Serial.println(" ppm"); + zbCarbonDioxideSensor_T6713.setCarbonDioxide(co2_t6713); + zbCarbonDioxideSensor_T6713.report(); + t6713_report_time = millis(); + } + // else { + // Serial.println("T6713 | Read Error"); + // } + + + delay(100); +} + + + + + + +// Helper function for T6713 +int readT6713() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); // Address High + Wire.write(0x8B); // Address Low + Wire.write(0x00); + Wire.write(0x01); // Length (1 register) + if (Wire.endTransmission() != 0) return -1; + + delay(10); // Processing delay + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Skip Func & Len + byte high = Wire.read(); + byte low = Wire.read(); + return (high << 8) | low; + } + return -1; +} + + +void configureT6713(bool enableABC) { + // 1. Wait for Sensor Warm-up (at least 500ms after power on, datasheet says much longer for accuracy) + delay(1000); + + // 2. Check Status Register (Optional but good practice) + // We read register 0x138A (5002) to check for errors/warmup + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); + Wire.write(0x13); Wire.write(0x8A); // Address 0x138A + Wire.write(0x00); Wire.write(0x01); + Wire.endTransmission(); + delay(10); + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Func, Len + uint16_t status = (Wire.read() << 8) | Wire.read(); + // Bit 3 is Warm-up mode. If 1, sensor is still warming up. + if (status & 0x08) { + Serial.println("T6713: Warming up..."); + } + } + + // 3. Configure ABC Logic (Automatic Background Calibration) + // Write to Register 0x03EE (1006). Value: 0xFF00 = Enable, 0x0000 = Disable + uint16_t abcValue = enableABC ? 0xFF00 : 0x0000; + + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x05); // Function: Write Single Coil + Wire.write(highByte(T6713_REG_ABC_LOGIC)); + Wire.write(lowByte(T6713_REG_ABC_LOGIC)); + Wire.write(highByte(abcValue)); + Wire.write(lowByte(abcValue)); + + byte error = Wire.endTransmission(); + if (error == 0) { + Serial.print("T6713: ABC Logic set to "); + Serial.println(enableABC ? "ON" : "OFF"); + } else { + Serial.println("T6713: Failed to set ABC Logic"); + } + + // 4. Wait for the write to "stick" + delay(100); +} + diff --git a/sketch_nov30e/sketch_nov30e.ino b/sketch_nov30e/sketch_nov30e.ino new file mode 100644 index 0000000..ec76e5e --- /dev/null +++ b/sketch_nov30e/sketch_nov30e.ino @@ -0,0 +1,96 @@ +#include + +// Default I2C Address for T6713 is 0x15 (decimal 21) +#define T6713_ADDR 0x15 +#define I2C_SCL_PIN 20 // Change to your SCL pin +#define I2C_SDA_PIN 6 // Change to your SDA pin + +#include +#ifndef BME68X_I2C_ADDR + #define BME68X_I2C_ADDR 0x76 // Change to 0x77 if sensor not found +#endif +Bme68x bme; + +void setup() { + Serial.begin(115200); + Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); // Join I2C bus + + Serial.println("Initializing Sensors..."); + + // 1. Initialize BME680 + bme.begin(BME68X_I2C_ADDR, Wire); + if(bme.checkStatus()) { + Serial.println("BME680 Error: " + bme.statusString()); + if (bme.checkStatus() == BME68X_ERROR) { + Serial.println("Check wiring or I2C address (0x76 vs 0x77)"); + while(1); // Halt if BME fails + } + } + Serial.println("BME680 Found!"); + + // Configure BME680 for "Forced Mode" (On-Demand) + bme.setTPH(); // Set default oversampling for Temp, Pres, Hum + + // Configure Heater for Gas Measurement (300°C for 100ms) + bme.setHeaterProf(300, 100); + + Serial.println("Sensors Ready. Starting Loop..."); + delay(2000); // Let sensor warm up +} + + + + +void loop() { + Serial.println("-----------------------------"); + + // --- Read T6713 (CO2) --- + int co2 = readT6713(); + if (co2 >= 0) { + Serial.print("T6713 | CO2: "); Serial.print(co2); Serial.println(" ppm"); + } else { + Serial.println("T6713 | Read Error"); + } + + // --- Read BME680 (Temp, Hum, Pres, Gas) --- + bme68xData data; + bme.setOpMode(BME68X_FORCED_MODE); // Trigger measurement + + // Wait for measurement to complete (depends on heater duration) + delay(bme.getMeasDur(BME68X_FORCED_MODE) / 1000 + 50); + + if (bme.fetchData()) { + bme.getData(data); + Serial.print("BME680 | Temp: "); Serial.print(data.temperature); Serial.println(" C"); + Serial.print("BME680 | Hum: "); Serial.print(data.humidity); Serial.println(" %"); + Serial.print("BME680 | Pres: "); Serial.print(data.pressure / 100.0); Serial.println(" hPa"); + Serial.print("BME680 | Gas: "); Serial.print(data.gas_resistance / 1000.0); Serial.println(" kOhm"); + } else { + Serial.println("BME680 | Failed to fetch data"); + } + + // Wait 5 seconds before next cycle + delay(5000); +} + +// Helper function for T6713 +int readT6713() { + Wire.beginTransmission(T6713_ADDR); + Wire.write(0x04); // Function: Read Input Registers + Wire.write(0x13); // Address High + Wire.write(0x8B); // Address Low + Wire.write(0x00); + Wire.write(0x01); // Length (1 register) + if (Wire.endTransmission() != 0) return -1; + + delay(10); // Processing delay + + Wire.requestFrom(T6713_ADDR, 4); + if (Wire.available() == 4) { + Wire.read(); Wire.read(); // Skip Func & Len + byte high = Wire.read(); + byte low = Wire.read(); + return (high << 8) | low; + } + return -1; +} \ No newline at end of file