diff --git a/platformio.ini b/platformio.ini index f31f3d8a..b357a037 100755 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ extra_configs = platformio-user.ini [common] framework = arduino -lib_deps = HanReader@1.0.1, ArduinoJson@6.14.1, MQTT@2.4.7, DallasTemperature@3.8.1, EspSoftwareSerial@6.7.1, Base64@1.0.0, RemoteDebug@3.0.5, Time@1.6 +lib_deps = HanReader@1.0.1, ArduinoJson@6.14.1, MQTT@2.4.7, DallasTemperature@3.8.1, EspSoftwareSerial@6.7.1, Base64@1.0.0, RemoteDebug@3.0.5, Time@1.6, NTPClient@3.1.0 [env:hw1esp12e] platform = espressif8266@2.3.3 diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index 63b09317..b64ec19f 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -179,6 +179,10 @@ void AmsConfiguration::clearMqtt() { setMqttPassword(""); } +void AmsConfiguration::setMqttChanged() { + mqttChanged = true; +} + bool AmsConfiguration::isMqttChanged() { return mqttChanged; } diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index 68591466..e25638e5 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -52,6 +52,7 @@ public: void setMqttSsl(bool mqttSsl); void clearMqtt(); + void setMqttChanged(); bool isMqttChanged(); void ackMqttChange(); diff --git a/src/AmsStorage.h b/src/AmsStorage.h new file mode 100644 index 00000000..51194c87 --- /dev/null +++ b/src/AmsStorage.h @@ -0,0 +1,10 @@ +#ifndef _AMSSTORAGE_H +#define _AMSSTORAGE_H + +#define FILE_FIRMWARE "/firmware.bin" + +#define FILE_MQTT_CA "/mqtt-ca.pem" +#define FILE_MQTT_CERT "/mqtt-cert.pem" +#define FILE_MQTT_KEY "/mqtt-key.pem" + +#endif diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 7cb9d811..5029001d 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -17,10 +17,12 @@ */ #include "AmsToMqttBridge.h" +#include "AmsStorage.h" #define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e9 #include #include #include +#include #if defined(ESP8266) ADC_MODE(ADC_VCC); @@ -46,6 +48,9 @@ HwTools hw; DNSServer dnsServer; +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "pool.ntp.org", 3600, 60000); + AmsConfiguration config; RemoteDebug Debug; @@ -121,7 +126,7 @@ void setup() { if(spiffs) { bool flashed = false; - if(SPIFFS.exists("/firmware.bin")) { + if(SPIFFS.exists(FILE_FIRMWARE)) { if(Debug.isActive(RemoteDebug::INFO)) debugI("Found firmware"); #if defined(ESP8266) WiFi.setSleepMode(WIFI_LIGHT_SLEEP); @@ -140,7 +145,7 @@ void setup() { } if(Debug.isActive(RemoteDebug::INFO)) debugI(" flashing"); - File firmwareFile = SPIFFS.open("/firmware.bin", "r"); + File firmwareFile = SPIFFS.open(FILE_FIRMWARE, "r"); uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; if (!Update.begin(maxSketchSpace, U_FLASH)) { if(Debug.isActive(RemoteDebug::ERROR)) { @@ -156,7 +161,7 @@ void setup() { flashed = Update.end(true); } firmwareFile.close(); - SPIFFS.remove("/firmware.bin"); + SPIFFS.remove(FILE_FIRMWARE); } SPIFFS.end(); if(flashed) { @@ -227,6 +232,7 @@ void setup() { } ws.setup(&config, &mqtt); + timeClient.begin(); #if HAS_RGB_LED //Signal startup by blinking red / green / yellow @@ -290,6 +296,8 @@ void loop() { errorBlink(); } + timeClient.update(); + // Only do normal stuff if we're not booted as AP if (WiFi.getMode() != WIFI_AP) { led_off(); @@ -621,7 +629,7 @@ void MQTT_connect() { if(Debug.isActive(RemoteDebug::WARNING)) debugW("No MQTT config"); return; } - if(millis() - lastMqttRetry < 5000) { + if(millis() - lastMqttRetry < (mqtt.lastError() == 0 ? 5000 : 60000)) { yield(); return; } @@ -633,79 +641,39 @@ void MQTT_connect() { mqtt.disconnect(); yield(); + WiFiClientSecure *secureClient; Client *client; if(config.isMqttSsl()) { debugI("MQTT SSL is configured"); - WiFiClientSecure *secureClient = new WiFiClientSecure(); - bool spiffs = false; -#if defined(ESP32) - debugD("ESP32 SPIFFS"); - spiffs = SPIFFS.begin(true); -#else - debugD("ESP8266 SPIFFS"); - spiffs = SPIFFS.begin(); + if(!timeClient.update()) debugW("NTP time is not ready"); + + secureClient = new WiFiClientSecure(); +#if defined(ESP8266) + secureClient->setBufferSizes(512, 512); #endif - bool caExists = false; - if(spiffs) { + if(SPIFFS.begin()) { char *ca = NULL; char *cert = NULL; char *key = NULL; - if(SPIFFS.exists("/mqtt-ca.cer")) { + + if(SPIFFS.exists(FILE_MQTT_CA)) { debugI("Found MQTT CA file"); - File file = SPIFFS.open("/mqtt-ca.cer", "r"); - ca = new char[file.size()]; - if (file.size() != file.readBytes(ca, file.size())) { - delete ca; - ca = NULL; - } + File file = SPIFFS.open(FILE_MQTT_CA, "r"); + secureClient->loadCACert(file, file.size()); } - if(SPIFFS.exists("/mqtt-cert.cer")) { + if(SPIFFS.exists(FILE_MQTT_CERT)) { debugI("Found MQTT certificate file"); - File file = SPIFFS.open("/mqtt-cert.cer", "r"); - cert = new char[file.size()]; - if (file.size() != file.readBytes(cert, file.size())) { - delete cert; - cert = NULL; - } + File file = SPIFFS.open(FILE_MQTT_CERT, "r"); + secureClient->loadCertificate(file, file.size()); } - if(SPIFFS.exists("/mqtt-key.cer")) { + if(SPIFFS.exists(FILE_MQTT_KEY)) { debugI("Found MQTT key file"); - File file = SPIFFS.open("/mqtt-key.cer", "r"); - key = new char[file.size()]; - if (file.size() != file.readBytes(key, file.size())) { - delete key; - key = NULL; - } + File file = SPIFFS.open(FILE_MQTT_KEY, "r"); + secureClient->loadPrivateKey(file, file.size()); } SPIFFS.end(); - - if(ca) { -#ifdef ESP32 - secureClient->setCACert(ca); -#else - secureClient->setTrustAnchors(new X509List(ca)); - secureClient->allowSelfSignedCerts(); -#endif - caExists = true; - } - if(cert && key) { -#ifdef ESP32 - secureClient->setCertificate(cert); - secureClient->setPrivateKey(key); -#else - secureClient->setClientRSACert(new X509List(cert), new PrivateKey(key)); -#endif - } - } - if(!caExists) { - debugW("No CA found, using insecure"); -#ifdef ESP32 - // TODO -#else - secureClient->setInsecure(); -#endif } client = secureClient; } else { @@ -714,6 +682,10 @@ void MQTT_connect() { mqtt.begin(config.getMqttHost().c_str(), config.getMqttPort(), *client); +#if defined(ESP8266) + if(secureClient) secureClient->setX509Time(timeClient.getEpochTime()); +#endif + // Connect to a unsecure or secure MQTT server if ((config.getMqttUser().isEmpty() && mqtt.connect(config.getMqttClientId().c_str())) || (!config.getMqttUser().isEmpty() && mqtt.connect(config.getMqttClientId().c_str(), config.getMqttUser().c_str(), config.getMqttPassword().c_str()))) { @@ -732,9 +704,15 @@ void MQTT_connect() { sendSystemStatusToMqtt(); } } else { - lastMqttRetry = millis() + 30000; if (Debug.isActive(RemoteDebug::ERROR)) { - debugI("Failed to connect to MQTT"); + debugE("Failed to connect to MQTT"); +#if defined(ESP8266) + if(secureClient) { + char buf[256]; + secureClient->getLastSSLError(buf,256); + Debug.println(buf); + } +#endif } } yield(); diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 9f2056f0..127415c4 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -1,7 +1,9 @@ #include "AmsWebServer.h" #include "version.h" +#include "AmsStorage.h" #include "root/index_html.h" +#include "root/index_js.h" #include "root/configmeter_html.h" #include "root/configwifi_html.h" #include "root/configmqtt_html.h" @@ -11,6 +13,7 @@ #include "root/boot_css.h" #include "root/gaugemeter_js.h" #include "root/upload_html.h" +#include "root/delete_html.h" #include "Base64.h" @@ -22,7 +25,8 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { this->config = config; this->mqtt = mqtt; - server.on("/", std::bind(&AmsWebServer::indexHtml, this)); + server.on("/", HTTP_GET, std::bind(&AmsWebServer::indexHtml, this)); + server.on("/index.js", HTTP_GET, std::bind(&AmsWebServer::indexJs, this)); server.on("/config-meter", HTTP_GET, std::bind(&AmsWebServer::configMeterHtml, this)); server.on("/config-wifi", HTTP_GET, std::bind(&AmsWebServer::configWifiHtml, this)); server.on("/config-mqtt", HTTP_GET, std::bind(&AmsWebServer::configMqttHtml, this)); @@ -40,10 +44,13 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { server.on("/mqtt-ca", HTTP_GET, std::bind(&AmsWebServer::mqttCa, this)); server.on("/mqtt-ca", HTTP_POST, std::bind(&AmsWebServer::uploadPost, this), std::bind(&AmsWebServer::mqttCaUpload, this)); + server.on("/mqtt-ca/delete", HTTP_POST, std::bind(&AmsWebServer::mqttCaDelete, this)); server.on("/mqtt-cert", HTTP_GET, std::bind(&AmsWebServer::mqttCert, this)); server.on("/mqtt-cert", HTTP_POST, std::bind(&AmsWebServer::uploadPost, this), std::bind(&AmsWebServer::mqttCertUpload, this)); + server.on("/mqtt-cert/delete", HTTP_POST, std::bind(&AmsWebServer::mqttCertDelete, this)); server.on("/mqtt-key", HTTP_GET, std::bind(&AmsWebServer::mqttKey, this)); server.on("/mqtt-key", HTTP_POST, std::bind(&AmsWebServer::uploadPost, this), std::bind(&AmsWebServer::mqttKeyUpload, this)); + server.on("/mqtt-key/delete", HTTP_POST, std::bind(&AmsWebServer::mqttKeyDelete, this)); server.begin(); // Web server start } @@ -93,6 +100,10 @@ bool AmsWebServer::checkSecurity(byte level) { server.setContentLength(0); server.send(401, "text/html", ""); } + if(access) + printD(" access granted"); + else + printD(" access denied"); return access; } @@ -163,6 +174,13 @@ void AmsWebServer::indexHtml() { server.send(200, "text/html", html); } +void AmsWebServer::indexJs() { + printD("Serving /index.js over http..."); + + server.sendHeader("Cache-Control", "public, max-age=3600"); + server.send_P(200, "application/javascript", INDEX_JS); +} + void AmsWebServer::configMeterHtml() { printD("Serving /config-meter.html over http..."); @@ -264,12 +282,12 @@ void AmsWebServer::configMqttHtml() { html.replace("${display.ssl}", config->isMqttSsl() ? "" : "none"); if(SPIFFS.begin()) { - html.replace("${display.ca.upload}", SPIFFS.exists("/mqtt-ca.pem") ? "none" : ""); - html.replace("${display.ca.file}", SPIFFS.exists("/mqtt-ca.pem") ? "" : "none"); - html.replace("${display.cert.upload}", SPIFFS.exists("/mqtt-cert.pem") ? "none" : ""); - html.replace("${display.cert.file}", SPIFFS.exists("/mqtt-cert.pem") ? "" : "none"); - html.replace("${display.key.upload}", SPIFFS.exists("/mqtt-key.pem") ? "none" : ""); - html.replace("${display.key.file}", SPIFFS.exists("/mqtt-key.pem") ? "" : "none"); + html.replace("${display.ca.upload}", SPIFFS.exists(FILE_MQTT_CA) ? "none" : ""); + html.replace("${display.ca.file}", SPIFFS.exists(FILE_MQTT_CA) ? "" : "none"); + html.replace("${display.cert.upload}", SPIFFS.exists(FILE_MQTT_CERT) ? "none" : ""); + html.replace("${display.cert.file}", SPIFFS.exists(FILE_MQTT_CERT) ? "" : "none"); + html.replace("${display.key.upload}", SPIFFS.exists(FILE_MQTT_KEY) ? "none" : ""); + html.replace("${display.key.file}", SPIFFS.exists(FILE_MQTT_KEY) ? "" : "none"); SPIFFS.end(); } else { html.replace("${display.ca.upload}", ""); @@ -314,23 +332,15 @@ void AmsWebServer::configWebHtml() { void AmsWebServer::bootCss() { printD("Serving /boot.css over http..."); - String css = String((const __FlashStringHelper*) BOOT_CSS); - server.sendHeader("Cache-Control", "public, max-age=3600"); - - server.setContentLength(css.length()); - server.send(200, "text/css", css); + server.send_P(200, "text/css", BOOT_CSS); } void AmsWebServer::gaugemeterJs() { printD("Serving /gaugemeter.js over http..."); - String js = String((const __FlashStringHelper*) GAUGEMETER_JS); - server.sendHeader("Cache-Control", "public, max-age=3600"); - - server.setContentLength(js.length()); - server.send(200, "application/javascript", js); + server.send_P(200, "application/javascript", GAUGEMETER_JS); } void AmsWebServer::dataJson() { @@ -604,38 +614,56 @@ void AmsWebServer::uploadPost() { server.send(200); } -void AmsWebServer::configSystemUpload() { +void AmsWebServer::uploadFile(const char* path) { HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ String filename = upload.filename; - if(!filename.endsWith(".bin")) { - server.send(500, "text/plain", "500: couldn't create file"); - } else if (!SPIFFS.begin()) { + if (!SPIFFS.begin()) { printE("An Error has occurred while mounting SPIFFS"); String html = "

