#include "SensorLogic.h"
#include "sh_core.h"
#include "ld2420_radar.h"
#include "bh1750_sensor.h"
#include "bme280_sensor.h"
#include "max4466_mic.h"
/*
=========================================================
Внешние объекты — объявлены и инициализированы в sensor.ino
=========================================================
*/
extern Ld2420Radar radar;
extern Bh1750Sensor light_sensor;
extern Bme280Sensor climate_sensor;
extern Max4466Mic mic;
/*
=========================================================
NeoPixel
=========================================================
*/
static Adafruit_NeoPixel led(SENSOR_LED_COUNT, SENSOR_LED_PIN, NEO_GRB + NEO_KHZ800);
static uint32_t color(uint8_t r, uint8_t g, uint8_t b) {
return led.Color(r, g, b);
}
/*
=========================================================
Состояние presence — для отслеживания смены
=========================================================
*/
static bool _prev_presence = false;
static bool _presence_init_done = false; // первый цикл — не шлём событие
/*
=========================================================
Вспомогательные функции
=========================================================
*/
static bool _is_setup() {
return (deviceMode == DEVICE_MODE_SETUP);
}
static bool _is_nowifi() {
if (deviceMode == DEVICE_MODE_SETUP) return false;
return (WiFi.status() != WL_CONNECTED);
}
/*
Хотя бы один датчик online — считаем устройство рабочим.
*/
static bool _any_sensor_online() {
return radar.is_online()
|| light_sensor.is_online()
|| climate_sensor.is_online()
|| mic.is_online();
}
/*
=========================================================
Индикатор
=========================================================
*/
static void _render_led() {
uint32_t t = millis();
/* --- Глобальные режимы --- */
if (_is_setup()) {
bool on = ((t / SENSOR_BLINK_SLOW_MS) % 2) == 0;
led.setPixelColor(0, on ? color(255, 255, 255) : color(0, 0, 0));
led.show();
return;
}
if (_is_nowifi()) {
bool on = ((t / SENSOR_BLINK_SLOW_MS) % 2) == 0;
led.setPixelColor(0, on ? color(0, 0, 255) : color(0, 0, 0));
led.show();
return;
}
if (!_any_sensor_online()) {
bool on = ((t / SENSOR_BLINK_SLOW_MS) % 2) == 0;
led.setPixelColor(0, on ? color(255, 0, 0) : color(0, 0, 0));
led.show();
return;
}
/* --- Рабочий режим --- */
if (radar.is_presence()) {
/* Присутствие — постоянный мягкий белый */
led.setPixelColor(0, color(60, 60, 60));
} else {
/* Тишина — тихий зелёный */
led.setPixelColor(0, color(0, 20, 0));
}
led.show();
}
/*
=========================================================
Событие presence_changed
=========================================================
*/
static void _send_presence_event(bool presence) {
if (deviceMode != DEVICE_MODE_NORMAL) return;
if (WiFi.status() != WL_CONNECTED) return;
String body = "{";
body += "\"event_name\":\"presence_changed\",";
body += "\"data\":{";
body += "\"presence\":" + String(presence ? "true" : "false") + ",";
body += "\"activity_score\":" + String(radar.get_activity_score()) + ",";
body += "\"activity_score_current\":" + String(radar.get_activity_score_current()) + ",";
body += "\"distance_m\":" + String(radar.get_distance_m(), 2);
body += "},";
body += "\"device_id\":\"" + getUniqueID() + "\"";
body += "}";
int http_code = -1;
core_post_json_to_server(SENSOR_EVENT_PATH, body, SENSOR_EVENT_TIMEOUT_MS, http_code);
}
/*
=========================================================
Отслеживание смены presence
=========================================================
*/
static void _tick_presence() {
bool current = radar.is_presence();
if (!_presence_init_done) {
_prev_presence = current;
_presence_init_done = true;
return;
}
if (current != _prev_presence) {
_prev_presence = current;
_send_presence_event(current);
}
}
/*
=========================================================
weak-хуки ядра
=========================================================
*/
/*
/status — добавляем поля sensors и indicators.
Ядро уже открыло '{' и написало "status":"ok",
мы дописываем в json начиная с ','.
*/
void appendStatusJsonFields(String &json) {
/* indicators */
String ind;
if (_is_setup()) ind = "setup";
else if (_is_nowifi()) ind = "nowifi";
else ind = "ok";
json += ",\"indicators\":\"" + ind + "\"";
/* sensors */
json += ",\"sensors\":{";
/* light */
json += "\"light\":" + light_sensor.get_state_json();
/* temperature */
json += ",\"temperature\":" + climate_sensor.get_temperature_json();
/* pressure */
json += ",\"pressure\":" + climate_sensor.get_pressure_json();
/* humidity — только если BME280 */
if (climate_sensor.has_humidity()) {
json += ",\"humidity\":" + climate_sensor.get_humidity_json();
}
/* radar */
json += ",\"radar\":" + String(radar.get_state_json());
/* microphone */
json += ",\"microphone\":" + mic.get_state_json();
json += "}";
}
/*
/action — датчик пассивный.
Поддерживается одно действие: reset_peak_noise.
*/
bool deviceHandleAction(const String &action,
const String ¶msJson,
String &errorCode,
String &errorMessage)
{
(void)paramsJson;
if (action == "reset_peak_noise") {
mic.reset_peak();
return true;
}
errorCode = "IllegalActionOrParams";
errorMessage = "Device does not support this action";
return false;
}
/*
=========================================================
Setup / Loop
=========================================================
*/
void sensor_logic_setup() {
led.begin();
led.setBrightness(40);
led.clear();
led.show();
}
void sensor_logic_loop() {
_tick_presence();
_render_led();
}