feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s

Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
This commit is contained in:
Codex Local
2026-10-08 10:06:44 +08:00
parent 98fb2965d0
commit bf1233d5df
861 changed files with 94614 additions and 3209 deletions
+88 -4
View File
@@ -9,11 +9,14 @@
#include <esp_event.h>
#include <esp_wifi.h>
#include <esp_log.h>
#include <esp_heap_caps.h>
#include <esp_timer.h>
#include <nvs.h>
#include <nvs_flash.h>
#include "configuration_ap.h"
#include "platform_client.h"
#include "ble_cloud.h"
#define TAG "NETWORK"
@@ -21,8 +24,33 @@
#define WIFI_EVENT_FAILED BIT1
#define WIFI_EVENT_STARTED BIT2
#define MAX_RECONNECT_COUNT 5
#define RECONNECT_DELAY_US (10 * 1000 * 1000)
static network_t network;
static esp_err_t network_error;
static esp_timer_handle_t reconnect_timer;
static bool reconnect_enabled;
esp_err_t network_last_error(void) { return network_error; }
static void reconnect_saved_network(void *arg)
{
(void)arg;
if (!reconnect_enabled ||
(xEventGroupGetBits(network.event_group) & WIFI_EVENT_CONNECTED)) return;
esp_err_t err = esp_wifi_connect();
if (err != ESP_OK) {
ESP_LOGW(TAG, "WiFi reconnect deferred: %s", esp_err_to_name(err));
esp_timer_start_once(reconnect_timer, RECONNECT_DELAY_US);
}
}
static void schedule_reconnect(void)
{
// Fast retries recover a short interruption; slower retries continue for as
// long as the saved network is unavailable, including a phone hotspot.
if (reconnect_enabled && reconnect_timer && !esp_timer_is_active(reconnect_timer))
esp_timer_start_once(reconnect_timer, RECONNECT_DELAY_US);
}
int8_t get_rssi()
{
@@ -49,6 +77,8 @@ void handler_event_wifi_st(void *arg, esp_event_base_t event_base, int32_t event
else if (event_id == WIFI_EVENT_STA_DISCONNECTED)
{
xEventGroupClearBits(network.event_group, WIFI_EVENT_CONNECTED);
network.ip_address[0] = '\0';
if (!reconnect_enabled) return;
if (network.reconnect_count < MAX_RECONNECT_COUNT)
{
/* Retry the selected AP first, but allow another AP if it is no longer
@@ -62,35 +92,47 @@ void handler_event_wifi_st(void *arg, esp_event_base_t event_base, int32_t event
ESP_LOGW(TAG, "Preferred AP unavailable; falling back to SSID scan");
}
}
esp_wifi_connect();
esp_err_t err = esp_wifi_connect();
network.reconnect_count++;
ESP_LOGI(TAG, "Reconnecting WiFi (attempt %d)", network.reconnect_count);
if (err != ESP_OK) schedule_reconnect();
}
else
{
xEventGroupSetBits(network.event_group, WIFI_EVENT_FAILED);
ESP_LOGI(TAG, "WiFi connection failed");
schedule_reconnect();
ESP_LOGI(TAG, "WiFi unavailable; retrying every 10 seconds");
}
}
else if (event_id == WIFI_EVENT_STA_STOP)
{
reconnect_enabled = false;
if (reconnect_timer) esp_timer_stop(reconnect_timer);
xEventGroupClearBits(network.event_group, WIFI_EVENT_CONNECTED | WIFI_EVENT_STARTED);
network.ip_address[0] = '\0';
}
}
void handler_event_ip_st(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
network.reconnect_count = 0;
if (reconnect_timer) esp_timer_stop(reconnect_timer);
esp_ip4addr_ntoa(&event->ip_info.ip, network.ip_address, sizeof(network.ip_address));
ESP_LOGI(TAG, "Got IP: %s", network.ip_address);
xEventGroupClearBits(network.event_group, WIFI_EVENT_FAILED);
xEventGroupSetBits(network.event_group, WIFI_EVENT_CONNECTED);
}
bool is_connected()
{
return xEventGroupGetBits(network.event_group) & WIFI_EVENT_CONNECTED;
return network.event_group && (xEventGroupGetBits(network.event_group) & WIFI_EVENT_CONNECTED);
}
bool configure_network()
{
network_error=ESP_OK;
// Create the event group
network.ssid[0] = '\0';
@@ -98,6 +140,15 @@ bool configure_network()
network.reconnect_count = 0;
network.ip_address[0] = '\0';
network.event_group = xEventGroupCreate();
if(!network.event_group){network_error=ESP_ERR_NO_MEM;return false;}
if (!reconnect_timer) {
const esp_timer_create_args_t timer_config = {
.callback = reconnect_saved_network,
.name = "wifi_reconnect"
};
network_error = esp_timer_create(&timer_config, &reconnect_timer);
if (network_error != ESP_OK) return false;
}
// Get ssid and password from NVS
nvs_handle_t nvs_handle;
@@ -143,7 +194,25 @@ bool configure_network()
// Initialize the WiFi stack in station mode
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// RTC and TLS share internal RAM with the Wi-Fi DMA buffers. Six static
// RX/TX frames retain streaming capacity without reserving 32 DMA frames.
cfg.static_rx_buf_num=6;
cfg.static_tx_buf_num=6;
// Dynamic RX buffers prefer PSRAM; match the 32KiB TCP receive window.
cfg.dynamic_rx_buf_num=32;
cfg.cache_tx_buf_num=8;
cfg.rx_ba_win=6;
ESP_LOGI(TAG,"WiFi init internal_free=%u largest=%u rx=%d tx=%d",
(unsigned)heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL),cfg.static_rx_buf_num,cfg.static_tx_buf_num);
network_error=esp_wifi_init(&cfg);
if(network_error!=ESP_OK){
ESP_LOGE(TAG,"WiFi initialization unavailable: %s",esp_err_to_name(network_error));
esp_event_handler_instance_unregister(WIFI_EVENT,ESP_EVENT_ANY_ID,instance_any_id);
esp_event_handler_instance_unregister(IP_EVENT,IP_EVENT_STA_GOT_IP,instance_got_ip);
esp_netif_destroy_default_wifi(station_netif);
return false; // No abort/reboot loop on insufficient internal RAM.
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
@@ -158,6 +227,7 @@ bool configure_network()
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
// Start the WiFi stack
reconnect_enabled = true;
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
xEventGroupWaitBits(network.event_group, WIFI_EVENT_STARTED, pdFALSE, pdFALSE, pdMS_TO_TICKS(5000));
@@ -190,6 +260,8 @@ bool configure_network()
// Reset the WiFi stack
// 取消注册事件处理程序
reconnect_enabled = false;
esp_timer_stop(reconnect_timer);
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_wifi_stop());
@@ -205,6 +277,18 @@ bool configure_network()
if (!is_connected())
{
if (ble_cloud_configured()) {
// Completed BLE devices need the same phone flow when taken away from
// their old Wi-Fi. Reboot to release normal-mode buffers before NimBLE.
network_error = nvs_open("wifi", NVS_READWRITE, &nvs_handle);
if (network_error == ESP_OK) {
network_error = nvs_set_u8(nvs_handle, "setup_requested", 1);
if (network_error == ESP_OK) network_error = nvs_commit(nvs_handle);
nvs_close(nvs_handle);
}
ESP_LOGI(TAG, "Saved WiFi unavailable; requesting Bluetooth setup");
return false;
}
configure_ap();
ESP_LOGI(TAG, "WiFi not connected, starting AP");
return false;