AutoSpa/main/webserver.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!");
}
}