use led, wifi component

This commit is contained in:
Terrence 2024-09-10 05:58:56 +08:00
parent 6112726b6d
commit 3a97934b15
13 changed files with 44 additions and 742 deletions

View File

@ -1,4 +1,6 @@
#include "Application.h"
#include "BuiltinLed.h"
#include "WifiStation.h"
#include <cstring>
#include "esp_log.h"
#include "model_path.h"
@ -94,19 +96,20 @@ void Application::Start() {
app->AudioDecodeTask();
}, "opus_decode", opus_stack_size, this, 1, audio_decode_task_stack_, &audio_decode_task_buffer_);
auto& builtin_led = BuiltinLed::GetInstance();
// Blink the LED to indicate the device is connecting
builtin_led_.SetBlue();
builtin_led_.BlinkOnce();
wifi_station_.Start();
builtin_led.SetBlue();
builtin_led.BlinkOnce();
WifiStation::GetInstance().Start();
// Check if there is a new firmware version available
firmware_upgrade_.CheckVersion();
if (firmware_upgrade_.HasNewVersion()) {
builtin_led_.TurnOn();
builtin_led.TurnOn();
firmware_upgrade_.StartUpgrade();
// If upgrade success, the device will reboot and never reach here
ESP_LOGI(TAG, "Firmware upgrade failed...");
builtin_led_.TurnOff();
builtin_led.TurnOff();
} else {
firmware_upgrade_.MarkValid();
}
@ -115,37 +118,38 @@ void Application::Start() {
StartDetection();
// Blink the LED to indicate the device is running
builtin_led_.SetGreen();
builtin_led_.BlinkOnce();
builtin_led.SetGreen();
builtin_led.BlinkOnce();
xEventGroupSetBits(event_group_, DETECTION_RUNNING);
}
void Application::SetChatState(ChatState state) {
auto& builtin_led = BuiltinLed::GetInstance();
chat_state_ = state;
switch (chat_state_) {
case kChatStateIdle:
ESP_LOGI(TAG, "Chat state: idle");
builtin_led_.TurnOff();
builtin_led.TurnOff();
break;
case kChatStateConnecting:
ESP_LOGI(TAG, "Chat state: connecting");
builtin_led_.SetBlue();
builtin_led_.TurnOn();
builtin_led.SetBlue();
builtin_led.TurnOn();
break;
case kChatStateListening:
ESP_LOGI(TAG, "Chat state: listening");
builtin_led_.SetRed();
builtin_led_.TurnOn();
builtin_led.SetRed();
builtin_led.TurnOn();
break;
case kChatStateSpeaking:
ESP_LOGI(TAG, "Chat state: speaking");
builtin_led_.SetGreen();
builtin_led_.TurnOn();
builtin_led.SetGreen();
builtin_led.TurnOn();
break;
case kChatStateWakeWordDetected:
ESP_LOGI(TAG, "Chat state: wake word detected");
builtin_led_.SetBlue();
builtin_led_.TurnOn();
builtin_led.SetBlue();
builtin_led.TurnOn();
break;
}

View File

@ -1,11 +1,9 @@
#ifndef _APPLICATION_H_
#define _APPLICATION_H_
#include "WifiStation.h"
#include "AudioDevice.h"
#include "OpusEncoder.h"
#include "WebSocketClient.h"
#include "BuiltinLed.h"
#include "FirmwareUpgrade.h"
#include "opus.h"
@ -33,14 +31,22 @@ enum ChatState {
class Application {
public:
Application();
~Application();
static Application& GetInstance() {
static Application instance;
return instance;
}
void Start();
// 删除拷贝构造函数和赋值运算符
Application(const Application&) = delete;
Application& operator=(const Application&) = delete;
private:
WifiStation wifi_station_;
Application();
~Application();
AudioDevice audio_device_;
BuiltinLed builtin_led_;
FirmwareUpgrade firmware_upgrade_;
std::recursive_mutex mutex_;

View File

@ -1,89 +0,0 @@
#include "BuiltinLed.h"
#include <cstring>
#include "driver/gpio.h"
#include "esp_log.h"
#define TAG "builtin_led"
BuiltinLed::BuiltinLed() {
mutex_ = xSemaphoreCreateMutex();
Configure();
SetGreen();
}
BuiltinLed::~BuiltinLed() {
if (blink_task_ != nullptr) {
vTaskDelete(blink_task_);
}
if (led_strip_ != nullptr) {
led_strip_del(led_strip_);
}
vSemaphoreDelete(mutex_);
}
void BuiltinLed::Configure() {
/* LED strip initialization with the GPIO and pixels number*/
led_strip_config_t strip_config;
bzero(&strip_config, sizeof(strip_config));
strip_config.strip_gpio_num = CONFIG_BUILTIN_LED_GPIO;
strip_config.max_leds = 1;
led_strip_rmt_config_t rmt_config;
bzero(&rmt_config, sizeof(rmt_config));
rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip_));
/* Set all LED off to clear all pixels */
led_strip_clear(led_strip_);
}
void BuiltinLed::SetColor(uint8_t r, uint8_t g, uint8_t b) {
r_ = r;
g_ = g;
b_ = b;
}
void BuiltinLed::TurnOn() {
xSemaphoreTake(mutex_, portMAX_DELAY);
led_strip_set_pixel(led_strip_, 0, r_, g_, b_);
led_strip_refresh(led_strip_);
xSemaphoreGive(mutex_);
}
void BuiltinLed::TurnOff() {
xSemaphoreTake(mutex_, portMAX_DELAY);
led_strip_clear(led_strip_);
xSemaphoreGive(mutex_);
}
void BuiltinLed::BlinkOnce() {
Blink(1, 100);
}
void BuiltinLed::Blink(int times, int interval_ms) {
xSemaphoreTake(mutex_, portMAX_DELAY);
struct BlinkTaskArgs {
BuiltinLed* self;
int times;
int interval_ms;
};
auto args = new BlinkTaskArgs {this, times, interval_ms};
xTaskCreate([](void* obj) {
auto args = (BlinkTaskArgs*) obj;
auto this_ = args->self;
for (int i = 0; i < args->times; i++) {
this_->TurnOn();
vTaskDelay(args->interval_ms / portTICK_PERIOD_MS);
this_->TurnOff();
vTaskDelay(args->interval_ms / portTICK_PERIOD_MS);
}
delete args;
this_->blink_task_ = nullptr;
vTaskDelete(NULL);
}, "blink", 4096, args, tskIDLE_PRIORITY, &blink_task_);
xSemaphoreGive(mutex_);
}

View File

@ -1,33 +0,0 @@
#ifndef _BUILTIN_LED_H_
#define _BUILTIN_LED_H_
#include "led_strip.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
class BuiltinLed {
public:
BuiltinLed();
~BuiltinLed();
void BlinkOnce();
void Blink(int times, int interval_ms);
void TurnOn();
void TurnOff();
void SetColor(uint8_t r, uint8_t g, uint8_t b);
void SetWhite() { SetColor(128, 128, 128); }
void SetGrey() { SetColor(32, 32, 32); }
void SetRed() { SetColor(128, 0, 0); }
void SetGreen() { SetColor(0, 128, 0); }
void SetBlue() { SetColor(0, 0, 128); }
private:
SemaphoreHandle_t mutex_;
TaskHandle_t blink_task_ = nullptr;
led_strip_handle_t led_strip_ = nullptr;
uint8_t r_ = 0, g_ = 0, b_ = 0;
void Configure();
};
#endif // _BUILTIN_LED_H_

View File

@ -3,15 +3,12 @@ set(SOURCES "AudioDevice.cc"
"SystemReset.cc"
"WebSocketClient.cc"
"OpusEncoder.cc"
"BuiltinLed.cc"
"Application.cc"
"WifiConfigurationAp.cc"
"main.cc"
"WifiStation.cc"
"FirmwareUpgrade.cc"
)
idf_component_register(SRCS ${SOURCES}
INCLUDE_DIRS "."
EMBED_TXTFILES "assets/wifi_configuration_ap.html"
)

View File

@ -18,13 +18,6 @@ config WEBSOCKET_ACCESS_TOKEN
help
Access token for websocket communication.
config BUILTIN_LED_GPIO
int "Builtin LED GPIO"
default 48
help
GPIO number of the builtin LED.
config AUDIO_INPUT_SAMPLE_RATE
int "Audio Input Sample Rate"
default 16000

View File

@ -1,284 +0,0 @@
#include "WifiConfigurationAp.h"
#include <cstdio>
#include "esp_err.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "esp_netif.h"
#include "lwip/ip_addr.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/task.h"
#define TAG "WifiConfigurationAp"
extern const char index_html_start[] asm("_binary_wifi_configuration_ap_html_start");
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
WifiConfigurationAp::WifiConfigurationAp()
{
event_group_ = xEventGroupCreate();
}
std::string WifiConfigurationAp::GetSsid()
{
// Get MAC and use it to generate a unique SSID
uint8_t mac[6];
ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP));
char ssid[32];
snprintf(ssid, sizeof(ssid), "ESP32-%02X%02X%02X", mac[3], mac[4], mac[5]);
return std::string(ssid);
}
void WifiConfigurationAp::StartAccessPoint()
{
// Get the SSID
std::string ssid = GetSsid();
// Register the WiFi event handler
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
[](void *ctx, esp_event_base_t event_base, int32_t event_id, void *event_data) {
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
ESP_LOGI(TAG, "Station connected: " MACSTR, MAC2STR(event->mac));
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
ESP_LOGI(TAG, "Station disconnected: " MACSTR, MAC2STR(event->mac));
} else if (event_id == WIFI_EVENT_STA_CONNECTED) {
xEventGroupSetBits(static_cast<WifiConfigurationAp *>(ctx)->event_group_, WIFI_CONNECTED_BIT);
} else if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
xEventGroupSetBits(static_cast<WifiConfigurationAp *>(ctx)->event_group_, WIFI_FAIL_BIT);
}
}, this));
// Initialize the TCP/IP stack
ESP_ERROR_CHECK(esp_netif_init());
// Create the default event loop
auto netif = esp_netif_create_default_wifi_ap();
// Set the router IP address to 192.168.4.1
esp_netif_ip_info_t ip_info;
IP4_ADDR(&ip_info.ip, 192, 168, 4, 1);
IP4_ADDR(&ip_info.gw, 192, 168, 4, 1);
IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
esp_netif_dhcps_stop(netif);
esp_netif_set_ip_info(netif, &ip_info);
esp_netif_dhcps_start(netif);
// Initialize the WiFi stack in Access Point mode
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Set the WiFi configuration
wifi_config_t wifi_config = {};
strcpy((char *)wifi_config.ap.ssid, ssid.c_str());
wifi_config.ap.ssid_len = ssid.length();
wifi_config.ap.max_connection = 4;
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
// Start the WiFi Access Point
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Access Point started with SSID %s", ssid.c_str());
}
void WifiConfigurationAp::StartWebServer()
{
// Start the web server
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_ERROR_CHECK(httpd_start(&server_, &config));
// Register the index.html file
httpd_uri_t index_html = {
.uri = "/",
.method = HTTP_GET,
.handler = [](httpd_req_t *req) -> esp_err_t {
httpd_resp_send(req, index_html_start, strlen(index_html_start));
return ESP_OK;
},
.user_ctx = NULL
};
ESP_ERROR_CHECK(httpd_register_uri_handler(server_, &index_html));
// Register the /scan URI
httpd_uri_t scan = {
.uri = "/scan",
.method = HTTP_GET,
.handler = [](httpd_req_t *req) -> esp_err_t {
esp_wifi_scan_start(nullptr, true);
uint16_t ap_num = 0;
esp_wifi_scan_get_ap_num(&ap_num);
wifi_ap_record_t *ap_records = (wifi_ap_record_t *)malloc(ap_num * sizeof(wifi_ap_record_t));
esp_wifi_scan_get_ap_records(&ap_num, ap_records);
// Send the scan results as JSON
httpd_resp_set_type(req, "application/json");
httpd_resp_sendstr_chunk(req, "[");
for (int i = 0; i < ap_num; i++) {
ESP_LOGI(TAG, "SSID: %s, RSSI: %d, Authmode: %d",
(char *)ap_records[i].ssid, ap_records[i].rssi, ap_records[i].authmode);
char buf[128];
snprintf(buf, sizeof(buf), "{\"ssid\":\"%s\",\"rssi\":%d,\"authmode\":%d}",
(char *)ap_records[i].ssid, ap_records[i].rssi, ap_records[i].authmode);
httpd_resp_sendstr_chunk(req, buf);
if (i < ap_num - 1) {
httpd_resp_sendstr_chunk(req, ",");
}
}
httpd_resp_sendstr_chunk(req, "]");
httpd_resp_sendstr_chunk(req, NULL);
free(ap_records);
return ESP_OK;
},
.user_ctx = NULL
};
ESP_ERROR_CHECK(httpd_register_uri_handler(server_, &scan));
// Register the form submission
httpd_uri_t form_submit = {
.uri = "/submit",
.method = HTTP_POST,
.handler = [](httpd_req_t *req) -> esp_err_t {
char buf[128];
int ret = httpd_req_recv(req, buf, sizeof(buf));
if (ret <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
httpd_resp_send_408(req);
}
return ESP_FAIL;
}
buf[ret] = '\0';
ESP_LOGI(TAG, "Received form data: %s", buf);
std::string decoded = UrlDecode(buf);
ESP_LOGI(TAG, "Decoded form data: %s", decoded.c_str());
// Parse the form data
char ssid[32], password[64];
if (sscanf(decoded.c_str(), "ssid=%32[^&]&password=%64s", ssid, password) != 2) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid form data");
return ESP_FAIL;
}
// Get this object from the user context
auto *this_ = static_cast<WifiConfigurationAp *>(req->user_ctx);
if (!this_->ConnectToWifi(ssid, password)) {
char error[] = "Failed to connect to WiFi";
char location[128];
snprintf(location, sizeof(location), "/?error=%s&ssid=%s", error, ssid);
httpd_resp_set_status(req, "302 Found");
httpd_resp_set_hdr(req, "Location", location);
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
// Set HTML response
httpd_resp_set_status(req, "200 OK");
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, "<h1>Done!</h1>", -1);
this_->Save(ssid, password);
return ESP_OK;
},
.user_ctx = this
};
ESP_ERROR_CHECK(httpd_register_uri_handler(server_, &form_submit));
ESP_LOGI(TAG, "Web server started");
}
std::string WifiConfigurationAp::UrlDecode(const std::string &url)
{
std::string decoded;
for (size_t i = 0; i < url.length(); ++i) {
if (url[i] == '%') {
char hex[3];
hex[0] = url[i + 1];
hex[1] = url[i + 2];
hex[2] = '\0';
char ch = static_cast<char>(std::stoi(hex, nullptr, 16));
decoded += ch;
i += 2;
} else if (url[i] == '+') {
decoded += ' ';
} else {
decoded += url[i];
}
}
return decoded;
}
void WifiConfigurationAp::Start()
{
builtin_led_.SetBlue();
builtin_led_.Blink(1000, 500);
StartAccessPoint();
StartWebServer();
}
bool WifiConfigurationAp::ConnectToWifi(const std::string &ssid, const std::string &password)
{
// auto esp_netif = esp_netif_create_default_wifi_sta();
wifi_config_t wifi_config;
bzero(&wifi_config, sizeof(wifi_config));
strcpy((char *)wifi_config.sta.ssid, ssid.c_str());
strcpy((char *)wifi_config.sta.password, password.c_str());
wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
wifi_config.sta.failure_retry_cnt = 1;
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
auto ret = esp_wifi_connect();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to connect to WiFi: %d", ret);
return false;
}
ESP_LOGI(TAG, "Connecting to WiFi %s", ssid.c_str());
// Wait for the connection to complete for 5 seconds
EventBits_t bits = xEventGroupWaitBits(event_group_, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000));
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "Connected to WiFi %s", ssid.c_str());
return true;
} else {
ESP_LOGE(TAG, "Failed to connect to WiFi %s", ssid.c_str());
return false;
}
}
void WifiConfigurationAp::Save(const std::string &ssid, const std::string &password)
{
// Open the NVS flash
nvs_handle_t nvs_handle;
ESP_ERROR_CHECK(nvs_open("wifi", NVS_READWRITE, &nvs_handle));
// Write the SSID and password to the NVS flash
ESP_ERROR_CHECK(nvs_set_str(nvs_handle, "ssid", ssid.c_str()));
ESP_ERROR_CHECK(nvs_set_str(nvs_handle, "password", password.c_str()));
// Commit the changes
ESP_ERROR_CHECK(nvs_commit(nvs_handle));
// Close the NVS flash
nvs_close(nvs_handle);
ESP_LOGI(TAG, "WiFi configuration saved");
// Use xTaskCreate to create a new task that restarts the ESP32
xTaskCreate([](void *ctx) {
ESP_LOGI(TAG, "Restarting the ESP32 in 3 second");
vTaskDelay(pdMS_TO_TICKS(3000));
esp_restart();
}, "restart_task", 4096, NULL, 5, NULL);
}

