246 lines
7.8 KiB
C
246 lines
7.8 KiB
C
#include "webserver.h"
|
|
#include "esp_event.h"
|
|
#include "esp_http_server.h"
|
|
#include "esp_log.h"
|
|
#include "esp_mac.h"
|
|
#include "esp_system.h"
|
|
#include "esp_wifi.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "nvs_flash.h"
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#define AP_WIFI_SSID "AutoSpa"
|
|
#define AP_WIFI_PASS "autospa123"
|
|
#define AP_MAX_CONN 4
|
|
#define AP_WIFI_CHANNEL 1
|
|
|
|
#define STA_WIFI_SSID "Big_Blue_House"
|
|
#define STA_WIFI_PASS "tDMiar*2024"
|
|
|
|
static const char *TAG = "webserver";
|
|
static volatile int s_check_id_req = 0;
|
|
|
|
// Log buffer
|
|
#define LOG_BUF_SIZE 4096
|
|
static char log_buffer[LOG_BUF_SIZE];
|
|
static int log_head = 0;
|
|
|
|
void web_log(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
char temp[256];
|
|
int len = vsnprintf(temp, sizeof(temp), fmt, args);
|
|
va_end(args);
|
|
|
|
if (len > 0) {
|
|
if (log_head + len < LOG_BUF_SIZE - 1) {
|
|
memcpy(log_buffer + log_head, temp, len);
|
|
log_head += len;
|
|
log_buffer[log_head] = '\0';
|
|
} else {
|
|
log_head = 0;
|
|
memcpy(log_buffer + log_head, temp, len);
|
|
log_head += len;
|
|
log_buffer[log_head] = '\0';
|
|
}
|
|
ESP_LOGI(TAG, "%s", temp);
|
|
}
|
|
}
|
|
|
|
int check_id_requested(void) {
|
|
if (s_check_id_req) {
|
|
s_check_id_req = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* WiFi AP Event Handler */
|
|
/* WiFi Event Handler */
|
|
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
|
int32_t event_id, void *event_data) {
|
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED) {
|
|
wifi_event_ap_staconnected_t *event =
|
|
(wifi_event_ap_staconnected_t *)event_data;
|
|
ESP_LOGI(TAG, "station " MACSTR " joined, AID=%d", MAC2STR(event->mac),
|
|
event->aid);
|
|
web_log("Client connected!\n");
|
|
} else if (event_base == WIFI_EVENT &&
|
|
event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
|
wifi_event_ap_stadisconnected_t *event =
|
|
(wifi_event_ap_stadisconnected_t *)event_data;
|
|
ESP_LOGI(TAG, "station " MACSTR " left, AID=%d", MAC2STR(event->mac),
|
|
event->aid);
|
|
web_log("Client disconnected.\n");
|
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
esp_wifi_connect();
|
|
} else if (event_base == WIFI_EVENT &&
|
|
event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
esp_wifi_connect();
|
|
ESP_LOGI(TAG, "retry to connect to the AP");
|
|
web_log("Retry to connect to the AP\n");
|
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
|
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
|
web_log("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
|
|
start_webserver();
|
|
}
|
|
}
|
|
|
|
void wifi_init_ap(void) {
|
|
ESP_ERROR_CHECK(esp_netif_init());
|
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
esp_netif_create_default_wifi_ap();
|
|
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
|
|
|
|
wifi_config_t wifi_config = {
|
|
.ap =
|
|
{
|
|
.ssid = AP_WIFI_SSID,
|
|
.ssid_len = strlen(AP_WIFI_SSID),
|
|
.channel = AP_WIFI_CHANNEL,
|
|
.password = AP_WIFI_PASS,
|
|
.max_connection = AP_MAX_CONN,
|
|
.authmode = WIFI_AUTH_WPA2_PSK,
|
|
.pmf_cfg = {.required = true},
|
|
},
|
|
};
|
|
|
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
|
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
|
|
ESP_ERROR_CHECK(esp_wifi_start());
|
|
|
|
ESP_LOGI(TAG, "SoftAP started. SSID: %s, Password: %s", AP_WIFI_SSID,
|
|
AP_WIFI_PASS);
|
|
ESP_LOGI(TAG, "Connect to this WiFi and browse to http://192.168.4.1:9099");
|
|
}
|
|
|
|
void wifi_init_sta(void) {
|
|
ESP_ERROR_CHECK(esp_netif_init());
|
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
esp_netif_create_default_wifi_sta();
|
|
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));
|
|
|
|
wifi_config_t wifi_config = {
|
|
.sta =
|
|
{
|
|
.ssid = STA_WIFI_SSID,
|
|
.password = STA_WIFI_PASS,
|
|
/* Setting a password implies station will connect to all security
|
|
* modes including WEP/WPA. However these modes are deprecated and
|
|
* not advised to be used. Incase your Access point doesn't
|
|
* support WPA2, these mode can be enabled by commenting below
|
|
* line */
|
|
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
|
|
},
|
|
};
|
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
|
ESP_ERROR_CHECK(esp_wifi_start());
|
|
|
|
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
|
}
|
|
|
|
/* HTTP Server Handlers */
|
|
static const char *index_html =
|
|
"<!DOCTYPE html><html><head><title>AD5940 Control</title></head><body>"
|
|
"<h1>AD5940 ESP32-S3 Dashboard</h1>"
|
|
"<button onclick=\"sendCommand('check_id')\">Check ID</button>"
|
|
"<h2>Console Log</h2>"
|
|
"<pre id=\"console\" "
|
|
"style=\"background:#eee;padding:10px;height:300px;overflow:auto;\"></pre>"
|
|
"<script>"
|
|
"function sendCommand(cmd) {"
|
|
" fetch('/api/command', {method:'POST', "
|
|
"body:JSON.stringify({command:cmd})});"
|
|
"}"
|
|
"setInterval(() => {"
|
|
" fetch('/api/log').then(r => r.text()).then(t => {"
|
|
" if(t) document.getElementById('console').textContent = t;"
|
|
" });"
|
|
"}, 1000);"
|
|
"</script></body></html>";
|
|
|
|
static esp_err_t root_get_handler(httpd_req_t *req) {
|
|
ESP_LOGI(TAG, "Request received for %s", req->uri);
|
|
httpd_resp_send(req, index_html, HTTPD_RESP_USE_STRLEN);
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t command_post_handler(httpd_req_t *req) {
|
|
char buf[100];
|
|
int ret, remaining = req->content_len;
|
|
|
|
if (remaining >= sizeof(buf)) {
|
|
remaining = sizeof(buf) - 1;
|
|
}
|
|
|
|
ret = httpd_req_recv(req, buf, remaining);
|
|
if (ret <= 0)
|
|
return ESP_FAIL;
|
|
buf[ret] = '\0';
|
|
|
|
if (strstr(buf, "check_id")) {
|
|
s_check_id_req = 1;
|
|
web_log("Command received: Check ID\n");
|
|
}
|
|
|
|
httpd_resp_send(req, "OK", HTTPD_RESP_USE_STRLEN);
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t log_get_handler(httpd_req_t *req) {
|
|
httpd_resp_set_type(req, "text/plain");
|
|
httpd_resp_send(req, log_buffer, HTTPD_RESP_USE_STRLEN);
|
|
// Note: This sends the whole buffer every time.
|
|
// Optimization: implement cursor or clear on read.
|
|
// For now, this is enough for "Check ID" simple verification.
|
|
return ESP_OK;
|
|
}
|
|
|
|
void start_webserver(void) {
|
|
httpd_handle_t server = NULL;
|
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
|
config.server_port = 9099;
|
|
config.lru_purge_enable = true;
|
|
|
|
ESP_LOGI(TAG, "Starting web server"); // Log to serial for debug too
|
|
if (httpd_start(&server, &config) == ESP_OK) {
|
|
ESP_LOGI(TAG, "Web server started on port %d", config.server_port);
|
|
httpd_uri_t root = {.uri = "/",
|
|
.method = HTTP_GET,
|
|
.handler = root_get_handler,
|
|
.user_ctx = NULL};
|
|
httpd_register_uri_handler(server, &root);
|
|
|
|
httpd_uri_t cmd = {.uri = "/api/command",
|
|
.method = HTTP_POST,
|
|
.handler = command_post_handler,
|
|
.user_ctx = NULL};
|
|
httpd_register_uri_handler(server, &cmd);
|
|
|
|
httpd_uri_t log_uri = {.uri = "/api/log",
|
|
.method = HTTP_GET,
|
|
.handler = log_get_handler,
|
|
.user_ctx = NULL};
|
|
httpd_register_uri_handler(server, &log_uri);
|
|
} else {
|
|
ESP_LOGE(TAG, "Error starting server!");
|
|
}
|
|
}
|