#include "Zigbee.h" #define RX2_PIN 4 #define TX2_PIN 5 // Normal mode command #define COMMAND "FDFCFBFA0800120000006400000004030201" #define PRESENCE_DISTANCE 100 #define DELAY_STATUS_CHECK 1000 // delay (in ms) between two checks of the presence #define POWER_DELAY 20000 // delay (in ms) until turning off the screen // Zigbee #define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1 #define ZCL_OCCUPANCY_SENSOR_CLUSTER_SERVER ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER); bool isPresent = false; unsigned long lastMotionDetected = 0; // time when the last motion was detected void setup() { initSerial(); sendCommandAsHex(COMMAND); Serial.println("Waiting for sensor readings..."); initZigbee(); } void loop() { readAndProcessSensorLines(); delay(DELAY_STATUS_CHECK); } void initSerial() { // Start the primary serial communication (USB Monitor) Serial.begin(115200); unsigned long startAttemptTime = millis(); while (!Serial && millis() - startAttemptTime < 2000) { delay(100); } Serial.println("Serial Monitor Initialized."); // Start Serial2 for the HMMD Sensor Serial2.begin(115200, SERIAL_8N1, RX2_PIN, TX2_PIN); Serial.println("Serial2 Initialized on RX:" + String(RX2_PIN) + ", TX:" + String(TX2_PIN)); } void initZigbee() { zbOccupancySensor.setManufacturerAndModel("EspressIf", "Presence detector"); zbOccupancySensor.allowMultipleBinding(true); Serial.println("Adding ZigbeeSwitch endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbOccupancySensor); if (!Zigbee.begin()) { ESP.restart(); } while (!Zigbee.connected()) { delay(100); } } void sendCommandAsHex(String hexString) { int hexStringLength = hexString.length(); if (hexStringLength % 2 != 0) { Serial.println("Error: Hex string must have an even number of characters."); return; } int byteCount = hexStringLength / 2; byte hexBytes[byteCount]; for (int i = 0; i < hexStringLength; i += 2) { String byteString = hexString.substring(i, i + 2); byte hexByte = (byte)strtoul(byteString.c_str(), NULL, 16); hexBytes[i / 2] = hexByte; } // Print confirmation of what's being sent Serial.print("Sending "); Serial.print(byteCount); Serial.print(" bytes: "); for(int i=0; i 0) { // Read a line of text until a newline character (\n) is received // The timeout helps prevent blocking forever if a line ending is missed String line = Serial2.readStringUntil('\n'); // Clean up the line: remove potential carriage return (\r) and leading/trailing whitespace line.trim(); // Check if the line contains the "Range" information if (line.startsWith("Range ")) { // Extract the substring after "Range " String distanceStr = line.substring(6); int distance = distanceStr.toInt(); bool currentStatus = distance <= PRESENCE_DISTANCE; if (currentStatus == 1) { lastMotionDetected = millis(); } if (currentStatus && !isPresent) { isPresent = true; bool res = sendZigbeeOnOffCommand(isPresent); Serial.println("Motion detected, turning screen light on"); } else if (!currentStatus && isPresent && (millis() - lastMotionDetected >= POWER_DELAY)) { isPresent = false; bool res = sendZigbeeOnOffCommand(isPresent); Serial.printf("No motion detected for %d ms, turning light off.\n", POWER_DELAY); } } } } bool sendZigbeeOnOffCommand(bool isPresent) { bool result1 = zbOccupancySensor.setOccupancy(isPresent); bool result2 = zbOccupancySensor.report(); return result2; }