Error uploading!

"; server.send(500, "text/html", html); } else { printD("handleFileUpload Name: %s", filename.c_str()); - firmwareFile = SPIFFS.open("/firmware.bin", "w"); + file = SPIFFS.open(path, "w"); filename = String(); } } else if(upload.status == UPLOAD_FILE_WRITE) { - if(firmwareFile) - firmwareFile.write(upload.buf, upload.currentSize); + if(file) + file.write(upload.buf, upload.currentSize); } else if(upload.status == UPLOAD_FILE_END) { - if(firmwareFile) { - firmwareFile.close(); + if(file) { + file.close(); SPIFFS.end(); printD("handleFileUpload Size: %d", upload.totalSize); - performRestart = true; - server.sendHeader("Location","/restart-wait"); - server.send(303); } else { server.send(500, "text/plain", "500: couldn't create file"); } } } +void AmsWebServer::deleteFile(const char* path) { + if(SPIFFS.begin()) { + SPIFFS.remove(path); + SPIFFS.end(); + } +} + +void AmsWebServer::configSystemUpload() { + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START) { + String filename = upload.filename; + if(!filename.endsWith(".bin")) { + server.send(500, "text/plain", "500: couldn't create file"); + } + } + uploadFile(FILE_FIRMWARE); + if(upload.status == UPLOAD_FILE_END) { + performRestart = true; + server.sendHeader("Location","/restart-wait"); + server.send(303); + } +} + void AmsWebServer::restartWaitHtml() { printD("Serving /restart-wait.html over http..."); @@ -680,154 +708,166 @@ void AmsWebServer::isAliveCheck() { server.send(200); } -void AmsWebServer::mqttCa() { - printD("Serving /mqtt-ca.html over http..."); - +void AmsWebServer::uploadHtml(const char* label, const char* action, const char* menu) { String html = String((const __FlashStringHelper*) UPLOAD_HTML); + html.replace("${form.action}", action); + html.replace("${version}", VERSION); + + if(WiFi.getMode() != WIFI_AP) { + html.replace("boot.css", BOOTSTRAP_URL); + } + + html.replace("${menu." + String(menu) + ".class}", "active"); html.replace("${menu.meter.class}", ""); html.replace("${menu.wifi.class}", ""); - html.replace("${menu.mqtt.class}", "active"); + html.replace("${menu.mqtt.class}", ""); html.replace("${menu.web.class}", ""); html.replace("${menu.system.class}", ""); - html.replace("${file.label}", "CA file"); + html.replace("${file.label}", label); - server.sendHeader("Cache-Control", "public, max-age=3600"); + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); server.setContentLength(html.length()); server.send(200, "text/html", html); } -void AmsWebServer::mqttCaUpload() { - HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = upload.filename; - if (!SPIFFS.begin()) { - printE("An Error has occurred while mounting SPIFFS"); - String html = "