View File

@ -1,26 +0,0 @@
#ifndef _WIFI_CONFIGURATION_AP_H_
#define _WIFI_CONFIGURATION_AP_H_
#include <string>
#include "esp_http_server.h"
#include "BuiltinLed.h"
class WifiConfigurationAp {
public:
WifiConfigurationAp();
void Start();
private:
BuiltinLed builtin_led_;
httpd_handle_t server_ = NULL;
EventGroupHandle_t event_group_;
std::string GetSsid();
void StartAccessPoint();
void StartWebServer();
bool ConnectToWifi(const std::string &ssid, const std::string &password);
void Save(const std::string &ssid, const std::string &password);
static std::string UrlDecode(const std::string &url);
};
#endif // _WIFI_CONFIGURATION_AP_H_

View File

@ -1,107 +0,0 @@
#include "WifiStation.h"
#include <cstring>
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_system.h"
#define TAG "wifi"
#define WIFI_EVENT_CONNECTED BIT0
#define WIFI_EVENT_FAILED BIT1
#define MAX_RECONNECT_COUNT 5
WifiStation::WifiStation() {
// Get ssid and password from NVS
nvs_handle_t nvs_handle;
ESP_ERROR_CHECK(nvs_open("wifi", NVS_READONLY, &nvs_handle));
char ssid[32], password[64];
size_t length = sizeof(ssid);
ESP_ERROR_CHECK(nvs_get_str(nvs_handle, "ssid", ssid, &length));
length = sizeof(password);
ESP_ERROR_CHECK(nvs_get_str(nvs_handle, "password", password, &length));
nvs_close(nvs_handle);
ssid_ = std::string(ssid);
password_ = std::string(password);
// Create the event group
event_group_ = xEventGroupCreate();
// Register event handler
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
[](void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
auto this_ = static_cast<WifiStation*>(event_handler_arg);
if (event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
xEventGroupClearBits(this_->event_group_, WIFI_EVENT_CONNECTED);
if (this_->reconnect_count_ < MAX_RECONNECT_COUNT) {
esp_wifi_connect();
this_->reconnect_count_++;
ESP_LOGI(TAG, "Reconnecting to WiFi (attempt %d)", this_->reconnect_count_);
} else {
xEventGroupSetBits(this_->event_group_, WIFI_EVENT_FAILED);
ESP_LOGI(TAG, "Failed to connect to WiFi");
}
}
}, this));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
[](void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
auto this_ = static_cast<WifiStation*>(event_handler_arg);
auto event = static_cast<ip_event_got_ip_t*>(event_data);
char ip_address[16];
esp_ip4addr_ntoa(&event->ip_info.ip, ip_address, sizeof(ip_address));
this_->ip_address_ = ip_address;
ESP_LOGI(TAG, "Got IP: %s", this_->ip_address_.c_str());
xEventGroupSetBits(this_->event_group_, WIFI_EVENT_CONNECTED);
}, this));
}
void WifiStation::Start() {
// Initialize the TCP/IP stack
ESP_ERROR_CHECK(esp_netif_init());
// Create the default event loop
esp_netif_create_default_wifi_sta();
// Initialize the WiFi stack in station mode
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_LOGI(TAG, "Connecting to WiFi ssid=%s password=%s", ssid_.c_str(), password_.c_str());
wifi_config_t wifi_config;
bzero(&wifi_config, sizeof(wifi_config));
strcpy((char *)wifi_config.sta.ssid, ssid_.c_str());
strcpy((char *)wifi_config.sta.password, password_.c_str());
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
// Start the WiFi stack
ESP_ERROR_CHECK(esp_wifi_start());
// Wait for the WiFi stack to start
auto bits = xEventGroupWaitBits(event_group_, WIFI_EVENT_CONNECTED | WIFI_EVENT_FAILED, pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_EVENT_FAILED) {
ESP_LOGE(TAG, "WifiStation start failed");
} else {
ESP_LOGI(TAG, "WifiStation started");
}
// Get station info
wifi_ap_record_t ap_info;
ESP_ERROR_CHECK(esp_wifi_sta_get_ap_info(&ap_info));
ESP_LOGI(TAG, "Connected to %s rssi=%d channel=%d", ap_info.ssid, ap_info.rssi, ap_info.primary);
rssi_ = ap_info.rssi;
channel_ = ap_info.primary;
}
bool WifiStation::IsConnected() {
return xEventGroupGetBits(event_group_) & WIFI_EVENT_CONNECTED;
}

