[ld2450] Use `Deduplicator` for sensors (#9863)

This commit is contained in:
Keith Burzinski 2025-07-24 04:02:03 -05:00 committed by GitHub
parent 568e774116
commit 5bff9bc8d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 102 additions and 205 deletions

View File

@ -3,6 +3,7 @@ from esphome.components import uart
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_THROTTLE from esphome.const import CONF_ID, CONF_THROTTLE
AUTO_LOAD = ["ld24xx"]
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
CODEOWNERS = ["@hareeshmu"] CODEOWNERS = ["@hareeshmu"]
MULTI_CONF = True MULTI_CONF = True

View File

@ -1,6 +1,5 @@
#include "ld2450.h" #include "ld2450.h"
#include <utility>
#include <cmath>
#ifdef USE_NUMBER #ifdef USE_NUMBER
#include "esphome/components/number/number.h" #include "esphome/components/number/number.h"
#endif #endif
@ -11,8 +10,8 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#define highbyte(val) (uint8_t)((val) >> 8) #include <cmath>
#define lowbyte(val) (uint8_t)((val) &0xff) #include <numbers>
namespace esphome { namespace esphome {
namespace ld2450 { namespace ld2450 {
@ -170,21 +169,16 @@ static inline int16_t hex_to_signed_int(const uint8_t *buffer, uint8_t offset) {
} }
static inline float calculate_angle(float base, float hypotenuse) { static inline float calculate_angle(float base, float hypotenuse) {
if (base < 0.0 || hypotenuse <= 0.0) { if (base < 0.0f || hypotenuse <= 0.0f) {
return 0.0; return 0.0f;
} }
float angle_radians = std::acos(base / hypotenuse); float angle_radians = acosf(base / hypotenuse);
float angle_degrees = angle_radians * (180.0 / M_PI); float angle_degrees = angle_radians * (180.0f / std::numbers::pi_v<float>);
return angle_degrees; return angle_degrees;
} }
static bool validate_header_footer(const uint8_t *header_footer, const uint8_t *buffer) { static inline bool validate_header_footer(const uint8_t *header_footer, const uint8_t *buffer) {
for (uint8_t i = 0; i < HEADER_FOOTER_SIZE; i++) { return std::memcmp(header_footer, buffer, HEADER_FOOTER_SIZE) == 0;
if (header_footer[i] != buffer[i]) {
return false; // Mismatch in header/footer
}
}
return true; // Valid header/footer
} }
void LD2450Component::setup() { void LD2450Component::setup() {
@ -217,41 +211,41 @@ void LD2450Component::dump_config() {
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
ESP_LOGCONFIG(TAG, "Sensors:"); ESP_LOGCONFIG(TAG, "Sensors:");
LOG_SENSOR(" ", "MovingTargetCount", this->moving_target_count_sensor_); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "MovingTargetCount", this->moving_target_count_sensor_);
LOG_SENSOR(" ", "StillTargetCount", this->still_target_count_sensor_); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "StillTargetCount", this->still_target_count_sensor_);
LOG_SENSOR(" ", "TargetCount", this->target_count_sensor_); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetCount", this->target_count_sensor_);
for (sensor::Sensor *s : this->move_x_sensors_) { for (auto &s : this->move_x_sensors_) {
LOG_SENSOR(" ", "TargetX", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetX", s);
} }
for (sensor::Sensor *s : this->move_y_sensors_) { for (auto &s : this->move_y_sensors_) {
LOG_SENSOR(" ", "TargetY", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetY", s);
} }
for (sensor::Sensor *s : this->move_angle_sensors_) { for (auto &s : this->move_angle_sensors_) {
LOG_SENSOR(" ", "TargetAngle", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetAngle", s);
} }
for (sensor::Sensor *s : this->move_distance_sensors_) { for (auto &s : this->move_distance_sensors_) {
LOG_SENSOR(" ", "TargetDistance", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetDistance", s);
} }
for (sensor::Sensor *s : this->move_resolution_sensors_) { for (auto &s : this->move_resolution_sensors_) {
LOG_SENSOR(" ", "TargetResolution", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetResolution", s);
} }
for (sensor::Sensor *s : this->move_speed_sensors_) { for (auto &s : this->move_speed_sensors_) {
LOG_SENSOR(" ", "TargetSpeed", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "TargetSpeed", s);
} }
for (sensor::Sensor *s : this->zone_target_count_sensors_) { for (auto &s : this->zone_target_count_sensors_) {
LOG_SENSOR(" ", "ZoneTargetCount", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "ZoneTargetCount", s);
} }
for (sensor::Sensor *s : this->zone_moving_target_count_sensors_) { for (auto &s : this->zone_moving_target_count_sensors_) {
LOG_SENSOR(" ", "ZoneMovingTargetCount", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "ZoneMovingTargetCount", s);
} }
for (sensor::Sensor *s : this->zone_still_target_count_sensors_) { for (auto &s : this->zone_still_target_count_sensors_) {
LOG_SENSOR(" ", "ZoneStillTargetCount", s); LOG_SENSOR_WITH_DEDUP_SAFE(" ", "ZoneStillTargetCount", s);
} }
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
ESP_LOGCONFIG(TAG, "Text Sensors:"); ESP_LOGCONFIG(TAG, "Text Sensors:");
LOG_TEXT_SENSOR(" ", "Version", this->version_text_sensor_); LOG_TEXT_SENSOR(" ", "Version", this->version_text_sensor_);
LOG_TEXT_SENSOR(" ", "Mac", this->mac_text_sensor_); LOG_TEXT_SENSOR(" ", "MAC address", this->mac_text_sensor_);
for (text_sensor::TextSensor *s : this->direction_text_sensors_) { for (text_sensor::TextSensor *s : this->direction_text_sensors_) {
LOG_TEXT_SENSOR(" ", "Direction", s); LOG_TEXT_SENSOR(" ", "Direction", s);
} }
@ -419,19 +413,19 @@ void LD2450Component::send_command_(uint8_t command, const uint8_t *command_valu
if (command_value != nullptr) { if (command_value != nullptr) {
len += command_value_len; len += command_value_len;
} }
uint8_t len_cmd[] = {lowbyte(len), highbyte(len), command, 0x00}; // 2 length bytes (low, high) + 2 command bytes (low, high)
uint8_t len_cmd[] = {len, 0x00, command, 0x00};
this->write_array(len_cmd, sizeof(len_cmd)); this->write_array(len_cmd, sizeof(len_cmd));
// command value bytes // command value bytes
if (command_value != nullptr) { if (command_value != nullptr) {
for (uint8_t i = 0; i < command_value_len; i++) { this->write_array(command_value, command_value_len);
this->write_byte(command_value[i]);
}
} }
// frame footer bytes // frame footer bytes
this->write_array(CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)); this->write_array(CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER));
// FIXME to remove
delay(50); // NOLINT if (command != CMD_ENABLE_CONF && command != CMD_DISABLE_CONF) {
delay(50); // NOLINT
}
} }
// LD2450 Radar data message: // LD2450 Radar data message:
@ -459,8 +453,8 @@ void LD2450Component::handle_periodic_data_() {
int16_t target_count = 0; int16_t target_count = 0;
int16_t still_target_count = 0; int16_t still_target_count = 0;
int16_t moving_target_count = 0; int16_t moving_target_count = 0;
int16_t res = 0;
int16_t start = 0; int16_t start = 0;
int16_t val = 0;
int16_t tx = 0; int16_t tx = 0;
int16_t ty = 0; int16_t ty = 0;
int16_t td = 0; int16_t td = 0;
@ -478,85 +472,43 @@ void LD2450Component::handle_periodic_data_() {
start = TARGET_X + index * 8; start = TARGET_X + index * 8;
is_moving = false; is_moving = false;
// tx is used for further calculations, so always needs to be populated // tx is used for further calculations, so always needs to be populated
val = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]); tx = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]);
tx = val; SAFE_PUBLISH_SENSOR(this->move_x_sensors_[index], tx);
sensor::Sensor *sx = this->move_x_sensors_[index];
if (sx != nullptr) {
if (this->cached_target_data_[index].x != val) {
sx->publish_state(val);
this->cached_target_data_[index].x = val;
}
}
// Y // Y
start = TARGET_Y + index * 8; start = TARGET_Y + index * 8;
// ty is used for further calculations, so always needs to be populated ty = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]);
val = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]); SAFE_PUBLISH_SENSOR(this->move_y_sensors_[index], ty);
ty = val;
sensor::Sensor *sy = this->move_y_sensors_[index];
if (sy != nullptr) {
if (this->cached_target_data_[index].y != val) {
sy->publish_state(val);
this->cached_target_data_[index].y = val;
}
}
// RESOLUTION // RESOLUTION
start = TARGET_RESOLUTION + index * 8; start = TARGET_RESOLUTION + index * 8;
sensor::Sensor *sr = this->move_resolution_sensors_[index]; res = (this->buffer_data_[start + 1] << 8) | this->buffer_data_[start];
if (sr != nullptr) { SAFE_PUBLISH_SENSOR(this->move_resolution_sensors_[index], res);
val = (this->buffer_data_[start + 1] << 8) | this->buffer_data_[start];
if (this->cached_target_data_[index].resolution != val) {
sr->publish_state(val);
this->cached_target_data_[index].resolution = val;
}
}
#endif #endif
// SPEED // SPEED
start = TARGET_SPEED + index * 8; start = TARGET_SPEED + index * 8;
val = ld2450::decode_speed(this->buffer_data_[start], this->buffer_data_[start + 1]); ts = ld2450::decode_speed(this->buffer_data_[start], this->buffer_data_[start + 1]);
ts = val; if (ts) {
if (val) {
is_moving = true; is_moving = true;
moving_target_count++; moving_target_count++;
} }
#ifdef USE_SENSOR #ifdef USE_SENSOR
sensor::Sensor *ss = this->move_speed_sensors_[index]; SAFE_PUBLISH_SENSOR(this->move_speed_sensors_[index], ts);
if (ss != nullptr) {
if (this->cached_target_data_[index].speed != val) {
ss->publish_state(val);
this->cached_target_data_[index].speed = val;
}
}
#endif #endif
// DISTANCE // DISTANCE
// Optimized: use already decoded tx and ty values, replace pow() with multiplication // Optimized: use already decoded tx and ty values, replace pow() with multiplication
int32_t x_squared = (int32_t) tx * tx; int32_t x_squared = (int32_t) tx * tx;
int32_t y_squared = (int32_t) ty * ty; int32_t y_squared = (int32_t) ty * ty;
val = (uint16_t) sqrt(x_squared + y_squared); td = (uint16_t) sqrtf(x_squared + y_squared);
td = val; if (td > 0) {
if (val > 0) {
target_count++; target_count++;
} }
#ifdef USE_SENSOR #ifdef USE_SENSOR
sensor::Sensor *sd = this->move_distance_sensors_[index]; SAFE_PUBLISH_SENSOR(this->move_distance_sensors_[index], td);
if (sd != nullptr) {
if (this->cached_target_data_[index].distance != val) {
sd->publish_state(val);
this->cached_target_data_[index].distance = val;
}
}
// ANGLE // ANGLE
angle = ld2450::calculate_angle(static_cast<float>(ty), static_cast<float>(td)); angle = ld2450::calculate_angle(static_cast<float>(ty), static_cast<float>(td));
if (tx > 0) { if (tx > 0) {
angle = angle * -1; angle = angle * -1;
} }
sensor::Sensor *sa = this->move_angle_sensors_[index]; SAFE_PUBLISH_SENSOR(this->move_angle_sensors_[index], angle);
if (sa != nullptr) {
if (std::isnan(this->cached_target_data_[index].angle) ||
std::abs(this->cached_target_data_[index].angle - angle) > 0.1f) {
sa->publish_state(angle);
this->cached_target_data_[index].angle = angle;
}
}
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
// DIRECTION // DIRECTION
@ -570,11 +522,9 @@ void LD2450Component::handle_periodic_data_() {
direction = DIRECTION_STATIONARY; direction = DIRECTION_STATIONARY;
} }
text_sensor::TextSensor *tsd = this->direction_text_sensors_[index]; text_sensor::TextSensor *tsd = this->direction_text_sensors_[index];
if (tsd != nullptr) { const auto *dir_str = find_str(ld2450::DIRECTION_BY_UINT, direction);
if (this->cached_target_data_[index].direction != direction) { if (tsd != nullptr && (!tsd->has_state() || tsd->get_state() != dir_str)) {
tsd->publish_state(find_str(ld2450::DIRECTION_BY_UINT, direction)); tsd->publish_state(dir_str);
this->cached_target_data_[index].direction = direction;
}
} }
#endif #endif
@ -599,53 +549,19 @@ void LD2450Component::handle_periodic_data_() {
zone_all_targets = zone_still_targets + zone_moving_targets; zone_all_targets = zone_still_targets + zone_moving_targets;
// Publish Still Target Count in Zones // Publish Still Target Count in Zones
sensor::Sensor *szstc = this->zone_still_target_count_sensors_[index]; SAFE_PUBLISH_SENSOR(this->zone_still_target_count_sensors_[index], zone_still_targets);
if (szstc != nullptr) {
if (this->cached_zone_data_[index].still_count != zone_still_targets) {
szstc->publish_state(zone_still_targets);
this->cached_zone_data_[index].still_count = zone_still_targets;
}
}
// Publish Moving Target Count in Zones // Publish Moving Target Count in Zones
sensor::Sensor *szmtc = this->zone_moving_target_count_sensors_[index]; SAFE_PUBLISH_SENSOR(this->zone_moving_target_count_sensors_[index], zone_moving_targets);
if (szmtc != nullptr) {
if (this->cached_zone_data_[index].moving_count != zone_moving_targets) {
szmtc->publish_state(zone_moving_targets);
this->cached_zone_data_[index].moving_count = zone_moving_targets;
}
}
// Publish All Target Count in Zones // Publish All Target Count in Zones
sensor::Sensor *sztc = this->zone_target_count_sensors_[index]; SAFE_PUBLISH_SENSOR(this->zone_target_count_sensors_[index], zone_all_targets);
if (sztc != nullptr) {
if (this->cached_zone_data_[index].total_count != zone_all_targets) {
sztc->publish_state(zone_all_targets);
this->cached_zone_data_[index].total_count = zone_all_targets;
}
}
} // End loop thru zones } // End loop thru zones
// Target Count // Target Count
if (this->target_count_sensor_ != nullptr) { SAFE_PUBLISH_SENSOR(this->target_count_sensor_, target_count);
if (this->cached_global_data_.target_count != target_count) {
this->target_count_sensor_->publish_state(target_count);
this->cached_global_data_.target_count = target_count;
}
}
// Still Target Count // Still Target Count
if (this->still_target_count_sensor_ != nullptr) { SAFE_PUBLISH_SENSOR(this->still_target_count_sensor_, still_target_count);
if (this->cached_global_data_.still_count != still_target_count) {
this->still_target_count_sensor_->publish_state(still_target_count);
this->cached_global_data_.still_count = still_target_count;
}
}
// Moving Target Count // Moving Target Count
if (this->moving_target_count_sensor_ != nullptr) { SAFE_PUBLISH_SENSOR(this->moving_target_count_sensor_, moving_target_count);
if (this->cached_global_data_.moving_count != moving_target_count) {
this->moving_target_count_sensor_->publish_state(moving_target_count);
this->cached_global_data_.moving_count = moving_target_count;
}
}
#endif #endif
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
@ -942,28 +858,33 @@ void LD2450Component::query_target_tracking_mode_() { this->send_command_(CMD_QU
void LD2450Component::query_zone_() { this->send_command_(CMD_QUERY_ZONE, nullptr, 0); } void LD2450Component::query_zone_() { this->send_command_(CMD_QUERY_ZONE, nullptr, 0); }
#ifdef USE_SENSOR #ifdef USE_SENSOR
void LD2450Component::set_move_x_sensor(uint8_t target, sensor::Sensor *s) { this->move_x_sensors_[target] = s; } // These could leak memory, but they are only set once prior to 'setup()' and should never be used again.
void LD2450Component::set_move_y_sensor(uint8_t target, sensor::Sensor *s) { this->move_y_sensors_[target] = s; } void LD2450Component::set_move_x_sensor(uint8_t target, sensor::Sensor *s) {
this->move_x_sensors_[target] = new SensorWithDedup<int16_t>(s);
}
void LD2450Component::set_move_y_sensor(uint8_t target, sensor::Sensor *s) {
this->move_y_sensors_[target] = new SensorWithDedup<int16_t>(s);
}
void LD2450Component::set_move_speed_sensor(uint8_t target, sensor::Sensor *s) { void LD2450Component::set_move_speed_sensor(uint8_t target, sensor::Sensor *s) {
this->move_speed_sensors_[target] = s; this->move_speed_sensors_[target] = new SensorWithDedup<int16_t>(s);
} }
void LD2450Component::set_move_angle_sensor(uint8_t target, sensor::Sensor *s) { void LD2450Component::set_move_angle_sensor(uint8_t target, sensor::Sensor *s) {
this->move_angle_sensors_[target] = s; this->move_angle_sensors_[target] = new SensorWithDedup<float>(s);
} }
void LD2450Component::set_move_distance_sensor(uint8_t target, sensor::Sensor *s) { void LD2450Component::set_move_distance_sensor(uint8_t target, sensor::Sensor *s) {
this->move_distance_sensors_[target] = s; this->move_distance_sensors_[target] = new SensorWithDedup<uint16_t>(s);
} }
void LD2450Component::set_move_resolution_sensor(uint8_t target, sensor::Sensor *s) { void LD2450Component::set_move_resolution_sensor(uint8_t target, sensor::Sensor *s) {
this->move_resolution_sensors_[target] = s; this->move_resolution_sensors_[target] = new SensorWithDedup<uint16_t>(s);
} }
void LD2450Component::set_zone_target_count_sensor(uint8_t zone, sensor::Sensor *s) { void LD2450Component::set_zone_target_count_sensor(uint8_t zone, sensor::Sensor *s) {
this->zone_target_count_sensors_[zone] = s; this->zone_target_count_sensors_[zone] = new SensorWithDedup<uint8_t>(s);
} }
void LD2450Component::set_zone_still_target_count_sensor(uint8_t zone, sensor::Sensor *s) { void LD2450Component::set_zone_still_target_count_sensor(uint8_t zone, sensor::Sensor *s) {
this->zone_still_target_count_sensors_[zone] = s; this->zone_still_target_count_sensors_[zone] = new SensorWithDedup<uint8_t>(s);
} }
void LD2450Component::set_zone_moving_target_count_sensor(uint8_t zone, sensor::Sensor *s) { void LD2450Component::set_zone_moving_target_count_sensor(uint8_t zone, sensor::Sensor *s) {
this->zone_moving_target_count_sensors_[zone] = s; this->zone_moving_target_count_sensors_[zone] = new SensorWithDedup<uint8_t>(s);
} }
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR

View File

@ -1,12 +1,7 @@
#pragma once #pragma once
#include "esphome/components/uart/uart.h"
#include "esphome/core/component.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/helpers.h" #include "esphome/core/component.h"
#include "esphome/core/preferences.h"
#include <limits>
#include <cmath>
#ifdef USE_SENSOR #ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#endif #endif
@ -29,18 +24,23 @@
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#endif #endif
#ifndef M_PI #include "esphome/components/ld24xx/ld24xx.h"
#define M_PI 3.14 #include "esphome/components/uart/uart.h"
#endif #include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include <array>
namespace esphome { namespace esphome {
namespace ld2450 { namespace ld2450 {
using namespace ld24xx;
// Constants // Constants
static const uint8_t DEFAULT_PRESENCE_TIMEOUT = 5; // Timeout to reset presense status 5 sec. static constexpr uint8_t DEFAULT_PRESENCE_TIMEOUT = 5; // Timeout to reset presense status 5 sec.
static const uint8_t MAX_LINE_LENGTH = 41; // Max characters for serial buffer static constexpr uint8_t MAX_LINE_LENGTH = 41; // Max characters for serial buffer
static const uint8_t MAX_TARGETS = 3; // Max 3 Targets in LD2450 static constexpr uint8_t MAX_TARGETS = 3; // Max 3 Targets in LD2450
static const uint8_t MAX_ZONES = 3; // Max 3 Zones in LD2450 static constexpr uint8_t MAX_ZONES = 3; // Max 3 Zones in LD2450
enum Direction : uint8_t { enum Direction : uint8_t {
DIRECTION_APPROACHING = 0, DIRECTION_APPROACHING = 0,
@ -81,9 +81,9 @@ class LD2450Component : public Component, public uart::UARTDevice {
SUB_BINARY_SENSOR(target) SUB_BINARY_SENSOR(target)
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
SUB_SENSOR(moving_target_count) SUB_SENSOR_WITH_DEDUP(moving_target_count, uint8_t)
SUB_SENSOR(still_target_count) SUB_SENSOR_WITH_DEDUP(still_target_count, uint8_t)
SUB_SENSOR(target_count) SUB_SENSOR_WITH_DEDUP(target_count, uint8_t)
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
SUB_TEXT_SENSOR(mac) SUB_TEXT_SENSOR(mac)
@ -176,48 +176,23 @@ class LD2450Component : public Component, public uart::UARTDevice {
Target target_info_[MAX_TARGETS]; Target target_info_[MAX_TARGETS];
Zone zone_config_[MAX_ZONES]; Zone zone_config_[MAX_ZONES];
// Change detection - cache previous values to avoid redundant publishes
// All values are initialized to sentinel values that are outside the valid sensor ranges
// to ensure the first real measurement is always published
struct CachedTargetData {
int16_t x = std::numeric_limits<int16_t>::min(); // -32768, outside range of -4860 to 4860
int16_t y = std::numeric_limits<int16_t>::min(); // -32768, outside range of 0 to 7560
int16_t speed = std::numeric_limits<int16_t>::min(); // -32768, outside practical sensor range
uint16_t resolution = std::numeric_limits<uint16_t>::max(); // 65535, unlikely resolution value
uint16_t distance = std::numeric_limits<uint16_t>::max(); // 65535, outside range of 0 to ~8990
Direction direction = DIRECTION_UNDEFINED; // Undefined, will differ from any real direction
float angle = NAN; // NAN, safe sentinel for floats
} cached_target_data_[MAX_TARGETS];
struct CachedZoneData {
uint8_t still_count = std::numeric_limits<uint8_t>::max(); // 255, unlikely zone count
uint8_t moving_count = std::numeric_limits<uint8_t>::max(); // 255, unlikely zone count
uint8_t total_count = std::numeric_limits<uint8_t>::max(); // 255, unlikely zone count
} cached_zone_data_[MAX_ZONES];
struct CachedGlobalData {
uint8_t target_count = std::numeric_limits<uint8_t>::max(); // 255, max 3 targets possible
uint8_t still_count = std::numeric_limits<uint8_t>::max(); // 255, max 3 targets possible
uint8_t moving_count = std::numeric_limits<uint8_t>::max(); // 255, max 3 targets possible
} cached_global_data_;
#ifdef USE_NUMBER #ifdef USE_NUMBER
ESPPreferenceObject pref_; // only used when numbers are in use ESPPreferenceObject pref_; // only used when numbers are in use
ZoneOfNumbers zone_numbers_[MAX_ZONES]; ZoneOfNumbers zone_numbers_[MAX_ZONES];
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
std::vector<sensor::Sensor *> move_x_sensors_ = std::vector<sensor::Sensor *>(MAX_TARGETS); std::array<SensorWithDedup<int16_t> *, MAX_TARGETS> move_x_sensors_{};
std::vector<sensor::Sensor *> move_y_sensors_ = std::vector<sensor::Sensor *>(MAX_TARGETS); std::array<SensorWithDedup<int16_t> *, MAX_TARGETS> move_y_sensors_{};
std::vector<sensor::Sensor *> move_speed_sensors_ = std::vector<sensor::Sensor *>(MAX_TARGETS); std::array<SensorWithDedup<int16_t> *, MAX_TARGETS> move_speed_sensors_{};
std::vector<sensor::Sensor *> move_angle_sensors_ = std::vector<sensor::Sensor *>(MAX_TARGETS); std::array<SensorWithDedup<float> *, MAX_TARGETS> move_angle_sensors_{};
std::vector<sensor::Sensor *> move_distance_sensors_ = std::vector<sensor::Sensor *>(MAX_TARGETS); std::array<SensorWithDedup<uint16_t> *, MAX_TARGETS> move_distance_sensors_{};
std::vector<sensor::Sensor *> move_resolution_sensors_ = std::vector<sensor::Sensor *>(MAX_TARGETS); std::array<SensorWithDedup<uint16_t> *, MAX_TARGETS> move_resolution_sensors_{};
std::vector<sensor::Sensor *> zone_target_count_sensors_ = std::vector<sensor::Sensor *>(MAX_ZONES); std::array<SensorWithDedup<uint8_t> *, MAX_ZONES> zone_target_count_sensors_{};
std::vector<sensor::Sensor *> zone_still_target_count_sensors_ = std::vector<sensor::Sensor *>(MAX_ZONES); std::array<SensorWithDedup<uint8_t> *, MAX_ZONES> zone_still_target_count_sensors_{};
std::vector<sensor::Sensor *> zone_moving_target_count_sensors_ = std::vector<sensor::Sensor *>(MAX_ZONES); std::array<SensorWithDedup<uint8_t> *, MAX_ZONES> zone_moving_target_count_sensors_{};
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
std::vector<text_sensor::TextSensor *> direction_text_sensors_ = std::vector<text_sensor::TextSensor *>(3); std::array<text_sensor::TextSensor *, 3> direction_text_sensors_{};
#endif #endif
}; };