126 lines
3.8 KiB
C++
126 lines
3.8 KiB
C++
#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<byteCount; i++) {
|
|
if (hexBytes[i] < 16) Serial.print("0");;
|
|
}
|
|
Serial.println();
|
|
// Send the data
|
|
Serial2.write(hexBytes, byteCount);
|
|
Serial.println("Initial command sent to Serial2.");
|
|
}
|
|
|
|
void readAndProcessSensorLines() {
|
|
// Check if data is available on Serial2
|
|
while (Serial2.available() > 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;
|
|
} |