diff --git a/code/espurna/analog.ino b/code/espurna/analog.ino index 352ae707..bd865cef 100644 --- a/code/espurna/analog.ino +++ b/code/espurna/analog.ino @@ -19,10 +19,12 @@ unsigned int getAnalog() { void analogSetup() { pinMode(ANALOG_PIN, INPUT); - - apiRegister(ANALOG_TOPIC, ANALOG_TOPIC, [](char * buffer, size_t len) { - snprintf_P(buffer, len, PSTR("%d"), getAnalog()); - }); + + #if WEB_SUPPORT + apiRegister(ANALOG_TOPIC, ANALOG_TOPIC, [](char * buffer, size_t len) { + snprintf_P(buffer, len, PSTR("%d"), getAnalog()); + }); + #endif } @@ -51,9 +53,11 @@ void analogLoop() { #endif // Update websocket clients - char buffer[100]; - sprintf_P(buffer, PSTR("{\"analogVisible\": 1, \"analogValue\": %d}"), analog); - wsSend(buffer); + #if WEB_SUPPORT + char buffer[100]; + sprintf_P(buffer, PSTR("{\"analogVisible\": 1, \"analogValue\": %d}"), analog); + wsSend(buffer); + #endif } diff --git a/code/espurna/config/arduino.h b/code/espurna/config/arduino.h index 20e5b962..2b82b0c9 100644 --- a/code/espurna/config/arduino.h +++ b/code/espurna/config/arduino.h @@ -46,6 +46,8 @@ //#define ALEXA_SUPPORT 0 //#define ANALOG_SUPPORT 1 +//#define DEBUG_SERIAL_SUPPORT 0 +//#define DEBUG_UDP_SUPPORT 1 //#define DHT_SUPPORT 1 //#define DOMOTICZ_SUPPORT 0 //#define DS18B20_SUPPORT 1 @@ -55,7 +57,6 @@ //#define MDNS_SUPPORT 0 //#define NOFUSS_SUPPORT 1 //#define RF_SUPPORT 1 -//#define DEBUG_SERIAL_SUPPORT 0 //#define SPIFFS_SUPPORT 1 //#define TERMINAL_SUPPORT 0 -//#define DEBUG_UDP_SUPPORT 1 +//#define WEB_SUPPORT 0 diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index d5e17fe5..a4353ab0 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -227,10 +227,28 @@ PROGMEM const char* const custom_reset_string[] = { #define WIFI_MAX_NETWORKS 5 // Max number of WIFI connection configurations #define WIFI_AP_MODE AP_MODE_ALONE +// Optional hardcoded configuration (up to 2 different networks) +//#define WIFI1_SSID "..." +//#define WIFI1_PASS "..." +//#define WIFI1_IP "192.168.1.201" +//#define WIFI1_GW "192.168.1.1" +//#define WIFI1_MASK "255.255.255.0" +//#define WIFI1_DNS "8.8.8.8" +//#define WIFI2_SSID "..." +//#define WIFI2_PASS "..." + // ----------------------------------------------------------------------------- // WEB // ----------------------------------------------------------------------------- +#ifndef WEB_SUPPORT +#define WEB_SUPPORT 1 // This enables web support (http, api) +#endif + +#ifndef WEB_EMBEDDED +#define WEB_EMBEDDED 1 // This option builds the firmware with the web interface embedded. +#endif + #define WEB_MODE_NORMAL 0 #define WEB_MODE_PASSWORD 1 @@ -238,15 +256,12 @@ PROGMEM const char* const custom_reset_string[] = { #define WEB_FORCE_PASS_CHANGE 1 // Force the user to change the password if default one #define WEB_PORT 80 // HTTP port -// This option builds the firmware with the web interface embedded. -#ifndef WEB_EMBEDDED -#define WEB_EMBEDDED 1 -#endif - // ----------------------------------------------------------------------------- // WEBSOCKETS // ----------------------------------------------------------------------------- +// This will only be enabled if WEB_SUPPORT is 1 (this is the default value) + #define WS_BUFFER_SIZE 5 // Max number of secured websocket connections #define WS_TIMEOUT 1800000 // Timeout for secured websocket @@ -254,7 +269,9 @@ PROGMEM const char* const custom_reset_string[] = { // API // ----------------------------------------------------------------------------- -#define API_ENABLED 0 // Do not enable API by default +// This will only be enabled if WEB_SUPPORT is 1 (this is the default value) + +#define API_ENABLED 0 // Do not enable API by default #define API_BUFFER_SIZE 10 // Size of the buffer for HTTP GET API responses // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index d1131fad..ab20f7db 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -8,13 +8,17 @@ typedef std::function apiGetCallbackFunction; typedef std::function apiPutCallbackFunction; void apiRegister(const char * url, const char * key, apiGetCallbackFunction getFn, apiPutCallbackFunction putFn = NULL); + void mqttRegister(void (*callback)(unsigned int, const char *, const char *)); String mqttSubtopic(char * topic); + template bool setSetting(const String& key, T value); template bool setSetting(const String& key, unsigned int index, T value); template String getSetting(const String& key, T defaultValue); template String getSetting(const String& key, unsigned int index, T defaultValue); template void domoticzSend(const char * key, T value); template void domoticzSend(const char * key, T nvalue, const char * svalue); + template bool influxDBSend(const char * topic, T payload); + char * ltrim(char * s); diff --git a/code/espurna/dht.ino b/code/espurna/dht.ino index 0e0a3700..4da1aa5f 100644 --- a/code/espurna/dht.ino +++ b/code/espurna/dht.ino @@ -29,13 +29,18 @@ unsigned int getDHTHumidity() { } void dhtSetup() { + dht.begin(); - apiRegister(DHT_TEMPERATURE_TOPIC, DHT_TEMPERATURE_TOPIC, [](char * buffer, size_t len) { - dtostrf(_dhtTemperature, len-1, 1, buffer); - }); - apiRegister(DHT_HUMIDITY_TOPIC, DHT_HUMIDITY_TOPIC, [](char * buffer, size_t len) { - snprintf_P(buffer, len, PSTR("%d"), _dhtHumidity); - }); + + #if WEB_SUPPORT + apiRegister(DHT_TEMPERATURE_TOPIC, DHT_TEMPERATURE_TOPIC, [](char * buffer, size_t len) { + dtostrf(_dhtTemperature, len-1, 1, buffer); + }); + apiRegister(DHT_HUMIDITY_TOPIC, DHT_HUMIDITY_TOPIC, [](char * buffer, size_t len) { + snprintf_P(buffer, len, PSTR("%d"), _dhtHumidity); + }); + #endif + } void dhtLoop() { @@ -99,9 +104,11 @@ void dhtLoop() { #endif // Update websocket clients - char buffer[100]; - sprintf_P(buffer, PSTR("{\"dhtVisible\": 1, \"dhtTmp\": %s, \"dhtHum\": %s, \"tmpUnits\": %d}"), temperature, humidity, tmpUnits); - wsSend(buffer); + #if WEB_SUPPORT + char buffer[100]; + sprintf_P(buffer, PSTR("{\"dhtVisible\": 1, \"dhtTmp\": %s, \"dhtHum\": %s, \"tmpUnits\": %d}"), temperature, humidity, tmpUnits); + wsSend(buffer); + #endif } diff --git a/code/espurna/ds18b20.ino b/code/espurna/ds18b20.ino index 9a05d90e..45412e2f 100644 --- a/code/espurna/ds18b20.ino +++ b/code/espurna/ds18b20.ino @@ -34,12 +34,16 @@ const char* getDSTemperatureStr() { } void dsSetup() { + ds18b20.begin(); ds18b20.setWaitForConversion(false); - apiRegister(DS18B20_TEMPERATURE_TOPIC, DS18B20_TEMPERATURE_TOPIC, [](char * buffer, size_t len) { - dtostrf(_dsTemperature, len-1, 1, buffer); - }); + #if WEB_SUPPORT + apiRegister(DS18B20_TEMPERATURE_TOPIC, DS18B20_TEMPERATURE_TOPIC, [](char * buffer, size_t len) { + dtostrf(_dsTemperature, len-1, 1, buffer); + }); + #endif + } void dsLoop() { @@ -104,9 +108,11 @@ void dsLoop() { #endif // Update websocket clients - char buffer[100]; - sprintf_P(buffer, PSTR("{\"dsVisible\": 1, \"dsTmp\": %s, \"tmpUnits\": %d}"), getDSTemperatureStr(), tmpUnits); - wsSend(buffer); + #if WEB_SUPPORT + char buffer[100]; + sprintf_P(buffer, PSTR("{\"dsVisible\": 1, \"dsTmp\": %s, \"tmpUnits\": %d}"), getDSTemperatureStr(), tmpUnits); + wsSend(buffer); + #endif } diff --git a/code/espurna/emon.ino b/code/espurna/emon.ino index 5feea673..3aa1793c 100644 --- a/code/espurna/emon.ino +++ b/code/espurna/emon.ino @@ -111,21 +111,25 @@ void powerMonitorSetup() { brzo_i2c_end_transaction(); #endif - apiRegister(EMON_APOWER_TOPIC, EMON_APOWER_TOPIC, [](char * buffer, size_t len) { - if (_emonReady) { - snprintf_P(buffer, len, PSTR("%d"), _emonPower); - } else { - buffer = NULL; - } - }); + #if WEB_SUPPORT - apiRegister(EMON_CURRENT_TOPIC, EMON_CURRENT_TOPIC, [](char * buffer, size_t len) { - if (_emonReady) { - dtostrf(_emonCurrent, len-1, 3, buffer); - } else { - buffer = NULL; - } - }); + apiRegister(EMON_APOWER_TOPIC, EMON_APOWER_TOPIC, [](char * buffer, size_t len) { + if (_emonReady) { + snprintf_P(buffer, len, PSTR("%d"), _emonPower); + } else { + buffer = NULL; + } + }); + + apiRegister(EMON_CURRENT_TOPIC, EMON_CURRENT_TOPIC, [](char * buffer, size_t len) { + if (_emonReady) { + dtostrf(_emonCurrent, len-1, 3, buffer); + } else { + buffer = NULL; + } + }); + + #endif // WEB_SUPPORT } @@ -163,11 +167,11 @@ void powerMonitorLoop() { DEBUG_MSG_P(PSTR("[ENERGY] Power: %dW\n"), int(current * voltage)); // Update websocket clients - if (wsConnected()) { + #if WEB_SUPPORT char text[100]; sprintf_P(text, PSTR("{\"emonVisible\": 1, \"emonApparentPower\": %d, \"emonCurrent\": %s}"), int(current * voltage), String(current, 3).c_str()); wsSend(text); - } + #endif } diff --git a/code/espurna/espurna.ino b/code/espurna/espurna.ino index f19b7b6e..746f39f2 100644 --- a/code/espurna/espurna.ino +++ b/code/espurna/espurna.ino @@ -226,7 +226,10 @@ void setup() { saveSettings(); } - webSetup(); + #if WEB_SUPPORT + webSetup(); + #endif + #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE lightSetup(); #endif diff --git a/code/espurna/hlw8012.ino b/code/espurna/hlw8012.ino index 5a5d83ca..0f3b3ea0 100644 --- a/code/espurna/hlw8012.ino +++ b/code/espurna/hlw8012.ino @@ -158,28 +158,32 @@ void hlw8012Setup() { hlw8012RetrieveCalibration(); // API definitions - apiRegister(HLW8012_POWER_TOPIC, HLW8012_POWER_TOPIC, [](char * buffer, size_t len) { - if (_hlwReady) { - snprintf_P(buffer, len, PSTR("%d"), _hlwPower); - } else { - buffer = NULL; - } - }); - apiRegister(HLW8012_CURRENT_TOPIC, HLW8012_CURRENT_TOPIC, [](char * buffer, size_t len) { - if (_hlwReady) { - dtostrf(_hlwCurrent, len-1, 3, buffer); - } else { - buffer = NULL; - } - }); - apiRegister(HLW8012_VOLTAGE_TOPIC, HLW8012_VOLTAGE_TOPIC, [](char * buffer, size_t len) { - if (_hlwReady) { - snprintf_P(buffer, len, PSTR("%d"), _hlwVoltage); - } else { - buffer = NULL; - } - }); + #if WEB_SUPPORT + + apiRegister(HLW8012_POWER_TOPIC, HLW8012_POWER_TOPIC, [](char * buffer, size_t len) { + if (_hlwReady) { + snprintf_P(buffer, len, PSTR("%d"), _hlwPower); + } else { + buffer = NULL; + } + }); + apiRegister(HLW8012_CURRENT_TOPIC, HLW8012_CURRENT_TOPIC, [](char * buffer, size_t len) { + if (_hlwReady) { + dtostrf(_hlwCurrent, len-1, 3, buffer); + } else { + buffer = NULL; + } + }); + apiRegister(HLW8012_VOLTAGE_TOPIC, HLW8012_VOLTAGE_TOPIC, [](char * buffer, size_t len) { + if (_hlwReady) { + snprintf_P(buffer, len, PSTR("%d"), _hlwVoltage); + } else { + buffer = NULL; + } + }); + #endif // WEB_SUPPORT + } void hlw8012Loop() { @@ -244,8 +248,8 @@ void hlw8012Loop() { } voltage_previous = voltage; - if (wsConnected()) { - + #if WEB_SUPPORT + { unsigned int apparent = getApparentPower(); double factor = getPowerFactor(); unsigned int reactive = getReactivePower(); @@ -264,8 +268,8 @@ void hlw8012Loop() { String output; root.printTo(output); wsSend(output.c_str()); - } + #endif if (--report_count == 0) { diff --git a/code/espurna/light.ino b/code/espurna/light.ino index 18e1df1e..c143e1f0 100644 --- a/code/espurna/light.ino +++ b/code/espurna/light.ino @@ -391,6 +391,7 @@ void lightUpdate(bool save, bool forward) { if (forward) lightMQTT(); // Report color to WS clients (using current brightness setting) + #if WEB_SUPPORT { DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.createObject(); @@ -410,6 +411,7 @@ void lightUpdate(bool save, bool forward) { root.printTo(output); wsSend(output.c_str()); } + #endif // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily if (save) colorTicker.once(LIGHT_SAVE_DELAY, _lightColorSave); @@ -461,67 +463,71 @@ void lightBrightness(unsigned int b) { void _lightAPISetup() { - // API entry points (protected with apikey) - if (lightHasColor()) { + #if WEB_SUPPORT - apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR, - [](char * buffer, size_t len) { - _toRGB(buffer, len, false); - }, - [](const char * payload) { - lightColor(payload); - lightUpdate(true, true); - } - ); - - apiRegister(MQTT_TOPIC_BRIGHTNESS, MQTT_TOPIC_BRIGHTNESS, - [](char * buffer, size_t len) { - snprintf_P(buffer, len, PSTR("%d"), _brightness); - }, - [](const char * payload) { - lightBrightness(atoi(payload)); - lightUpdate(true, true); - } - ); + // API entry points (protected with apikey) + if (lightHasColor()) { - apiRegister(MQTT_TOPIC_KELVIN, MQTT_TOPIC_KELVIN, - [](char * buffer, size_t len) {}, - [](const char * payload) { - _fromKelvin(atol(payload)); - lightUpdate(true, true); - } - ); + apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR, + [](char * buffer, size_t len) { + _toRGB(buffer, len, false); + }, + [](const char * payload) { + lightColor(payload); + lightUpdate(true, true); + } + ); + + apiRegister(MQTT_TOPIC_BRIGHTNESS, MQTT_TOPIC_BRIGHTNESS, + [](char * buffer, size_t len) { + snprintf_P(buffer, len, PSTR("%d"), _brightness); + }, + [](const char * payload) { + lightBrightness(atoi(payload)); + lightUpdate(true, true); + } + ); + + apiRegister(MQTT_TOPIC_KELVIN, MQTT_TOPIC_KELVIN, + [](char * buffer, size_t len) {}, + [](const char * payload) { + _fromKelvin(atol(payload)); + lightUpdate(true, true); + } + ); + + apiRegister(MQTT_TOPIC_MIRED, MQTT_TOPIC_MIRED, + [](char * buffer, size_t len) {}, + [](const char * payload) { + _fromMireds(atol(payload)); + lightUpdate(true, true); + } + ); - apiRegister(MQTT_TOPIC_MIRED, MQTT_TOPIC_MIRED, - [](char * buffer, size_t len) {}, - [](const char * payload) { - _fromMireds(atol(payload)); - lightUpdate(true, true); - } - ); - - } + } - for (unsigned int id=0; id */ +#if WEB_SUPPORT + #include #include -#include #include -#include #include #include #include @@ -20,16 +20,23 @@ Copyright (C) 2016-2017 by Xose Pérez #include "static/index.html.gz.h" #endif +// ----------------------------------------------------------------------------- + AsyncWebServer * _server; -AsyncWebSocket ws("/ws"); -Ticker deferred; +char _last_modified[50]; +Ticker _web_defer; +// ----------------------------------------------------------------------------- + +AsyncWebSocket _ws("/ws"); typedef struct { IPAddress ip; unsigned long timestamp = 0; } ws_ticket_t; ws_ticket_t _ticket[WS_BUFFER_SIZE]; +// ----------------------------------------------------------------------------- + typedef struct { char * url; char * key; @@ -37,27 +44,12 @@ typedef struct { apiPutCallbackFunction putFn = NULL; } web_api_t; std::vector _apis; -char _last_modified[50]; // ----------------------------------------------------------------------------- // WEBSOCKETS // ----------------------------------------------------------------------------- -bool wsConnected() { - return (ws.count() > 0); -} - -bool wsSend(const char * payload) { - if (ws.count() > 0) { - ws.textAll(payload); - } -} - -bool wsSend(uint32_t client_id, const char * payload) { - ws.text(client_id, payload); -} - -void wsMQTTCallback(unsigned int type, const char * topic, const char * payload) { +void _wsMQTTCallback(unsigned int type, const char * topic, const char * payload) { if (type == MQTT_CONNECT_EVENT) { wsSend("{\"mqttStatus\": true}"); @@ -76,7 +68,7 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { JsonObject& root = jsonBuffer.parseObject((char *) payload); if (!root.success()) { DEBUG_MSG_P(PSTR("[WEBSOCKET] Error parsing data\n")); - ws.text(client_id, "{\"message\": \"Error parsing data!\"}"); + wsSend(client_id, "{\"message\": \"Error parsing data!\"}"); return; } @@ -111,7 +103,7 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { JsonObject& data = root["data"]; if (!data.containsKey("app") || (data["app"] != APP_NAME)) { - ws.text(client_id, "{\"message\": \"The file does not look like a valid configuration backup.\"}"); + wsSend(client_id, "{\"message\": \"The file does not look like a valid configuration backup.\"}"); return; } @@ -127,14 +119,14 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { saveSettings(); - ws.text(client_id, "{\"message\": \"Changes saved. You should reboot your board now.\"}"); + wsSend(client_id, "{\"message\": \"Changes saved. You should reboot your board now.\"}"); } if (action.equals("reconnect")) { // Let the HTTP request return and disconnect after 100ms - deferred.once_ms(100, wifiDisconnect); + _web_defer.once_ms(100, wifiDisconnect); } @@ -272,11 +264,11 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { } if (key == "adminPass2") { if (!value.equals(adminPass)) { - ws.text(client_id, "{\"message\": \"Passwords do not match!\"}"); + wsSend(client_id, "{\"message\": \"Passwords do not match!\"}"); return; } if (value.length() == 0) continue; - ws.text(client_id, "{\"action\": \"reload\"}"); + wsSend(client_id, "{\"action\": \"reload\"}"); key = String("adminPass"); } @@ -379,9 +371,9 @@ void _wsParse(uint32_t client_id, uint8_t * payload, size_t length) { } if (changed) { - ws.text(client_id, "{\"message\": \"Changes saved\"}"); + wsSend(client_id, "{\"message\": \"Changes saved\"}"); } else { - ws.text(client_id, "{\"message\": \"No changes detected\"}"); + wsSend(client_id, "{\"message\": \"No changes detected\"}"); } } @@ -397,7 +389,7 @@ void _wsStart(uint32_t client_id) { JsonObject& root = jsonBuffer.createObject(); bool changePassword = false; - #if WEB_PASS_CHANGE == 1 + #if WEB_FORCE_PASS_CHANGE String adminPass = getSetting("adminPass", ADMIN_PASS); if (adminPass.equals(ADMIN_PASS)) changePassword = true; #endif @@ -600,7 +592,7 @@ void _wsStart(uint32_t client_id) { String output; root.printTo(output); - ws.text(client_id, (char *) output.c_str()); + wsSend(client_id, (char *) output.c_str()); } @@ -616,7 +608,7 @@ bool _wsAuth(AsyncWebSocketClient * client) { if (index == WS_BUFFER_SIZE) { DEBUG_MSG_P(PSTR("[WEBSOCKET] Validation check failed\n")); - ws.text(client->id(), "{\"message\": \"Session expired, please reload page...\"}"); + wsSend(client->id(), "{\"message\": \"Session expired, please reload page...\"}"); return false; } @@ -665,21 +657,32 @@ void _wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTy } -// ----------------------------------------------------------------------------- -// WEBSERVER // ----------------------------------------------------------------------------- -void webLogRequest(AsyncWebServerRequest *request) { - DEBUG_MSG_P(PSTR("[WEBSERVER] Request: %s %s\n"), request->methodToString(), request->url().c_str()); +bool wsConnected() { + return (_ws.count() > 0); } -bool _authenticate(AsyncWebServerRequest *request) { - String password = getSetting("adminPass", ADMIN_PASS); - char httpPassword[password.length() + 1]; - password.toCharArray(httpPassword, password.length() + 1); - return request->authenticate(WEB_USERNAME, httpPassword); +bool wsSend(const char * payload) { + if (_ws.count() > 0) { + _ws.textAll(payload); + } +} + +bool wsSend(uint32_t client_id, const char * payload) { + _ws.text(client_id, payload); +} + +void wsSetup() { + _ws.onEvent(_wsEvent); + mqttRegister(_wsMQTTCallback); + _server->addHandler(&_ws); } +// ----------------------------------------------------------------------------- +// API +// ----------------------------------------------------------------------------- + bool _authAPI(AsyncWebServerRequest *request) { if (getSetting("apiEnabled", API_ENABLED).toInt() == 0) { @@ -718,7 +721,7 @@ ArRequestHandlerFunction _bindAPI(unsigned int apiID) { return [apiID](AsyncWebServerRequest *request) { - webLogRequest(request); + _webLog(request); if (!_authAPI(request)) return; web_api_t api = _apis[apiID]; @@ -757,28 +760,9 @@ ArRequestHandlerFunction _bindAPI(unsigned int apiID) { } -void apiRegister(const char * url, const char * key, apiGetCallbackFunction getFn, apiPutCallbackFunction putFn) { - - // Store it - web_api_t api; - char buffer[40]; - snprintf_P(buffer, strlen(buffer), PSTR("/api/%s"), url); - api.url = strdup(buffer); - api.key = strdup(key); - api.getFn = getFn; - api.putFn = putFn; - _apis.push_back(api); - - // Bind call - unsigned int methods = HTTP_GET; - if (putFn != NULL) methods += HTTP_PUT; - _server->on(buffer, methods, _bindAPI(_apis.size() - 1)); - -} - void _onAPIs(AsyncWebServerRequest *request) { - webLogRequest(request); + _webLog(request); if (!_authAPI(request)) return; @@ -805,7 +789,7 @@ void _onAPIs(AsyncWebServerRequest *request) { void _onRPC(AsyncWebServerRequest *request) { - webLogRequest(request); + _webLog(request); if (!_authAPI(request)) return; @@ -820,7 +804,7 @@ void _onRPC(AsyncWebServerRequest *request) { if (action.equals("reset")) { response = 200; - deferred.once_ms(100, []() { + _web_defer.once_ms(100, []() { customReset(CUSTOM_RESET_RPC); ESP.restart(); }); @@ -832,9 +816,50 @@ void _onRPC(AsyncWebServerRequest *request) { } +// ----------------------------------------------------------------------------- + +void apiRegister(const char * url, const char * key, apiGetCallbackFunction getFn, apiPutCallbackFunction putFn) { + + // Store it + web_api_t api; + char buffer[40]; + snprintf_P(buffer, strlen(buffer), PSTR("/api/%s"), url); + api.url = strdup(buffer); + api.key = strdup(key); + api.getFn = getFn; + api.putFn = putFn; + _apis.push_back(api); + + // Bind call + unsigned int methods = HTTP_GET; + if (putFn != NULL) methods += HTTP_PUT; + _server->on(buffer, methods, _bindAPI(_apis.size() - 1)); + +} + +void apiSetup() { + _server->on("/apis", HTTP_GET, _onAPIs); + _server->on("/rpc", HTTP_GET, _onRPC); +} + +// ----------------------------------------------------------------------------- +// WEBSERVER +// ----------------------------------------------------------------------------- + +void _webLog(AsyncWebServerRequest *request) { + DEBUG_MSG_P(PSTR("[WEBSERVER] Request: %s %s\n"), request->methodToString(), request->url().c_str()); +} + +bool _authenticate(AsyncWebServerRequest *request) { + String password = getSetting("adminPass", ADMIN_PASS); + char httpPassword[password.length() + 1]; + password.toCharArray(httpPassword, password.length() + 1); + return request->authenticate(WEB_USERNAME, httpPassword); +} + void _onAuth(AsyncWebServerRequest *request) { - webLogRequest(request); + _webLog(request); if (!_authenticate(request)) return request->requestAuthentication(); IPAddress ip = request->client()->remoteIP(); @@ -857,7 +882,7 @@ void _onAuth(AsyncWebServerRequest *request) { void _onGetConfig(AsyncWebServerRequest *request) { - webLogRequest(request); + _webLog(request); if (!_authenticate(request)) return request->requestAuthentication(); AsyncJsonResponse * response = new AsyncJsonResponse(); @@ -884,7 +909,7 @@ void _onGetConfig(AsyncWebServerRequest *request) { #if WEB_EMBEDDED void _onHome(AsyncWebServerRequest *request) { - webLogRequest(request); + _webLog(request); if (request->header("If-Modified-Since").equals(_last_modified)) { @@ -906,7 +931,7 @@ void _onUpgrade(AsyncWebServerRequest *request) { AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", Update.hasError() ? "FAIL" : "OK"); response->addHeader("Connection", "close"); if (!Update.hasError()) { - deferred.once_ms(100, []() { + _web_defer.once_ms(100, []() { customReset(CUSTOM_RESET_UPGRADE); ESP.restart(); }); @@ -944,20 +969,21 @@ void _onUpgradeData(AsyncWebServerRequest *request, String filename, size_t inde } } +// ----------------------------------------------------------------------------- + void webSetup() { + // Cache the Last-Modifier header value + sprintf_P(_last_modified, PSTR("%s %s GMT"), __DATE__, __TIME__); + // Create server _server = new AsyncWebServer(getSetting("webPort", WEB_PORT).toInt()); // Setup websocket - ws.onEvent(_wsEvent); - mqttRegister(wsMQTTCallback); + wsSetup(); - // Cache the Last-Modifier header value - sprintf_P(_last_modified, PSTR("%s %s GMT"), __DATE__, __TIME__); - - // Setup webserver - _server->addHandler(&ws); + // API setup + apiSetup(); // Rewrites _server->rewrite("/", "/index.html"); @@ -968,8 +994,6 @@ void webSetup() { #endif _server->on("/config", HTTP_GET, _onGetConfig); _server->on("/auth", HTTP_GET, _onAuth); - _server->on("/apis", HTTP_GET, _onAPIs); - _server->on("/rpc", HTTP_GET, _onRPC); _server->on("/upgrade", HTTP_POST, _onUpgrade, _onUpgradeData); // Serve static files @@ -977,7 +1001,7 @@ void webSetup() { _server->serveStatic("/", SPIFFS, "/") .setLastModified(_last_modified) .setFilter([](AsyncWebServerRequest *request) -> bool { - webLogRequest(request); + _webLog(request); return true; }); #endif @@ -992,3 +1016,5 @@ void webSetup() { DEBUG_MSG_P(PSTR("[WEBSERVER] Webserver running on port %d\n"), getSetting("webPort", WEB_PORT).toInt()); } + +#endif // WEB_SUPPORT diff --git a/code/espurna/wifi.ino b/code/espurna/wifi.ino index becea0bb..2ca55ebb 100644 --- a/code/espurna/wifi.ino +++ b/code/espurna/wifi.ino @@ -7,6 +7,7 @@ Copyright (C) 2016-2017 by Xose Pérez */ #include "JustWifi.h" +#include // ----------------------------------------------------------------------------- // WIFI @@ -115,8 +116,52 @@ void wifiStatus() { } +// Inject hardcoded networks +void wifiInject() { + + #ifdef WIFI1_SSID + if (getSetting("ssid", 0, "").length() == 0) setSetting("ssid", 0, WIFI1_SSID); + #endif + #ifdef WIFI1_PASS + if (getSetting("pass", 0, "").length() == 0) setSetting("pass", 0, WIFI1_PASS); + #endif + #ifdef WIFI1_IP + if (getSetting("ip", 0, "").length() == 0) setSetting("ip", 0, WIFI1_IP); + #endif + #ifdef WIFI1_GW + if (getSetting("gw", 0, "").length() == 0) setSetting("gw", 0, WIFI1_GW); + #endif + #ifdef WIFI1_MASK + if (getSetting("mask", 0, "").length() == 0) setSetting("mask", 0, WIFI1_MASK); + #endif + #ifdef WIFI1_DNS + if (getSetting("dns", 0, "").length() == 0) setSetting("dns", 0, WIFI1_DNS); + #endif + + #ifdef WIFI2_SSID + if (getSetting("ssid", 1, "").length() == 0) setSetting("ssid", 1, WIFI2_SSID); + #endif + #ifdef WIFI2_PASS + if (getSetting("pass", 1, "").length() == 0) setSetting("pass", 1, WIFI2_PASS); + #endif + #ifdef WIFI2_IP + if (getSetting("ip", 1, "").length() == 0) setSetting("ip", 1, WIFI2_IP); + #endif + #ifdef WIFI2_GW + if (getSetting("gw", 1, "").length() == 0) setSetting("gw", 1, WIFI2_GW); + #endif + #ifdef WIFI2_MASK + if (getSetting("mask", 1, "").length() == 0) setSetting("mask", 1, WIFI2_MASK); + #endif + #ifdef WIFI2_DNS + if (getSetting("dns", 1, "").length() == 0) setSetting("dns", 1, WIFI2_DNS); + #endif + +} + void wifiSetup() { + wifiInject(); wifiConfigure(); // Message callbacks