Error uploading!

"; - server.send(500, "text/html", html); +void AmsWebServer::deleteHtml(const char* label, const char* action, const char* menu) { + String html = String((const __FlashStringHelper*) DELETE_HTML); + html.replace("${form.action}", action); + html.replace("${version}", VERSION); + + if(WiFi.getMode() != WIFI_AP) { + html.replace("boot.css", BOOTSTRAP_URL); + } + + html.replace("${menu." + String(menu) + ".class}", "active"); + html.replace("${menu.meter.class}", ""); + html.replace("${menu.wifi.class}", ""); + html.replace("${menu.mqtt.class}", ""); + html.replace("${menu.web.class}", ""); + html.replace("${menu.system.class}", ""); + html.replace("${file.label}", label); + + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); + + server.setContentLength(html.length()); + server.send(200, "text/html", html); +} + +void AmsWebServer::mqttCa() { + printD("Serving /mqtt-ca.html over http..."); + + String html; + if(SPIFFS.begin()) { + if(SPIFFS.exists(FILE_MQTT_CA)) { + deleteHtml("CA file", "/mqtt-ca/delete", "mqtt"); } else { - printD("handleFileUpload Name: %s", filename.c_str()); - mqttCaFile = SPIFFS.open("/mqtt-ca.pem", "w"); - filename = String(); - } - } else if(upload.status == UPLOAD_FILE_WRITE) { - if(mqttCaFile) - mqttCaFile.write(upload.buf, upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END) { - if(mqttCaFile) { - mqttCaFile.close(); - SPIFFS.end(); - printD("handleFileUpload Size: %d", upload.totalSize); - server.sendHeader("Location","/config-mqtt"); - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } - } + uploadHtml("CA file", "/mqtt-ca", "mqtt"); + } + SPIFFS.end(); + } else { + server.sendHeader("Location","/config-mqtt"); + server.send(303); + } +} + +void AmsWebServer::mqttCaUpload() { + uploadFile(FILE_MQTT_CA); + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_END) { + server.sendHeader("Location","/config-mqtt"); + server.send(303); + if(config->isMqttSsl()) { + config->setMqttChanged(); + } + } } void AmsWebServer::mqttCaDelete() { - + deleteFile(FILE_MQTT_CA); + server.sendHeader("Location","/config-mqtt"); + server.send(303); + if(config->isMqttSsl()) { + config->setMqttChanged(); + } } void AmsWebServer::mqttCert() { printD("Serving /mqtt-cert.html over http..."); - String html = String((const __FlashStringHelper*) UPLOAD_HTML); - html.replace("${menu.meter.class}", ""); - html.replace("${menu.wifi.class}", ""); - html.replace("${menu.mqtt.class}", "active"); - html.replace("${menu.web.class}", ""); - html.replace("${menu.system.class}", ""); - html.replace("${file.label}", "Certificate"); - - server.sendHeader("Cache-Control", "public, max-age=3600"); - - server.setContentLength(html.length()); - server.send(200, "text/html", html); + String html; + if(SPIFFS.begin()) { + if(SPIFFS.exists(FILE_MQTT_CERT)) { + deleteHtml("Certificate", "/mqtt-cert/delete", "mqtt"); + } else { + uploadHtml("Certificate", "/mqtt-cert", "mqtt"); + } + SPIFFS.end(); + } else { + server.sendHeader("Location","/config-mqtt"); + server.send(303); + } } void AmsWebServer::mqttCertUpload() { + uploadFile(FILE_MQTT_CERT); HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = upload.filename; - if (!SPIFFS.begin()) { - printE("An Error has occurred while mounting SPIFFS"); - String html = "

