#include "http_server.h" #define TAG "httpd" static void handle_set_int(httpd_req_t* req, int* val) { char buf[128]; int buf_len = httpd_req_get_url_query_len(req) + 1; esp_err_t err; if (buf_len > 1) { if (buf_len > sizeof(buf)) { ESP_LOGI(TAG, "Invalid request. Query string too long."); httpd_resp_set_status(req, HTTPD_400); return; } if ((err = httpd_req_get_url_query_str(req, buf, buf_len)) == ESP_OK) { char param[32]; if (httpd_query_key_value(buf, "add", param, sizeof(param)) == ESP_OK) { *val += atoi(param); } else if (httpd_query_key_value(buf, "set", param, sizeof(param)) == ESP_OK) { *val = atoi(param); } else if (httpd_query_key_value(buf, "sub", param, sizeof(param)) == ESP_OK) { *val -= atoi(param); } else { ESP_LOGI(TAG, "No valid parameters."); httpd_resp_set_status(req, HTTPD_400); return; } } else { ESP_LOGI(TAG, "Unable to get URL query string. [%d]", err); httpd_resp_set_status(req, HTTPD_500); return; } } else { ESP_LOGI(TAG, "No query string provided?"); httpd_resp_set_status(req, HTTPD_400); return; } ESP_LOGI(TAG, "Now equals %d", *val); httpd_resp_set_status(req, HTTPD_204); } static void handle_set_bool(httpd_req_t* req, bool* val) { char buf[128]; int buf_len = httpd_req_get_url_query_len(req) + 1; if (buf_len > 1) { if (buf_len > sizeof(buf)) { ESP_LOGI(TAG, "Invalid request. Query string too long."); httpd_resp_set_status(req, HTTPD_400); return; } if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { char param[32]; if (httpd_query_key_value(buf, "set", param, sizeof(param)) == ESP_OK) { if (!strcmp(param, "on")) { *val = true; } else if (!strcmp(param, "off")) { *val = false; } else if (!strcmp(param, "toggle")) { *val = !*val; } else { ESP_LOGI(TAG, "Invalid request. Invalid param value."); httpd_resp_set_status(req, HTTPD_400); return; } } } } httpd_resp_set_status(req, HTTPD_204); } static void handle_set_uint8_t(httpd_req_t* req, uint8_t* val) { int tmp = *val; handle_set_int(req, &tmp); *val = tmp; } static void handle_set_uint32_t(httpd_req_t* req, uint32_t* val) { int tmp = *val; handle_set_int(req, &tmp); *val = tmp; } #define STATE_PARAM(typ, attr, ...) \ static esp_err_t handle_set_ ## attr (httpd_req_t *req) { \ ESP_LOGI(TAG, "Handling [%s] (%s)", #attr, req->uri); \ ws_params_t* params = (ws_params_t*) req->user_ctx; \ httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); \ handle_set_ ## typ (req, ¶ms->state. attr); \ httpd_resp_send(req, NULL, 0); \ return ESP_OK; \ } \ static httpd_uri_t http_ ## attr ## _handler = { \ .uri = "/" #attr, \ .method = HTTP_POST, \ .handler = handle_set_ ## attr, \ .user_ctx = NULL \ }; #include "state_params.i" #undef STATE_PARAM static size_t write_uint32_t_value( char** out, size_t len, const char* attr, const char* dn, uint32_t value) { size_t newlen = snprintf(*out, len, "\"%s\":{\"type\":\"uint32_t\",\"value\":\"%u\",\"disp\":\"%s\"}", attr, (unsigned int) value, dn); *out += newlen; return len - newlen; } static size_t write_uint8_t_value( char** out, size_t len, const char* attr, const char* dn, uint8_t value) { size_t newlen = snprintf(*out, len, "\"%s\":{\"type\":\"uint8_t\",\"value\":\"%u\",\"disp\":\"%s\"}", attr, (unsigned int)value, dn); *out += newlen; return len - newlen; } static size_t write_int_value( char** out, size_t len, const char* attr, const char* dn, int value) { size_t newlen = snprintf(*out, len, "\"%s\":{\"type\":\"int\",\"value\":\"%d\",\"disp\":\"%s\"}", attr, value, dn); *out += newlen; return len - newlen; } static size_t write_bool_value( char** out, size_t len, const char* attr, const char* dn, bool value) { size_t newlen = snprintf(*out, len, "\"%s\":{\"type\":\"bool\",\"value\":\"%s\",\"disp\":\"%s\"}", attr, value ? "on" : "off", dn); *out += newlen; return len - newlen; } static esp_err_t handle_get_params(httpd_req_t* req) { httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); \ size_t len = NUMBER_PARAMS * 128; char out_buffer[len + 1]; out_buffer[len] = 0; char* out_ptr = out_buffer; ws_params_t* ws_params = (ws_params_t*) req->user_ctx; bool write_comma = false; httpd_resp_set_type(req, "application/json"); if (len > 1) { *out_ptr = '{'; out_ptr ++; len --; } #define STATE_PARAM(typ, attr, display, ...) \ if (write_comma && len > 1) { \ *(out_ptr++) = ','; \ len --; \ } \ len = write_ ## typ ## _value( \ &out_ptr, len, #attr, display, ws_params->state. attr); \ write_comma = true; #include "state_params.i" #undef STATE_PARAM if (len > 3) { *(out_ptr++) = '}'; len --; *(out_ptr++) = '\r'; len --; *(out_ptr++) = '\n'; len --; } if (len > 1) { *(out_ptr++) = 0; len --; } httpd_resp_set_status(req, HTTPD_200); httpd_resp_send(req, out_buffer, strlen(out_buffer)); return ESP_OK; } static httpd_uri_t http_params_get_handler = { .uri = "/params", .method = HTTP_GET, .handler = handle_get_params, .user_ctx = NULL }; httpd_handle_t start_webserver(ws_params_t* params) { httpd_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.lru_purge_enable = true; config.max_uri_handlers = NUMBER_PARAMS + 1; ESP_LOGI(TAG, "Starting httpd server on port: '%d'", config.server_port); if (httpd_start(&server, &config) == ESP_OK) { http_params_get_handler.user_ctx = params; httpd_register_uri_handler(server, &http_params_get_handler); #define STATE_PARAM(typ, attr, ...) \ ESP_LOGI(TAG, "Registering URI handler [%s]", #attr); \ http_ ## attr ## _handler.user_ctx = params; \ httpd_register_uri_handler(server, & http_ ## attr ## _handler); #include "state_params.i" #undef STATE_PARAM return server; } ESP_LOGI(TAG, "Error starting server!"); return NULL; }