#pragma once
#include <Arduino.h>
struct RadarConfig {
int uart_rx_pin = 4;
int uart_tx_pin = 15;
uint32_t baud_rate = 115200;
uint32_t presence_hold_ms = 1500;
uint32_t stale_after_ms = 2000;
float distance_ema_alpha = 0.35f;
int min_valid_zone = 1;
int max_valid_zone = 200;
float zone_to_meter_k = 0.7f;
float zone_to_meter_b = 0.0f;
/*
Порог минимального движения, ниже которого
текущая активность почти не растёт.
*/
float activity_min_speed_m_s = 0.03f;
/*
Скорость, при которой моментная активность
выходит примерно к 10.
*/
float activity_max_speed_m_s = 1.20f;
bool enable_debug_unknown_lines = false;
};
class Ld2420Radar {
public:
Ld2420Radar();
bool begin(HardwareSerial &serial, const RadarConfig &config);
void update();
String get_state_json() const;
private:
static const size_t LINE_BUFFER_SIZE = 160;
static const size_t SECOND_HISTORY_SIZE = 600; // 10 минут по 1 секунде
HardwareSerial *serial_port = nullptr;
RadarConfig cfg;
char line_buffer[LINE_BUFFER_SIZE];
size_t line_length = 0;
bool initialized = false;
bool online = false;
bool raw_presence = false;
bool presence = false;
float raw_distance_m = 0.0f;
float filtered_distance_m = 0.0f;
float current_speed_m_s = 0.0f;
uint8_t activity_score_current = 0;
uint32_t last_frame_ms = 0;
uint32_t last_presence_ms = 0;
uint32_t last_distance_sample_ms = 0;
float last_distance_for_speed_m = 0.0f;
bool has_distance_for_speed = false;
uint8_t second_scores[SECOND_HISTORY_SIZE];
uint16_t second_scores_head = 0;
uint16_t second_scores_count = 0;
uint32_t last_second_push_ms = 0;
String activity_score_dynamics = "constant";
private:
void reset_runtime_state();
void process_incoming_byte(char ch);
void process_line(const char *line_cstr);
void update_online_state(uint32_t now_ms);
void update_presence_state(uint32_t now_ms);
void update_second_history(uint32_t now_ms);
bool parse_ascii_line(const String &line);
bool extract_number_by_keys(const String &line, const char *keys[], size_t key_count, float &value_out) const;
bool extract_bool_by_keys(const String &line, const char *keys[], size_t key_count, bool &value_out) const;
bool parse_number_after_key(const String &line, const String &key, float &value_out) const;
bool parse_bool_after_key(const String &line, const String &key, bool &value_out) const;
String normalize_line(const String &line) const;
float clampf(float value, float min_value, float max_value) const;
int clampi(int value, int min_value, int max_value) const;
float zone_to_meters(float zone) const;
void apply_new_distance(float distance_m, uint32_t now_ms);
uint8_t compute_current_activity_score(bool detected_presence, float distance_m, float speed_m_s) const;
uint8_t compute_minute_activity_score() const;
String compute_dynamics() const;
bool is_distance_plausible(float distance_m) const;
};