View File

@ -1,27 +0,0 @@
#ifndef _WIFI_STATION_H_
#define _WIFI_STATION_H_
#include <string>
#include "esp_event.h"
class WifiStation {
public:
WifiStation();
void Start();
bool IsConnected();
std::string ssid() { return ssid_; }
std::string ip_address() { return ip_address_; }
int8_t rssi() { return rssi_; }
uint8_t channel() { return channel_; }
private:
EventGroupHandle_t event_group_;
std::string ssid_;
std::string password_;
std::string ip_address_;
uint8_t rssi_ = 0;
uint8_t channel_ = 0;
int reconnect_count_ = 0;
};
#endif // _WIFI_STATION_H_

View File

@ -1,137 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>WiFi Configuration</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<style type="text/css">
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f0f0f0;
}
h1 {
text-align: center;
margin-top: 50px;
}
form {
width: 300px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
label {
display: block;
margin-bottom: 5px;
}
input {
width: 100%;
padding: 5px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 3px;
}
input[type="submit"] {
background-color: #007bff;
color: #fff;
border: none;
border-radius: 3px;
padding: 10px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
input[type="submit"]:disabled {
background-color: #ccc;
cursor: not-allowed;
}
#ap_list {
margin-top: 20px;
border-top: 1px solid #ccc;
padding-top: 10px;
}
#ap_list a {
display: block;
margin-top: 5px;
color: #007bff;
text-decoration: none;
}
#ap_list a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<h1>WiFi Configuration</h1>
<form action="/submit" method="post" onsubmit="button.disabled = true;">
<p class="error" style="color: red; text-align: center;" id="error">
</p>
<p>
<label for="ssid">SSID:</label>
<input type="text" id="ssid" name="ssid" required>
</p>
<p>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
</p>
<p style="text-align: center;">
<input type="submit" value="Submit" id="button">
</p>
<p id="ap_list">
</p>
</form>
<script type="text/javascript">
const button = document.getElementById('button');
const error = document.getElementById('error');
const ssid = document.getElementById('ssid');
const params = new URLSearchParams(window.location.search);
if (params.has('error')) {
error.textContent = params.get('error');
}
if (params.has('ssid')) {
ssid.value = params.get('ssid');
}
// Load AP list from /scan
function loadAPList() {
if (button.disabled) {
return;
}
fetch('/scan')
.then(response => response.json())
.then(data => {
const apList = document.getElementById('ap_list');
apList.innerHTML = '<p>Select an AP from the list below: </p>';
data.forEach(ap => {
// Create a link for each AP
const link = document.createElement('a');
link.href = '#';
link.textContent = ap.ssid + ' (' + ap.rssi + ' dBm)';
if (ap.authmode === 0) {
link.textContent += ' 🌐';
} else {
link.textContent += ' 🔒';
}
link.addEventListener('click', () => {
ssid.value = ap.ssid;
});
apList.appendChild(link);
});
setTimeout(loadAPList, 5000);
})
.catch(error => {
console.error('Error:', error);
});
}
loadAPList();
</script>
</body>
</html>

