diff --git a/devices/sh_core_esp8266/src/sh_core_esp8266.cpp b/devices/sh_core_esp8266/src/sh_core_esp8266.cpp index 3609346..58c5a30 100644 --- a/devices/sh_core_esp8266/src/sh_core_esp8266.cpp +++ b/devices/sh_core_esp8266/src/sh_core_esp8266.cpp @@ -2,13 +2,10 @@ // -------------------- WiFi radio tuning -------------------- static void wifi_apply_radio_tuning() { - // PHY: для дальности/стабильности чаще лучше 11G, чем 11N на грани сигнала WiFi.setPhyMode(WIFI_PHY_MODE_11G); - - // Sleep: выключаем энергосбережение (меньше лагов/потерь/дёрганий на плохом сигнале) WiFi.setSleepMode(WIFI_NONE_SLEEP); - // TX power: 0..20.5 dBm. 17 dBm обычно хороший компромисс + // TX power: 0..20.5 dBm. WiFi.setOutputPower(20.0f); } @@ -37,6 +34,10 @@ static uint32_t sta_pause_until = 0; static uint8_t last_ap_sta_num = 0; +// -------------------- core "online" event state -------------------- +static bool sta_was_connected = false; +static bool online_event_sent_for_this_connection = false; + static bool sta_is_paused() { return (sta_pause_until != 0) && ((int32_t)(sta_pause_until - millis()) > 0); } @@ -210,33 +211,105 @@ sta_attempt_started_at = millis(); } +__attribute__((weak)) const char* core_get_event_path() { + return "/api/v1/devices/event"; // дефолт, в сервере можешь принять это или переопределить в прошивке +} + +// -------------------- core HTTP helper -------------------- +bool core_post_json_to_server(const String &path, + const String &json_body, + uint32_t timeout_ms, + int &http_code_out) +{ + http_code_out = -1; + + if (WiFi.status() != WL_CONNECTED) return false; + if (authToken.length() == 0) return false; + if (serverBaseUrl.length() == 0) return false; + if (serverBaseUrl == "0.0.0.0") return false; + + String url = "http://" + serverBaseUrl + path; + + WiFiClient client; + HTTPClient http; + + if (!http.begin(client, url)) return false; + + http.setTimeout(timeout_ms); + http.addHeader("Content-Type", "application/json"); + http.addHeader("Authorization", "Bearer " + authToken); + + int code = http.POST(json_body); + http.end(); + + http_code_out = code; + return (code >= 200 && code < 300); +} + +// -------------------- core online event -------------------- +static void core_send_online_event_once() { + if (deviceMode != DEVICE_MODE_NORMAL) return; + if (online_event_sent_for_this_connection) return; + + // сервер должен быть известен (IP фиксируется при set_token в setup) + if (serverBaseUrl.length() == 0 || serverBaseUrl == "0.0.0.0") return; + if (authToken.length() == 0) return; + + IPAddress ip = WiFi.localIP(); + + String body = "{"; + body += "\"event_name\":\"online\","; + body += "\"data\":{"; + body += "\"device_ip\":\"" + ip.toString() + "\""; + body += "},"; + body += "\"device_id\":\"" + getUniqueID() + "\""; + body += "}"; + + int http_code = -1; + (void)core_post_json_to_server(core_get_event_path(), body, 1500, http_code); + + online_event_sent_for_this_connection = true; +} + static void wifi_tick() { + // reset connection flags on disconnect + if (WiFi.status() != WL_CONNECTED) { + if (sta_was_connected) { + sta_was_connected = false; + online_event_sent_for_this_connection = false; + } + } + // 1) Если нет SSID — только AP (и всё) if (savedSSID.length() == 0) { wifi_enable_ap_if_needed(); return; } - // 2) Если подключились — гасим AP и выходим (это должно быть раньше паузы) + // 2) Если подключились — гасим AP и (после этого) триггерим core online event if (WiFi.status() == WL_CONNECTED) { + if (!sta_was_connected) { + sta_was_connected = true; + online_event_sent_for_this_connection = false; + } + if (sta_first_fail_at != 0) sta_first_fail_at = 0; wifi_disable_ap_if_enabled(); + + // триггер ядра: устройство онлайн + core_send_online_event_once(); return; } - // если к AP подключился клиент — стопаем STA попытки (AP должен быть стабильным) + // если AP поднят и к нему кто-то подключён — держим STA на паузе if (ap_enabled) { uint8_t ap_sta_num = WiFi.softAPgetStationNum(); if (ap_sta_num > 0) { sta_pause_for(60000); } - last_ap_sta_num = ap_sta_num; } - // если STA на паузе — не дёргаем begin/disconnect/retry - if (sta_is_paused()) { - return; - } + if (sta_is_paused()) return; // 3) Если это initial setup — AP обязан быть включен постоянно до успешного STA if (deviceMode == DEVICE_MODE_SETUP) { @@ -272,7 +345,6 @@ } - // -------------------- Utils -------------------- String getUniqueID() { return String(ESP.getChipId(), HEX); @@ -335,31 +407,3 @@ wifi_tick(); delay(0); } - -// -------------------- core: post json helper (добавлено) -------------------- -bool core_post_json_to_server(const String &path, const String &json_body, uint32_t timeout_ms, int &http_code_out) { - http_code_out = -1; - - if (WiFi.status() != WL_CONNECTED) return false; - if (authToken.length() == 0) return false; - if (serverBaseUrl.length() == 0 || serverBaseUrl == "0.0.0.0") return false; - - String url = "http://" + serverBaseUrl + path; - - WiFiClient client; - HTTPClient http; - - if (!http.begin(client, url)) { - return false; - } - - http.setTimeout(timeout_ms); - http.addHeader("Content-Type", "application/json"); - http.addHeader("Authorization", "Bearer " + authToken); - - int code = http.POST(json_body); - http.end(); - - http_code_out = code; - return (code >= 200 && code < 300); -} \ No newline at end of file diff --git a/devices/sh_core_esp8266/src/sh_core_esp8266.h b/devices/sh_core_esp8266/src/sh_core_esp8266.h index 95529b4..e698710 100755 --- a/devices/sh_core_esp8266/src/sh_core_esp8266.h +++ b/devices/sh_core_esp8266/src/sh_core_esp8266.h @@ -10,7 +10,7 @@ #include #include -static const char CORE_VERSION[] PROGMEM = "esp8266 1.1.0 dev"; +static const char CORE_VERSION[] PROGMEM = "esp8266 1.20 dev"; // -------------------- compile-time defaults -------------------- extern const char* DEVICE_TYPE; @@ -101,6 +101,8 @@ // Универсальный POST JSON на serverBaseUrl (добавлено) bool core_post_json_to_server(const String &path, const String &json_body, uint32_t timeout_ms, int &http_code_out); +// Путь для core event'ов (можно переопределить в прошивке устройства). +__attribute__((weak)) const char* core_get_event_path(); // -------------------- routes registration (реализованы в .cpp) -------------------- void registerWebUiRoutes();