Error uploading!

"; - server.send(500, "text/html", html); - } else { - printD("handleFileUpload Name: %s", filename.c_str()); - mqttCertFile = SPIFFS.open("/mqtt-cert.pem", "w"); - filename = String(); - } - } else if(upload.status == UPLOAD_FILE_WRITE) { - if(mqttCertFile) - mqttCertFile.write(upload.buf, upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END) { - if(mqttCertFile) { - mqttCertFile.close(); - SPIFFS.end(); - printD("handleFileUpload Size: %d", upload.totalSize); - server.sendHeader("Location","/config-mqtt"); - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } - } + if(upload.status == UPLOAD_FILE_END) { + server.sendHeader("Location","/config-mqtt"); + server.send(303); + if(config->isMqttSsl()) { + config->setMqttChanged(); + } + } } void AmsWebServer::mqttCertDelete() { - + deleteFile(FILE_MQTT_CERT); + server.sendHeader("Location","/config-mqtt"); + server.send(303); + if(config->isMqttSsl()) { + config->setMqttChanged(); + } } void AmsWebServer::mqttKey() { printD("Serving /mqtt-key.html over http..."); - String html = String((const __FlashStringHelper*) UPLOAD_HTML); - html.replace("${menu.meter.class}", ""); - html.replace("${menu.wifi.class}", ""); - html.replace("${menu.mqtt.class}", "active"); - html.replace("${menu.web.class}", ""); - html.replace("${menu.system.class}", ""); - html.replace("${file.label}", "Private key"); - - server.sendHeader("Cache-Control", "public, max-age=3600"); - - server.setContentLength(html.length()); - server.send(200, "text/html", html); + String html; + if(SPIFFS.begin()) { + if(SPIFFS.exists(FILE_MQTT_KEY)) { + deleteHtml("Private key", "/mqtt-key/delete", "mqtt"); + } else { + uploadHtml("Private key", "/mqtt-key", "mqtt"); + } + SPIFFS.end(); + } else { + server.sendHeader("Location","/config-mqtt"); + server.send(303); + } } void AmsWebServer::mqttKeyUpload() { + uploadFile(FILE_MQTT_KEY); HTTPUpload& upload = server.upload(); - if(upload.status == UPLOAD_FILE_START){ - String filename = upload.filename; - if (!SPIFFS.begin()) { - printE("An Error has occurred while mounting SPIFFS"); - String html = "

