186 lines
5.7 KiB
C++
186 lines
5.7 KiB
C++
#include "esphome.h"
|
|
|
|
#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1)
|
|
#define STATE_SIZE 8
|
|
#define TARGETS 3
|
|
|
|
static const char *TAG = "ld2450";
|
|
class LD2450 : public PollingComponent, public UARTDevice
|
|
{
|
|
public:
|
|
LD2450(UARTComponent *parent) : UARTDevice(parent) {}
|
|
|
|
// BinarySensor *lastCommandSuccess = new BinarySensor();
|
|
Sensor *lastCommandSuccess = new Sensor();
|
|
Sensor *target1Resolution = new Sensor();
|
|
Sensor *target1Speed = new Sensor();
|
|
Sensor *target1X = new Sensor();
|
|
Sensor *target1Y = new Sensor();
|
|
Sensor *target2Resolution = new Sensor();
|
|
Sensor *target2Speed = new Sensor();
|
|
Sensor *target2X = new Sensor();
|
|
Sensor *target2Y = new Sensor();
|
|
Sensor *target3Resolution = new Sensor();
|
|
Sensor *target3Speed = new Sensor();
|
|
Sensor *target3X = new Sensor();
|
|
Sensor *target3Y = new Sensor();
|
|
Sensor *targets = new Sensor();
|
|
|
|
uint32_t lastPeriodicMillis = millis();
|
|
|
|
uint16_t twoByteToUint(char firstByte, char secondByte) {
|
|
return (uint16_t)(secondByte << 8) + firstByte;
|
|
}
|
|
|
|
void reportTargetInfo(int target, char *raw) {
|
|
int16_t newX, newY, newSpeed, sum;
|
|
uint16_t newResolution;
|
|
|
|
ESP_LOGV(TAG, "Will reporting taget %d", target);
|
|
|
|
switch (target) {
|
|
case 0:
|
|
newX = twoByteToUint(raw[0], raw[1] & 0x7F);
|
|
if (raw[1] >> 7 != 0x1)
|
|
newX = 0 - newX / 10;
|
|
else
|
|
newX = newX / 10;
|
|
if (target1X->get_state() != newX)
|
|
target1X->publish_state(newX);
|
|
newY = twoByteToUint(raw[2], raw[3] & 0x7F);
|
|
if (raw[3] >> 7 != 0x1)
|
|
newY = 0 - newY / 10;
|
|
else
|
|
newY = newY / 10;
|
|
if (target1Y->get_state() != newY)
|
|
target1Y->publish_state(newY);
|
|
newSpeed = twoByteToUint(raw[4], raw[5] & 0x7F);
|
|
if (raw[5] >> 7 != 0x1)
|
|
newSpeed = 0 - newSpeed;
|
|
if (target1Speed->get_state() != newSpeed)
|
|
target1Speed->publish_state(newSpeed);
|
|
newResolution = twoByteToUint(raw[6], raw[7]);
|
|
if (target1Resolution->get_state() != newResolution)
|
|
target1Resolution->publish_state(newResolution);
|
|
break;
|
|
case 1:
|
|
newX = twoByteToUint(raw[0], raw[1] & 0x7F);
|
|
if (raw[1] >> 7 != 0x1)
|
|
newX = 0 - newX / 10;
|
|
else
|
|
newX = newX / 10;
|
|
if (target2X->get_state() != newX)
|
|
target2X->publish_state(newX);
|
|
newY = twoByteToUint(raw[2], raw[3] & 0x7F);
|
|
if (raw[3] >> 7 != 0x1)
|
|
newY = 0 - newY / 10;
|
|
else
|
|
newY = newY / 10;
|
|
if (target2Y->get_state() != newY)
|
|
target2Y->publish_state(newY);
|
|
newSpeed = twoByteToUint(raw[4], raw[5] & 0x7F);
|
|
if (raw[5] >> 7 != 0x1)
|
|
newSpeed = 0 - newSpeed;
|
|
if (target2Speed->get_state() != newSpeed)
|
|
target2Speed->publish_state(newSpeed);
|
|
newResolution = twoByteToUint(raw[6], raw[7]);
|
|
if (target2Resolution->get_state() != newResolution)
|
|
target2Resolution->publish_state(newResolution);
|
|
break;
|
|
case 2:
|
|
newX = twoByteToUint(raw[0], raw[1] & 0x7F);
|
|
if (raw[1] >> 7 != 0x1)
|
|
newX = 0 - newX / 10;
|
|
else
|
|
newX = newX / 10;
|
|
if (target3X->get_state() != newX)
|
|
target3X->publish_state(newX);
|
|
newY = twoByteToUint(raw[2], raw[3] & 0x7F);
|
|
if (raw[3] >> 7 != 0x1)
|
|
newY = 0 - newY / 10;
|
|
else
|
|
newY = newY / 10;
|
|
if (target3Y->get_state() != newY)
|
|
target3Y->publish_state(newY);
|
|
newSpeed = twoByteToUint(raw[4], raw[5] & 0x7F);
|
|
if (raw[5] >> 7 != 0x1)
|
|
newSpeed = 0 - newSpeed;
|
|
if (target3Speed->get_state() != newSpeed)
|
|
target3Speed->publish_state(newSpeed);
|
|
newResolution = twoByteToUint(raw[6], raw[7]);
|
|
if (target3Resolution->get_state() != newResolution)
|
|
target3Resolution->publish_state(newResolution);
|
|
break;
|
|
}
|
|
sum = 0;
|
|
if (target1Resolution->get_state() > 0){
|
|
sum+=1;
|
|
}
|
|
if (target2Resolution->get_state() > 0){
|
|
sum+=1;
|
|
}
|
|
if (target3Resolution->get_state() > 0){
|
|
sum+=1;
|
|
}
|
|
if (targets->get_state() != sum){
|
|
targets->publish_state(sum);
|
|
}
|
|
}
|
|
|
|
void handlePeriodicData(char *buffer, int len) {
|
|
if (len < 29)
|
|
return; // 4 frame start bytes + 2 length bytes + 1 data end byte + 1 crc byte + 4 frame end bytes
|
|
if (buffer[0] != 0xAA || buffer[1] != 0xFF || buffer[2] != 0x03 || buffer[3] != 0x00)
|
|
return; // check 4 frame start bytes
|
|
if (buffer[len - 2] != 0x55 || buffer[len - 1] != 0xCC)
|
|
return; // data end=0x55, 0xcc
|
|
char stateBytes[STATE_SIZE];
|
|
|
|
/*
|
|
Reduce data update rate to prevent home assistant database size glow fast
|
|
*/
|
|
uint32_t currentMillis = millis();
|
|
if (currentMillis - lastPeriodicMillis < 1000)
|
|
return;
|
|
lastPeriodicMillis = currentMillis;
|
|
for (int i = 0; i < TARGETS; i++) {
|
|
memcpy(stateBytes, &buffer[4 + i * STATE_SIZE], STATE_SIZE);
|
|
reportTargetInfo(i, stateBytes);
|
|
}
|
|
}
|
|
|
|
void readline(int readch, char *buffer, int len) {
|
|
static int pos = 0;
|
|
if (readch >= 0) {
|
|
if (pos < len - 1) {
|
|
buffer[pos++] = readch;
|
|
buffer[pos] = 0;
|
|
} else {
|
|
pos = 0;
|
|
}
|
|
if (pos >= 4) {
|
|
if (buffer[pos - 2] == 0x55 && buffer[pos - 1] == 0xCC) {
|
|
handlePeriodicData(buffer, pos);
|
|
pos = 0; // Reset position index ready for next time
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void setup() override {
|
|
set_update_interval(15000);
|
|
}
|
|
|
|
void loop() override {
|
|
const int max_line_length = 160;
|
|
static char buffer[max_line_length];
|
|
while (available()) {
|
|
readline(read(), buffer, max_line_length);
|
|
}
|
|
}
|
|
|
|
void update(){
|
|
}
|
|
};
|