Files
hmmd-sensor-waveshare/hmmd-sensor-zigbee
2025-10-09 19:46:20 +02:00

126 lines
3.6 KiB
Plaintext

#include "Zigbee.h"
#define RX2_PIN 4
#define TX2_PIN 5
// Normal mode command
#define COMMAND "FDFCFBFA0800120000006400000004030201"
#define PRESENCE_DISTANCE 100
#define COUNT_STATUS_DIFFERENCE 5
// Zigbee
#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1
#define ZCL_OCCUPANCY_SENSOR_CLUSTER_SERVER
ZigbeeOccupancySensor zbOccupancySensor = ZigbeeOccupancySensor(OCCUPANCY_SENSOR_ENDPOINT_NUMBER);
bool isPresent = false;
int countDifferent = 0;
void setup() {
initSerial();
sendCommandAsHex(COMMAND);
Serial.println("Waiting for sensor readings...");
initZigbee();
}
void loop() {
readAndProcessSensorLines();
delay(500);
}
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 != isPresent) {
countDifferent++;
} else {
countDifferent = 0;
}
// change the status, if the last n updates were different than the current status
if (countDifferent >= COUNT_STATUS_DIFFERENCE) {
isPresent = !isPresent;
bool res = sendZigbeeOnOffCommand(isPresent);
Serial.print("Message sent: ");
Serial.print(isPresent);
Serial.print(" - successful: ");
Serial.println(res);
}
}
}
}
bool sendZigbeeOnOffCommand(bool isPresent) {
bool result1 = zbOccupancySensor.setOccupancy(isPresent);
bool result2 = zbOccupancySensor.report();
return result2;
}