Error uploading!

"; - server.send(500, "text/html", html); - } else { - printD("handleFileUpload Name: %s", filename.c_str()); - mqttKeyFile = SPIFFS.open("/mqtt-key.pem", "w"); - filename = String(); - } - } else if(upload.status == UPLOAD_FILE_WRITE) { - if(mqttKeyFile) - mqttKeyFile.write(upload.buf, upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END) { - if(mqttKeyFile) { - mqttKeyFile.close(); - SPIFFS.end(); - printD("handleFileUpload Size: %d", upload.totalSize); - server.sendHeader("Location","/config-mqtt"); - server.send(303); - } else { - server.send(500, "text/plain", "500: couldn't create file"); - } - } + if(upload.status == UPLOAD_FILE_END) { + server.sendHeader("Location","/config-mqtt"); + server.send(303); + if(config->isMqttSsl()) { + config->setMqttChanged(); + } + } } void AmsWebServer::mqttKeyDelete() { - + deleteFile(FILE_MQTT_KEY); + server.sendHeader("Location","/config-mqtt"); + server.send(303); + if(config->isMqttSsl()) { + config->setMqttChanged(); + } } diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index 5f62f10a..fdffae32 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -44,10 +44,7 @@ private: AmsConfiguration* config; AmsData data; MQTTClient* mqtt; - File firmwareFile; - File mqttCaFile; - File mqttCertFile; - File mqttKeyFile; + File file; bool performRestart = false; #if defined(ESP8266) @@ -59,6 +56,7 @@ private: bool checkSecurity(byte level); void indexHtml(); + void indexJs(); void configMeterHtml(); void configWifiHtml(); void configMqttHtml(); @@ -74,6 +72,10 @@ private: void restartWaitHtml(); void isAliveCheck(); + void uploadHtml(const char* label, const char* action, const char* menu); + void deleteHtml(const char* label, const char* action, const char* menu); + void uploadFile(const char* path); + void deleteFile(const char* path); void uploadPost(); void mqttCa(); void mqttCaUpload(); diff --git a/web/boot.css b/web/boot.css index 9bf91c81..612782ef 100644 --- a/web/boot.css +++ b/web/boot.css @@ -225,6 +225,12 @@ a { border-radius: .25rem; transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; } +.btn-group-sm>.btn, .btn-sm { + padding: .25rem .5rem; + font-size: .875rem; + line-height: 1.5; + border-radius: .2rem; +} .btn-outline-secondary { color: #6c757d; border-color: #6c757d; @@ -234,6 +240,11 @@ a { background-color: #007bff; border-color: #007bff; } +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} .navbar { position: relative; display: -ms-flexbox; diff --git a/web/configmqtt.html b/web/configmqtt.html index 75417d15..e48906e1 100644 --- a/web/configmqtt.html +++ b/web/configmqtt.html @@ -115,20 +115,24 @@
- Upload + + Upload + - Delete + Delete
- -
- Upload + +
+ + Upload + - Delete + Delete
@@ -137,9 +141,11 @@
- Upload + + Upload + - Delete + Delete
diff --git a/web/delete.html b/web/delete.html new file mode 100644 index 00000000..07cffe54 --- /dev/null +++ b/web/delete.html @@ -0,0 +1,56 @@ + + + + + AMS reader - Meter configuration + + + + +
+ +
+
+
Are you sure you want to delete this file?
+
+
+
+
+ Back +
+
+ +
+
+
+
+ + diff --git a/web/index.html b/web/index.html index e8654dd3..0a903d21 100644 --- a/web/index.html +++ b/web/index.html @@ -196,163 +196,6 @@
- + diff --git a/web/index.js b/web/index.js new file mode 100644 index 00000000..b4e51c59 --- /dev/null +++ b/web/index.js @@ -0,0 +1,159 @@ +$(function() { + +}); +var im = $("#importMeter") +im.gaugeMeter({ + percent: 0, + text: "-", + append: "W" +}); + +var em = $("#exportMeter") +em.gaugeMeter({ + percent: 0, + text: "-", + append: "W" +}); + +var setStatus = function(id, status) { + var item = $('#'+id); + item.removeClass('d-none'); + item.removeClass (function (index, className) { + return (className.match (/(^|\s)badge-\S+/g) || []).join(' '); + }); + item.addClass('badge badge-' + status); +}; + +var interval = 5000; +var fetch = function() { + $.ajax({ + url: '/data.json', + timeout: 10000, + dataType: 'json', + }).done(function(json) { + $(".SimpleMeter").hide(); + im.show(); + em.show(); + + for(var id in json) { + var str = json[id]; + if(typeof str === "object") + continue; + if(isNaN(str)) { + $('#'+id).html(str); + } else { + var num = parseFloat(str); + $('#'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1)); + } + } + + if(window.moment) { + $('#currentMillis').html(moment.duration(parseInt(json.uptime_seconds), 'seconds').humanize()); + $('#currentMillis').closest('.row').show(); + } + + if(json.status) { + for(var id in json.status) { + setStatus(id, json.status[id]); + } + } + + if(json.mqtt) { + $('.mqtt-error').addClass('d-none'); + $('.mqtt-error'+json.mqtt.lastError).removeClass('d-none'); + $('#mqtt-lastError').html(json.mqtt.lastError); + } + + if(json.wifi) { + for(var id in json.wifi) { + var str = json.wifi[id]; + dst = $('#'+id); + if(isNaN(str)) { + dst.html(str); + } else { + var num = parseFloat(str); + dst.html(num.toFixed(0)); + $('#'+id+'-row').show(); + } + } + } + + if(json.data) { + var p = 0; + var p_pct = parseInt(json.p_pct); + var p_append = "W"; + if(json.data.P) { + p = parseFloat(json.data.P); + if(p > 1000) { + p = (p/1000).toFixed(1); + p_append = "kW"; + } + } + im.gaugeMeter({ + percent: p_pct, + text: p, + append: p_append + }); + + var po = 0; + var po_pct = parseInt(json.po_pct); + var po_append = "W"; + if(json.data.PO) { + po = parseFloat(json.data.PO); + if(po > 1000) { + po = (po/1000).toFixed(1); + po_append = "kW"; + } + } + em.gaugeMeter({ + percent: po_pct, + text: po, + append: po_append + }); + + for(var id in json.data) { + var str = json.data[id]; + if(isNaN(str)) { + $('#'+id).html(str); + } else { + var num = parseFloat(str); + $('#'+id).html(num.toFixed(1)); + $('#'+id+'-row').show(); + } + } + } else { + im.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + + em.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + } + setTimeout(fetch, interval); + }).fail(function() { + setTimeout(fetch, interval*4); + + im.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + + em.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + + setStatus("mqtt", "secondary"); + setStatus("wifi", "secondary"); + setStatus("han", "secondary"); + setStatus("esp", "danger"); + }); +} +fetch(); diff --git a/web/upload.html b/web/upload.html index 1d0963eb..caf45909 100644 --- a/web/upload.html +++ b/web/upload.html @@ -5,7 +5,6 @@ AMS reader - Meter configuration -