View File

@ -1,12 +1,14 @@
## IDF Component Manager Manifest File
dependencies:
78/esp-opus: "*"
78/esp-opus: "^1.0.2"
78/esp-builtin-led: "^1.0.0"
78/esp-wifi-connect: "^1.0.0"
espressif/esp_websocket_client: "^1.2.3"
espressif/led_strip: "*"
espressif/esp-sr: "^1.9.0"
## Required IDF version
idf:
version: ">=4.1.0"
version: ">=5.3"
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"

View File

@ -10,6 +10,7 @@
#include "Application.h"
#include "SystemInfo.h"
#include "SystemReset.h"
#include "BuiltinLed.h"
#define TAG "main"
#define STATS_TICKS pdMS_TO_TICKS(1000)
@ -37,15 +38,17 @@ extern "C" void app_main(void)
// If the WiFi configuration is not found, launch the WiFi configuration AP
if (ret != ESP_OK) {
auto app = new WifiConfigurationAp();
app->Start();
auto& builtin_led = BuiltinLed::GetInstance();
builtin_led.SetBlue();
builtin_led.Blink(1000, 500);
WifiConfigurationAp::GetInstance().Start("Xiaozhi");
return;
}
nvs_close(nvs_handle);
// Otherwise, launch the application
auto app = new Application();
app->Start();
Application::GetInstance().Start();
// Dump CPU usage every 10 second
while (true) {