Newer
Older
smart-home-server / devices / sensor / sensor.ino
#include <Arduino.h>
#include <sh_core.h>

#include "ld2420_radar.h"
#include "bh1750_sensor.h"
#include "bme280_sensor.h"
#include "max4466_mic.h"
#include "SensorLogic.h"

/*
    =========================
    Тип и версия устройства
    (требуются ядром)
    =========================
*/
const char* DEVICE_TYPE = "sensor";
const char* FW_VERSION  = "1.0.0";

/*
    Устройство не использует канальную схему.
    Ядро требует CHANNEL_NUM — ставим 0.
*/
const uint8_t CHANNEL_NUM = 0;

/*
    =========================
    Глобальные объекты
    =========================
*/
Ld2420Radar   radar;
RadarConfig   radar_config;

Bh1750Sensor  light_sensor;
Bh1750Config  light_config;

Bme280Sensor  climate_sensor;
Bme280Config  climate_config;

Max4466Mic    mic;
Max4466Config mic_config;

/*
    Отдельные I2C-шины:
      Wire  (0) — BH1750    SDA=16, SCL=17
      Wire1 (1) — BME/BMP280 SDA=18, SCL=19
*/
TwoWire i2c_climate = TwoWire(1);


/*
    =========================
    RADAR CONFIGURATION
    =========================
*/
static void setup_radar_config() {
    radar_config.uart_rx_pin = 4;
    radar_config.uart_tx_pin = 15;
    radar_config.baud_rate   = 115200;

    radar_config.presence_hold_ms   = 1500;
    radar_config.stale_after_ms     = 2000;
    radar_config.distance_ema_alpha = 0.6f;

    radar_config.min_gate        = 1;
    radar_config.max_gate        = 8;
    radar_config.radar_timeout_s = 5;

    radar_config.move_threshold  = 10000;
    radar_config.still_threshold = 8000;

    static const uint32_t thresholds[LD2420_TOTAL_GATES] = {
        0,      // g0  ~0.0 м  шум антенны
        0,      // g1  ~0.7 м  фоновый шум
        800,    // g2  ~1.4 м
        500,    // g3  ~2.1 м
        15000,  // g4  ~2.8 м  (помехи в комнате)
        25000,  // g5  ~3.5 м  (помехи в комнате)
        15000,  // g6  ~4.2 м  (помехи в комнате)
        2000,   // g7  ~4.9 м
        2000,   // g8  ~5.6 м
        500,    // g9
        500,    // g10
        500,    // g11
        500,    // g12
        500,    // g13
        500,    // g14
        500,    // g15
    };
    memcpy(radar_config.presence_thresholds, thresholds,
           sizeof(radar_config.presence_thresholds));

    radar_config.presence_min_active_gates = 1;

    radar_config.total_energy_max          = 150000;
    radar_config.activity_avg_window_s     = 60;
    radar_config.activity_trend_window_min = 10;

    radar_config.enable_debug_frames = false;
}


/*
    =========================
    BH1750 CONFIGURATION
    =========================
*/
static void setup_light_config() {
    light_config.sda_pin         = 16;
    light_config.scl_pin         = 17;
    light_config.i2c_address     = 0x5C;
    light_config.measurement_mode = 0x10;
    light_config.stale_after_ms  = 2000;
    light_config.read_interval_ms = 200;
    light_config.lux_ema_alpha   = 0.25f;
    light_config.lux_max         = 500.0f;
}


/*
    =========================
    BME/BMP280 CONFIGURATION
    =========================
*/
static void setup_climate_config() {
    climate_config.sda_pin       = 18;
    climate_config.scl_pin       = 19;
    climate_config.i2c_address   = 0x76;

    climate_config.stale_after_ms  = 3000;
    climate_config.read_interval_ms = 1000;

    climate_config.temperature_ema_alpha = 0.25f;
    climate_config.pressure_ema_alpha    = 0.20f;
    climate_config.humidity_ema_alpha    = 0.20f;
}


/*
    =========================
    MAX4466 CONFIGURATION
    =========================
*/
static void setup_mic_config() {
    mic_config.adc_pin            = 34;
    mic_config.adc_max_value      = 4095;
    mic_config.adc_vref_mv        = 3300.0f;

    mic_config.sample_count       = 256;
    mic_config.sample_interval_us = 100;

    mic_config.read_interval_ms   = 100;
    mic_config.stale_after_ms     = 2000;

    mic_config.db_ema_alpha       = 0.15f;
    mic_config.db_ref_mv          = 1.0f;
    mic_config.db_noise_floor     = 30.0f;
    mic_config.db_scale_range_db  = 30.0f;

    mic_config.db_avg_window_s    = 30;
    mic_config.db_trend_window_min = 10;

    mic_config.peak_reset_ms      = 60000;
}


/*
    =========================
    DEVICE INITIALIZATION
    =========================
*/
static void init_radar() {
    setup_radar_config();
    bool ok = radar.begin(Serial2, radar_config);
    Serial.println(ok ? "Radar OK" : "Radar FAIL");
}

static void init_light_sensor() {
    setup_light_config();
    bool ok = light_sensor.begin(light_config);
    Serial.println(ok ? "BH1750 OK" : "BH1750 FAIL");
}

static void init_climate_sensor() {
    setup_climate_config();
    bool ok = climate_sensor.begin(i2c_climate, climate_config);
    if (ok) {
        Serial.print("Climate OK: ");
        Serial.println(climate_sensor.get_sensor_type_string());
    } else {
        Serial.println("Climate FAIL");
    }
}

static void init_mic() {
    setup_mic_config();
    mic.begin(mic_config);
    Serial.println("MAX4466 OK");
}


/*
    =========================
    SETUP
    =========================
*/
void setup() {
    Serial.begin(115200);
    delay(500);

    Serial.println("\n[sensor] starting...");

    /*
        Ядро инициализирует WiFi, EEPROM, HTTP-сервер,
        регистрирует базовые роуты (/about, /status, /action, ...).
    */
    coreSetup();

    /* Датчики */
    init_radar();
    init_light_sensor();
    init_climate_sensor();
    init_mic();

    /* Индикатор и логика устройства */
    sensor_logic_setup();

    Serial.println("[sensor] ready");
}


/*
    =========================
    LOOP
    =========================
*/
void loop() {
    /* Ядро: обработка HTTP-запросов, watchdog и пр. */
    coreLoop();

    /* Датчики */
    radar.update();
    light_sensor.update();
    climate_sensor.update();
    mic.update();

    /* Индикатор + отслеживание presence */
    sensor_logic_loop();
}