- make wifi_provisioning component compatible with netwrok_interface component
- add i2s channel delete to deinit_player() - improve network interface component store IP and connection status of interfaces - improve UI http server Signed-off-by: Karl Osterseher <karli_o@gmx.at>
This commit is contained in:
59
README.md
59
README.md
@@ -4,7 +4,9 @@
|
||||
|
||||
## Feature list
|
||||
- FLAC, OPUS and PCM decoding currently supported
|
||||
- Wifi setup from menuconfig or through [ImprovWifi via Serial](https://www.improv-wifi.com/)
|
||||
- Wifi setup from menuconfig
|
||||
- WiFi provisioning via [ImprovWifi via Serial](https://www.improv-wifi.com/)<br>
|
||||
Ensure your browser supports this, Chrome or Edge will handle serial communication just fine.
|
||||
- Auto connect to snapcast server on network
|
||||
- Buffers up to 758ms on Wroom modules (tested with 44100:16:2)
|
||||
- Buffers more then enough on Wrover modules
|
||||
@@ -12,10 +14,10 @@
|
||||
- DSP / EQ functionality configurable through menuconfig and partly controllable through HTTP server running on ESP client (work in progress)
|
||||
|
||||
## Description
|
||||
I have continued the work from @badaix, @bridadan and @jorgenkraghjakobsen towards a ESP32 Snapcast
|
||||
client. Currently it support basic features like multiroom sync, network
|
||||
controlled volume and mute. For now it supports FLAC, OPUS, PCM 16bit
|
||||
audio streams with sample rates up to 48Khz maybe more, I didn't test.
|
||||
I have picked up the work from [bridadan](https://github.com/bridadan/libsnapcast) and [jorgenkraghjakobsen](https://github.com/jorgenkraghjakobsen/snapclient)
|
||||
towards a ESP32 Snapcast client. It is a full featured snapcast client which
|
||||
supports the codecs FLAC, OPUS and PCM 16bit audio streams with sample rates
|
||||
up to 48Khz maybe more, I didn't test.
|
||||
|
||||
Please check out the task list and feel free to fill in.
|
||||
|
||||
@@ -29,7 +31,7 @@ The codebase is split into components and build on <b>ESP-IDF v5.1.5</b>. I stil
|
||||
have some refactoring on the todo list as the concept has started to settle and
|
||||
allow for new features can be added in a structured manner. In the code you
|
||||
will find parts that are only partly related features and still not on the task
|
||||
list. Also there is a lot of code clean up needed.
|
||||
list. Also there is a lot of code clean up needed, as there is quite some dead code too.
|
||||
|
||||
Components
|
||||
- audio-board : taken from ADF, stripped down to strictly necessary parts for playback
|
||||
@@ -40,24 +42,26 @@ Components
|
||||
- esp-dsp : Submodule to the ESP-ADF done by David Douard
|
||||
- esp-peripherals : taken from ADF, stripped down to strictly necessary parts for usage with Lyrat v4.3
|
||||
- flac : flac audio encoder/decoder full submodule
|
||||
- libmedian: Median Filter implementation. Many thanks to @accabog https://github.com/accabog/MedianFilter
|
||||
- opus : Opus audio coder/decoder full submodule
|
||||
- libmedian: Median Filter implementation. Many thanks to [accabog](https://github.com/accabog/MedianFilter)
|
||||
- libbuffer : Generic buffer abstraction
|
||||
- lightsnapcast :
|
||||
* snapcast module, port of @bridadan scapcast packages decode library
|
||||
* player module, which is responsible for sync and low level I2S control
|
||||
- net_functions :
|
||||
- opus : Opus audio coder/decoder full submodule
|
||||
- ota_server :
|
||||
- protocol :
|
||||
- rtprx : Alternative RTP audio client UDP low latency also opus based
|
||||
- websocket :
|
||||
- websocket_if :
|
||||
- wifi_interface : wifi provisoning and init code for wifi module and AP connection
|
||||
- improv_wifi : WiFi provisioning via [ImprovWifi via Serial](https://www.improv-wifi.com/)
|
||||
- network_interface : init code for wifi module and AP connection and ethernet init code
|
||||
- ui_http_server : work in progress control interface for DSP functions
|
||||
|
||||
The snapclient functionanlity are implemented in a task included in main - but
|
||||
should be refactored to a component at some point.
|
||||
|
||||
I did my own syncing implementation which is different than @jorgenkraghjakobsen's
|
||||
I did my own syncing implementation which is different than jorgenkraghjakobsen's
|
||||
approach in the original repository, at least regarding syncing itself. I tried to
|
||||
replicate the behaivior of how badaix did it for his original snapclients.
|
||||
|
||||
@@ -83,26 +87,12 @@ end of a freeRTOS queue. Now the front end just needs to pass on the decoded aud
|
||||
data to the queue with the server timestamp and chunk size. The backend reads
|
||||
timestamps and waits until the audio chunk has the correct playback-delay
|
||||
to be written to the DAC amplifer speaker through i2s DMA. When the backend pipeline
|
||||
is in sync, any offset get rolled in by micro tuning the APLL on the ESP. No
|
||||
sample manipulation needed.
|
||||
is in sync, any offset gets corrected by inserting a single sample every chunk_ms,
|
||||
which is determined by the server.
|
||||
|
||||
|
||||
### Hardware
|
||||
You will need an ESP32 or ESP32-S2 and an I2S DAC. We recommend using a Lyrat board. For pinout see the config options.
|
||||
|
||||
- ESP pinout MA12070P
|
||||
------------------------------------------------------
|
||||
-> I2S_BCK Audio Clock 3.072 MHz
|
||||
-> I2S_WS Frame Word Select or L/R
|
||||
-> GND Ground
|
||||
-> I2S_DI Audio data 24bits LSB first
|
||||
-> MCLK Master clk connect to I2S_BCK
|
||||
-> I2C_SCL I2C clock
|
||||
-> I2C_SDA I2C Data
|
||||
-> GND Ground
|
||||
-> NENABLE Amplifier Enable active low
|
||||
-> NMUTE Amplifier Mute active low
|
||||
|
||||
You will need an ESP32 or ESP32-S2 and an I2S DAC. For pinout see the default config options in menuconfig (Audio Board).
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -148,19 +138,22 @@ idf.py menuconfig
|
||||
Configure to match your setup
|
||||
- <b>Audio HAL :</b> Choose your audio board
|
||||
- Lyrat (4.3, 4.2)
|
||||
- Lyrat TD (2.2, 2.1) --> not supported yet
|
||||
- Lyrat TD (2.2, 2.1)
|
||||
- Lyrat Mini (1.1)
|
||||
- KORVO DU1906 --> not supported yet
|
||||
- ESP32-S2 Kaluga (1.2) --> not supported yet
|
||||
- KORVO DU1906
|
||||
- ESP32-S2 Kaluga (1.2)
|
||||
- ESP-AI-Thinker-ES8388 (2.2)
|
||||
- Or a custom board
|
||||
- <b>Custom Audio Board :</b> Configure your DAC and GPIO
|
||||
- DAC Chip :
|
||||
- TI PCM51XX/TAS57XX DAC (PCM51XX are stereo DAC in TSSOP package and TAS57XX are class-D amp in HTSSOP package. Both have i2s input and i2c control)
|
||||
- TI PCM5102A DAC (Very basic stereo DAC WITHOUT i2c control)
|
||||
- TI TAS5805M DAC
|
||||
- Infineon MA120X0 (High power class-D amp in QFN package)
|
||||
- Analog Devices ADAU1961 (Stereo DAC with multiple analog inputs in LFCSP package)
|
||||
- Analog Devices MAX98357 (Very popular basic mono AMP without i2c control)
|
||||
- DAC I2C control interface : Choose GPIO pin of your I2C line and address of the DAC. If your DAC doesn't support I2C (PCM5102A or equivalent), put unused GPIO values.
|
||||
- Princton Technology PT8211
|
||||
- DAC I2C control interface : Choose GPIO pin of your I2C line and address of the DAC. If your DAC doesn't support I2C (PCM5102A or equivalent), set them to -1.
|
||||
- I2C master interface : GPIO pin of your DAC I2S bus.
|
||||
- DAC interface configuration : Configure specific GPIO for your DAC functionnalities. Use `?` to have more info.
|
||||
- <b>ESP32 DSP processor config :</b>
|
||||
@@ -175,7 +168,7 @@ Configure to match your setup
|
||||
- <b>Snapclient configuration :</b>
|
||||
- Use mDNS : The client will search on the network for the snapserver automatically. Your network must support mDNS.
|
||||
- Snapserver host : IP or URL of the server if mDNS is disabled or the mDNS resolution fail.
|
||||
- Snapserver port : Port of your snapserver, default is 1704.
|
||||
- Snapserver port : Port of your snapserver, default is 1704.
|
||||
- Snapclient name : The name under wich your ESP will appear on the Snapserver.
|
||||
- HTTP Server Setting : The ESP create a basic webpage. You can configure the port to view this page and configure the DSP.
|
||||
|
||||
@@ -217,7 +210,7 @@ On a linux box:
|
||||
|
||||
```
|
||||
cd snapclient
|
||||
idf.py build
|
||||
idf.py build
|
||||
curl snapclient.local:8032 --data-binary @- < build/snapclient.bin
|
||||
```
|
||||
Replace `snapclient.local` with your clients IP address. If you have multiple clients you could use the Android or Web App to find out your clients IPs.
|
||||
|
||||
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.15)
|
||||
SRCS "improvWifi.cpp" "improv_wrapper.cpp" "wifi_provisioning.c"
|
||||
PRIV_INCLUDE_DIRS "Improv-WiFi-Library/src" "priv_include"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES driver network_interface
|
||||
PRIV_REQUIRES driver esp_wifi network_interface
|
||||
#SRCS "Improv-WiFi-Library/src/ImprovWiFiLibrary.cpp" "wifi_provisioning.c"
|
||||
#INCLUDE_DIRS "Improv-WiFi-Library/src" "include"
|
||||
)
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/projdefs.h"
|
||||
#include "freertos/task.h"
|
||||
#include "improv_wrapper.h"
|
||||
#include "network_interface.h"
|
||||
#include "wifi_interface.h"
|
||||
|
||||
#define TAG "IMPROV"
|
||||
@@ -105,13 +107,10 @@ void improv_wifi_scan(unsigned char *scanResponse, int bufLen,
|
||||
|
||||
esp_wifi_scan_start(NULL, true);
|
||||
}
|
||||
// ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
|
||||
// ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
|
||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
|
||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(count));
|
||||
// ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds =
|
||||
// %u",
|
||||
// *count, number);
|
||||
|
||||
*count = 0;
|
||||
scanResponse[0] = 0;
|
||||
for (int i = 0; i < number; i++) {
|
||||
char rssiStr[8] = {
|
||||
@@ -120,7 +119,7 @@ void improv_wifi_scan(unsigned char *scanResponse, int bufLen,
|
||||
char cipherStr[8] = {
|
||||
0,
|
||||
};
|
||||
uint16_t neededLen;
|
||||
int16_t neededLen;
|
||||
|
||||
itoa(ap_info[i].rssi, rssiStr, 10);
|
||||
if (ap_info[i].authmode != WIFI_AUTH_OPEN) {
|
||||
@@ -140,19 +139,20 @@ void improv_wifi_scan(unsigned char *scanResponse, int bufLen,
|
||||
strcat((char *)scanResponse, (char *)"\n");
|
||||
|
||||
bufLen -= neededLen;
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
}
|
||||
|
||||
// ESP_LOGI(TAG, "APs \t\t%s", scanResponse);
|
||||
// ESP_LOGI(TAG, "APs \n%s", scanResponse);
|
||||
}
|
||||
|
||||
bool improv_wifi_connect(const char *ssid, const char *password) {
|
||||
uint8_t count = 0;
|
||||
wifi_ap_record_t apRec;
|
||||
esp_err_t err;
|
||||
esp_netif_ip_info_t ip;
|
||||
|
||||
while ((err = esp_wifi_sta_get_ap_info(&apRec)) != ESP_ERR_WIFI_NOT_CONNECT) {
|
||||
esp_wifi_disconnect();
|
||||
esp_wifi_disconnect();
|
||||
while (wifi_get_ip(&ip) == true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ bool improv_wifi_connect(const char *ssid, const char *password) {
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||
|
||||
esp_wifi_connect();
|
||||
while (esp_wifi_sta_get_ap_info(&apRec) != ESP_OK) {
|
||||
while (wifi_get_ip(&ip) == false) {
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
if (count > 20) {
|
||||
esp_wifi_disconnect();
|
||||
@@ -175,43 +175,42 @@ bool improv_wifi_connect(const char *ssid, const char *password) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
bool improv_wifi_is_connected(void) {
|
||||
wifi_ap_record_t apRec;
|
||||
bool ret = network_if_get_ip(NULL);
|
||||
|
||||
if (esp_wifi_sta_get_ap_info(&apRec) == ESP_OK) {
|
||||
// printf("connected\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// printf("NOT connected\n");
|
||||
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
void improv_wifi_get_local_ip(uint8_t *address) {
|
||||
esp_netif_ip_info_t ip_info;
|
||||
|
||||
// TODO: find a better way to do this
|
||||
do {
|
||||
esp_netif_get_ip_info(get_current_netif(), &ip_info);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
} while (ip_info.ip.addr == 0);
|
||||
if (network_if_get_ip(&ip_info) == false) {
|
||||
ESP_LOGE(TAG, "%s: no valid IP available", __func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
address[0] = ip_info.ip.addr >> 0;
|
||||
address[1] = ip_info.ip.addr >> 8;
|
||||
address[2] = ip_info.ip.addr >> 16;
|
||||
address[3] = ip_info.ip.addr >> 24;
|
||||
|
||||
// ESP_LOGI(TAG, "%d.%d.%d.%d", address[0], address[1], address[2],
|
||||
// address[3]);
|
||||
ESP_LOGI(TAG, "%d.%d.%d.%d", address[0], address[1], address[2], address[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
void improv_init(void) {
|
||||
uint8_t webPortStr[6] = {0};
|
||||
uint16_t webPort = CONFIG_WEB_PORT;
|
||||
uint8_t urlStr[26] = "http://{LOCAL_IPV4}:";
|
||||
|
||||
ESP_LOGI(TAG, "start IPROV WiFi provisioning service");
|
||||
|
||||
utoa(webPort, (char *)webPortStr, 10);
|
||||
strcat((char *)urlStr, (char *)webPortStr);
|
||||
|
||||
@@ -244,4 +243,5 @@ void improv_deinit(void) {
|
||||
t_improv_task = NULL;
|
||||
}
|
||||
improv_wifi_destroy();
|
||||
ESP_ERROR_CHECK(uart_driver_delete(UART_NUM_0));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "driver/i2s_common.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -319,6 +320,12 @@ int deinit_player(void) {
|
||||
playerTaskHandle = NULL;
|
||||
}
|
||||
|
||||
my_i2s_channel_disable(tx_chan);
|
||||
if (tx_chan) {
|
||||
i2s_del_channel(tx_chan);
|
||||
tx_chan = NULL;
|
||||
}
|
||||
|
||||
if (snapcastSettingsMux != NULL) {
|
||||
vSemaphoreDelete(snapcastSettingsMux);
|
||||
snapcastSettingsMux = NULL;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
idf_component_register(SRCS "network_interface.c" "eth_interface.c" "wifi_interface.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES driver esp_eth esp_netif esp_timer nvs_flash improv_wifi
|
||||
REQUIRES esp_wifi)
|
||||
PRIV_REQUIRES driver esp_wifi esp_eth esp_netif esp_timer nvs_flash improv_wifi)
|
||||
|
||||
@@ -27,6 +27,9 @@ static const char *TAG = "ETH_IF";
|
||||
|
||||
static uint8_t eth_port_cnt = 0;
|
||||
|
||||
static esp_netif_ip_info_t ip_info = {{0}, {0}, {0}};
|
||||
static bool connected = false;
|
||||
|
||||
#if CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM
|
||||
#define SPI_ETHERNETS_NUM CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM
|
||||
#else
|
||||
@@ -374,6 +377,33 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base,
|
||||
}
|
||||
}
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
static void lost_ip_event_handler(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;
|
||||
|
||||
for (int i = 0; i < eth_port_cnt; i++) {
|
||||
char if_desc_str[10];
|
||||
char num_str[3];
|
||||
|
||||
itoa(i, num_str, 10);
|
||||
strcat(strcpy(if_desc_str, NETWORK_INTERFACE_DESC_ETH), num_str);
|
||||
|
||||
if (network_is_our_netif(if_desc_str, event->esp_netif)) {
|
||||
// const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
|
||||
memcpy((void *)&ip_info, (const void *)&event->ip_info,
|
||||
sizeof(esp_netif_ip_info_t));
|
||||
|
||||
ESP_LOGI(TAG, "Ethernet Lost IP Address");
|
||||
|
||||
connected = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Event handler for IP_EVENT_ETH_GOT_IP */
|
||||
static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
@@ -387,20 +417,35 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
strcat(strcpy(if_desc_str, NETWORK_INTERFACE_DESC_ETH), num_str);
|
||||
|
||||
if (network_is_our_netif(if_desc_str, event->esp_netif)) {
|
||||
const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
// const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
|
||||
memcpy((void *)&ip_info, (const void *)&event->ip_info,
|
||||
sizeof(esp_netif_ip_info_t));
|
||||
|
||||
ESP_LOGI(TAG, "Ethernet Got IP Address");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
|
||||
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
|
||||
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
|
||||
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info.ip));
|
||||
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info.netmask));
|
||||
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info.gw));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
|
||||
connected = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
bool eth_get_ip(esp_netif_ip_info_t *ip) {
|
||||
if (ip) {
|
||||
memcpy((void *)ip, (const void *)&ip_info, sizeof(esp_netif_ip_info_t));
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
static void eth_on_got_ipv6(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data) {
|
||||
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
|
||||
@@ -465,6 +510,8 @@ void eth_start(void) {
|
||||
ð_event_handler, eth_netif));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP,
|
||||
&got_ip_event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_LOST_IP,
|
||||
&lost_ip_event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6,
|
||||
ð_on_got_ipv6, NULL));
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool eth_get_ip(esp_netif_ip_info_t *ip);
|
||||
void eth_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -22,8 +22,9 @@ extern char *ipv6_addr_types_to_str[6];
|
||||
|
||||
esp_netif_t *network_get_netif_from_desc(const char *desc);
|
||||
const char *network_get_ifkey(esp_netif_t *esp_netif);
|
||||
bool network_if_get_ip(esp_netif_ip_info_t *ip);
|
||||
bool network_is_netif_up(esp_netif_t *esp_netif);
|
||||
bool network_is_our_netif(const char *prefix, esp_netif_t *netif);
|
||||
void network_init(void);
|
||||
void network_if_init(void);
|
||||
|
||||
#endif /* COMPONENTS_NETWORK_INTERFACE_INCLUDE_NETWORK_INTERFACE_H_ */
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#ifndef _WIFI_INTERFACE_H_
|
||||
#define _WIFI_INTERFACE_H_
|
||||
|
||||
#include "esp_netif_types.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
// use wifi provisioning
|
||||
#define ENABLE_WIFI_PROVISIONING CONFIG_ENABLE_WIFI_PROVISIONING
|
||||
|
||||
@@ -19,14 +14,7 @@
|
||||
|
||||
#define WIFI_MAXIMUM_RETRY CONFIG_WIFI_MAXIMUM_RETRY
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about
|
||||
* two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
bool wifi_get_ip(esp_netif_ip_info_t *ip);
|
||||
void wifi_start(void);
|
||||
esp_netif_t *get_current_netif(void);
|
||||
|
||||
#endif /* _WIFI_INTERFACE_H_ */
|
||||
|
||||
@@ -67,7 +67,22 @@ bool network_is_netif_up(esp_netif_t *esp_netif) {
|
||||
return esp_netif_is_netif_up(esp_netif);
|
||||
}
|
||||
|
||||
void network_init(void) {
|
||||
bool network_if_get_ip(esp_netif_ip_info_t *ip) {
|
||||
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
|
||||
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
|
||||
if (eth_get_ip(ip) == true) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wifi_get_ip(ip) == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void network_if_init(void) {
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
|
||||
@@ -22,18 +22,19 @@
|
||||
#include "wifi_provisioning.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "WIFI";
|
||||
static const char *TAG = "WIFI_IF";
|
||||
|
||||
static void reset_reason_timer_counter_cb(void *);
|
||||
|
||||
static char mac_address[18];
|
||||
|
||||
EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
static esp_netif_t *esp_wifi_netif = NULL;
|
||||
|
||||
static esp_netif_ip_info_t ip_info = {{0}, {0}, {0}};
|
||||
static bool connected = false;
|
||||
|
||||
#if ENABLE_WIFI_PROVISIONING
|
||||
static esp_timer_handle_t resetReasonTimerHandle = NULL;
|
||||
static const esp_timer_create_args_t resetReasonTimerArgs = {
|
||||
@@ -95,18 +96,50 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
|
||||
return;
|
||||
}
|
||||
|
||||
const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
// const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
|
||||
memcpy((void *)&ip_info, (const void *)&event->ip_info,
|
||||
sizeof(esp_netif_ip_info_t));
|
||||
|
||||
ESP_LOGI(TAG, "Wifi Got IP Address");
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
ESP_LOGI(TAG, "WIFIIP:" IPSTR, IP2STR(&ip_info->ip));
|
||||
ESP_LOGI(TAG, "WIFIMASK:" IPSTR, IP2STR(&ip_info->netmask));
|
||||
ESP_LOGI(TAG, "WIFIGW:" IPSTR, IP2STR(&ip_info->gw));
|
||||
ESP_LOGI(TAG, "WIFIIP:" IPSTR, IP2STR(&ip_info.ip));
|
||||
ESP_LOGI(TAG, "WIFIMASK:" IPSTR, IP2STR(&ip_info.netmask));
|
||||
ESP_LOGI(TAG, "WIFIGW:" IPSTR, IP2STR(&ip_info.gw));
|
||||
ESP_LOGI(TAG, "~~~~~~~~~~~");
|
||||
|
||||
connected = true;
|
||||
|
||||
s_retry_num = 0;
|
||||
}
|
||||
|
||||
static void lost_ip_event_handler(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;
|
||||
if (!network_is_our_netif(NETWORK_INTERFACE_DESC_STA, event->esp_netif)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// const esp_netif_ip_info_t *ip_info = &event->ip_info;
|
||||
|
||||
memcpy((void *)&ip_info, (const void *)&event->ip_info,
|
||||
sizeof(esp_netif_ip_info_t));
|
||||
|
||||
connected = false;
|
||||
|
||||
ESP_LOGI(TAG, "Wifi Lost IP Address");
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
bool wifi_get_ip(esp_netif_ip_info_t *ip) {
|
||||
if (ip) {
|
||||
memcpy((void *)ip, (const void *)&ip_info, sizeof(esp_netif_ip_info_t));
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
void wifi_start(void) {
|
||||
@@ -122,11 +155,6 @@ void wifi_start(void) {
|
||||
esp_wifi_netif = esp_netif_create_wifi(WIFI_IF_STA, &esp_netif_config);
|
||||
esp_wifi_set_default_wifi_sta_handlers();
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT40));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_protocol(
|
||||
WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N));
|
||||
|
||||
// esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
|
||||
// esp_wifi_set_ps(WIFI_PS_NONE);
|
||||
|
||||
@@ -176,11 +204,23 @@ void wifi_start(void) {
|
||||
/* Start Wi-Fi station */
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_protocol(
|
||||
WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT40));
|
||||
|
||||
wifi_config_t wifi_config;
|
||||
ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));
|
||||
wifi_config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(
|
||||
WIFI_EVENT, ESP_EVENT_ANY_ID, (esp_event_handler_t)&event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||
&got_ip_event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_LOST_IP,
|
||||
&lost_ip_event_handler, NULL));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
ESP_LOGI(TAG, "Starting provisioning");
|
||||
@@ -206,6 +246,8 @@ void wifi_start(void) {
|
||||
WIFI_EVENT, ESP_EVENT_ANY_ID, (esp_event_handler_t)&event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
|
||||
&got_ip_event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_LOST_IP,
|
||||
&lost_ip_event_handler, NULL));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
@@ -213,5 +255,3 @@ void wifi_start(void) {
|
||||
wifi_config.sta.ssid);
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_netif_t *get_current_netif(void) { return esp_wifi_netif; }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
idf_component_register(SRCS "ui_http_server.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES spiffs esp_http_server mbedtls dsp_processor vfs esp_wifi)
|
||||
REQUIRES spiffs esp_http_server dsp_processor vfs)
|
||||
|
||||
# Create a SPIFFS image from the contents of the 'html' directory
|
||||
# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void init_http_server_task(char *key);
|
||||
void init_http_server_task(void);
|
||||
|
||||
typedef struct {
|
||||
char str_value[8];
|
||||
|
||||
@@ -8,31 +8,26 @@
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "ui_http_server.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "dsp_processor.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_wifi.h"
|
||||
// #include "esp_wifi.h"
|
||||
|
||||
#include "dsp_processor.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "ui_http_server.h"
|
||||
|
||||
static const char *TAG = "HTTP";
|
||||
static const char *TAG = "UI_HTTP";
|
||||
|
||||
static QueueHandle_t xQueueHttp;
|
||||
|
||||
static esp_netif_t *netInterface = NULL;
|
||||
static QueueHandle_t xQueueHttp = NULL;
|
||||
static TaskHandle_t taskHandle = NULL;
|
||||
static httpd_handle_t server = NULL;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -53,28 +48,32 @@ static void SPIFFS_Directory(char *path) {
|
||||
*
|
||||
*/
|
||||
static esp_err_t SPIFFS_Mount(char *path, char *label, int max_files) {
|
||||
esp_vfs_spiffs_conf_t conf = {.base_path = path,
|
||||
.partition_label = label,
|
||||
.max_files = max_files,
|
||||
.format_if_mount_failed = true};
|
||||
esp_err_t ret;
|
||||
|
||||
// Use settings defined above to initialize and mount SPIFFS file system.
|
||||
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
|
||||
esp_err_t ret = esp_vfs_spiffs_register(&conf);
|
||||
if (!esp_spiffs_mounted(label)) {
|
||||
esp_vfs_spiffs_conf_t conf = {.base_path = path,
|
||||
.partition_label = label,
|
||||
.max_files = max_files,
|
||||
.format_if_mount_failed = true};
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Failed to mount or format filesystem");
|
||||
} else if (ret == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
|
||||
// Use settings defined above to initialize and mount SPIFFS file system.
|
||||
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
|
||||
ret = esp_vfs_spiffs_register(&conf);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Failed to mount or format filesystem");
|
||||
} else if (ret == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t total = 0, used = 0;
|
||||
ret = esp_spiffs_info(conf.partition_label, &total, &used);
|
||||
ret = esp_spiffs_info(label, &total, &used);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)",
|
||||
esp_err_to_name(ret));
|
||||
@@ -258,9 +257,7 @@ static esp_err_t root_post_handler(httpd_req_t *req) {
|
||||
/* Redirect onto root to see the updated file list */
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
httpd_resp_set_hdr(req, "Location", "/");
|
||||
#ifdef CONFIG_EXAMPLE_HTTPD_CONN_CLOSE_HEADER
|
||||
httpd_resp_set_hdr(req, "Connection", "close");
|
||||
#endif
|
||||
// httpd_resp_set_hdr(req, "Connection", "close");
|
||||
httpd_resp_sendstr(req, "post successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -273,11 +270,21 @@ static esp_err_t favicon_get_handler(httpd_req_t *req) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
esp_err_t stop_server(void) {
|
||||
if (server) {
|
||||
httpd_stop(server);
|
||||
server = NULL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to start the web server
|
||||
*/
|
||||
esp_err_t start_server(const char *base_path, int port) {
|
||||
httpd_handle_t server = NULL;
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.server_port = port;
|
||||
config.max_open_sockets = 2;
|
||||
@@ -317,86 +324,15 @@ esp_err_t start_server(const char *base_path, int port) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//// LEDC Stuff
|
||||
//#define LEDC_TIMER LEDC_TIMER_0
|
||||
//#define LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
////#define LEDC_OUTPUT_IO (5) // Define the output GPIO
|
||||
//#define LEDC_OUTPUT_IO CONFIG_BLINK_GPIO // Define the output
|
||||
// GPIO #define LEDC_CHANNEL LEDC_CHANNEL_0 #define LEDC_DUTY_RES
|
||||
// LEDC_TIMER_13_BIT // Set duty resolution to 13 bits #define LEDC_DUTY
|
||||
//(4095) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095 #define LEDC_FREQUENCY
|
||||
//(5000) // Frequency in Hertz. Set frequency at 5 kHz
|
||||
//
|
||||
// static void ledc_init(void)
|
||||
//{
|
||||
// // Prepare and then apply the LEDC PWM timer configuration
|
||||
// ledc_timer_config_t ledc_timer = {
|
||||
// .speed_mode = LEDC_MODE,
|
||||
// .timer_num = LEDC_TIMER,
|
||||
// .duty_resolution = LEDC_DUTY_RES,
|
||||
// .freq_hz = LEDC_FREQUENCY, // Set output
|
||||
// frequency at 5 kHz .clk_cfg = LEDC_AUTO_CLK
|
||||
// };
|
||||
// ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
//
|
||||
// // Prepare and then apply the LEDC PWM channel configuration
|
||||
// ledc_channel_config_t ledc_channel = {
|
||||
// .speed_mode = LEDC_MODE,
|
||||
// .channel = LEDC_CHANNEL,
|
||||
// .timer_sel = LEDC_TIMER,
|
||||
// .intr_type = LEDC_INTR_DISABLE,
|
||||
// .gpio_num = LEDC_OUTPUT_IO,
|
||||
// .duty = 0, // Set duty to 0%
|
||||
// .hpoint = 0
|
||||
// };
|
||||
// ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
//}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void http_server_task(void *pvParameters) {
|
||||
/* Get the local IP address */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_get_ip_info(netInterface, &ip_info));
|
||||
|
||||
char ipString[64];
|
||||
sprintf(ipString, IPSTR, IP2STR(&ip_info.ip));
|
||||
|
||||
ESP_LOGI(TAG, "Start http task=%s", ipString);
|
||||
|
||||
char portString[6];
|
||||
sprintf(portString, "%d", CONFIG_WEB_PORT);
|
||||
|
||||
char url[strlen("http://") + strlen(ipString) + strlen(":") +
|
||||
strlen(portString) + 1];
|
||||
memset(url, 0, sizeof(url));
|
||||
strcat(url, ipString);
|
||||
strcat(url, ":");
|
||||
strcat(url, portString);
|
||||
|
||||
// Set the LEDC peripheral configuration
|
||||
// ledc_init();
|
||||
|
||||
// Set duty to 50%
|
||||
// double maxduty = pow(2, 13) - 1;
|
||||
// float percent = 0.5;
|
||||
// uint32_t duty = maxduty * percent;
|
||||
// ESP_LOGI(TAG, "duty=%"PRIu32, duty);
|
||||
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
|
||||
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
|
||||
// Update duty to apply the new value
|
||||
// ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
|
||||
|
||||
// Start Server
|
||||
ESP_LOGI(TAG, "Starting server on %s", url);
|
||||
ESP_ERROR_CHECK(start_server("/html", CONFIG_WEB_PORT));
|
||||
|
||||
URL_t urlBuf;
|
||||
while (1) {
|
||||
// ESP_LOGW (TAG, "stack free: %d", uxTaskGetStackHighWaterMark(NULL));
|
||||
|
||||
// Waiting for post
|
||||
if (xQueueReceive(xQueueHttp, &urlBuf, portMAX_DELAY) == pdTRUE) {
|
||||
filterParams_t filterParams;
|
||||
@@ -413,16 +349,6 @@ static void http_server_task(void *pvParameters) {
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
dsp_processor_update_filter_params(&filterParams);
|
||||
#endif
|
||||
|
||||
// Set duty value
|
||||
// percent = urlBuf.long_value / 100.0;
|
||||
// duty = maxduty * percent;
|
||||
// ESP_LOGI(TAG, "percent=%f duty=%"PRIu32,
|
||||
// percent, duty);
|
||||
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
|
||||
// Update duty to apply the new value
|
||||
// ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE,
|
||||
// LEDC_CHANNEL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,19 +360,7 @@ static void http_server_task(void *pvParameters) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void init_http_server_task(char *key) {
|
||||
if (!key) {
|
||||
ESP_LOGE(TAG,
|
||||
"key should be \"WIFI_STA_DEF\", \"WIFI_AP_DEF\" or \"ETH_DEF\"");
|
||||
return;
|
||||
}
|
||||
|
||||
netInterface = esp_netif_get_handle_from_ifkey(key);
|
||||
if (!netInterface) {
|
||||
ESP_LOGE(TAG, "can't get net interface for %s", key);
|
||||
return;
|
||||
}
|
||||
|
||||
void init_http_server_task(void) {
|
||||
// Initialize SPIFFS
|
||||
ESP_LOGI(TAG, "Initializing SPIFFS");
|
||||
if (SPIFFS_Mount("/html", "storage", 6) != ESP_OK) {
|
||||
@@ -455,9 +369,17 @@ void init_http_server_task(char *key) {
|
||||
}
|
||||
|
||||
// Create Queue
|
||||
xQueueHttp = xQueueCreate(10, sizeof(URL_t));
|
||||
configASSERT(xQueueHttp);
|
||||
if (!xQueueHttp) {
|
||||
xQueueHttp = xQueueCreate(10, sizeof(URL_t));
|
||||
configASSERT(xQueueHttp);
|
||||
}
|
||||
|
||||
xTaskCreatePinnedToCore(http_server_task, "HTTP", 512 * 5, NULL, 2, NULL,
|
||||
tskNO_AFFINITY);
|
||||
if (taskHandle) {
|
||||
stop_server();
|
||||
vTaskDelete(taskHandle);
|
||||
taskHandle = NULL;
|
||||
}
|
||||
|
||||
xTaskCreatePinnedToCore(http_server_task, "HTTP", 512 * 5, NULL, 2,
|
||||
&taskHandle, tskNO_AFFINITY);
|
||||
}
|
||||
|
||||
14
main/main.c
14
main/main.c
@@ -550,33 +550,35 @@ static void http_get_task(void *pvParameters) {
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Wait for network connection");
|
||||
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
|
||||
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
|
||||
esp_netif_t *eth_netif =
|
||||
network_get_netif_from_desc(NETWORK_INTERFACE_DESC_ETH);
|
||||
#endif
|
||||
esp_netif_t *sta_netif =
|
||||
network_get_netif_from_desc(NETWORK_INTERFACE_DESC_STA);
|
||||
while (1) {
|
||||
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
|
||||
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
|
||||
bool ethUp = network_is_netif_up(eth_netif);
|
||||
bool staUp = network_is_netif_up(sta_netif);
|
||||
|
||||
if (ethUp) {
|
||||
netif = eth_netif;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool staUp = network_is_netif_up(sta_netif);
|
||||
if (staUp) {
|
||||
netif = sta_netif;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Wait for WiFi or Eth");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SNAPCAST_SERVER_USE_MDNS
|
||||
// Find snapcast server
|
||||
@@ -2841,7 +2843,9 @@ void app_main(void) {
|
||||
init_http_server_task("WIFI_STA_DEF");
|
||||
#endif
|
||||
*/
|
||||
network_init();
|
||||
network_if_init();
|
||||
|
||||
init_http_server_task();
|
||||
|
||||
// Enable websocket server
|
||||
// ESP_LOGI(TAG, "Setup ws server");
|
||||
|
||||
Reference in New Issue
Block a user