mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-13 15:37:03 +00:00
Implemented support for MQTT SSL and cleaned up necessary code
This commit is contained in:
parent
cc032fdf29
commit
0c93c52e3d
@ -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
|
||||
|
||||
@ -179,6 +179,10 @@ void AmsConfiguration::clearMqtt() {
|
||||
setMqttPassword("");
|
||||
}
|
||||
|
||||
void AmsConfiguration::setMqttChanged() {
|
||||
mqttChanged = true;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::isMqttChanged() {
|
||||
return mqttChanged;
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@ public:
|
||||
void setMqttSsl(bool mqttSsl);
|
||||
void clearMqtt();
|
||||
|
||||
void setMqttChanged();
|
||||
bool isMqttChanged();
|
||||
void ackMqttChange();
|
||||
|
||||
|
||||
10
src/AmsStorage.h
Normal file
10
src/AmsStorage.h
Normal file
@ -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
|
||||
@ -17,10 +17,12 @@
|
||||
*/
|
||||
|
||||
#include "AmsToMqttBridge.h"
|
||||
#include "AmsStorage.h"
|
||||
#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e9
|
||||
#include <ArduinoJson.h>
|
||||
#include <MQTT.h>
|
||||
#include <DNSServer.h>
|
||||
#include <NTPClient.h>
|
||||
|
||||
#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();
|
||||
|
||||
@ -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 = "<html><body><h1>Error uploading!</h1></form>";
|
||||
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 = "<html><body><h1>Error uploading!</h1></form>";
|
||||
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 = "<html><body><h1>Error uploading!</h1></form>";
|
||||
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 = "<html><body><h1>Error uploading!</h1></form>";
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
11
web/boot.css
11
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;
|
||||
|
||||
@ -115,20 +115,24 @@
|
||||
<div class="row form-group">
|
||||
<label class="col-4">CA</label>
|
||||
<div class="col-8">
|
||||
<span style="display: ${display.ca.upload};"><a href="/mqtt-ca">Upload</a></span>
|
||||
<span style="display: ${display.ca.upload};">
|
||||
<a href="/mqtt-ca" class="btn btn-sm btn-outline-secondary">Upload</a>
|
||||
</span>
|
||||
<span style="display: ${display.ca.file};">
|
||||
<a href="#">Delete</a>
|
||||
<a href="/mqtt-ca" class="btn btn-sm btn-danger">Delete</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 mqtt-ssl-config">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Certificate</label>
|
||||
<div class="col-8">
|
||||
<span style="display: ${display.cert.upload};"><a href="/mqtt-ca">Upload</a></span>
|
||||
<label class="col-6">Certificate</label>
|
||||
<div class="col-6">
|
||||
<span style="display: ${display.cert.upload};">
|
||||
<a href="/mqtt-cert" class="btn btn-sm btn-outline-secondary">Upload</a>
|
||||
</span>
|
||||
<span style="display: ${display.cert.file};">
|
||||
<a href="#">Delete</a>
|
||||
<a href="/mqtt-cert" class="btn btn-sm btn-danger">Delete</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -137,9 +141,11 @@
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Private key</label>
|
||||
<div class="col-6">
|
||||
<span style="display: ${display.key.upload};"><a href="/mqtt-ca">Upload</a></span>
|
||||
<span style="display: ${display.key.upload};">
|
||||
<a href="/mqtt-key" class="btn btn-sm btn-outline-secondary">Upload</a>
|
||||
</span>
|
||||
<span style="display: ${display.key.file};">
|
||||
<a href="#">Delete</a>
|
||||
<a href="/mqtt-key" class="btn btn-sm btn-danger">Delete</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
56
web/delete.html
Normal file
56
web/delete.html
Normal file
@ -0,0 +1,56 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - Meter configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link ${menu.meter.class}" href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link ${menu.wifi.class}" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link ${menu.mqtt.class}" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link ${menu.web.class}" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link ${menu.system.class}" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post" action="${form.action}">
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="alert alert-warning">Are you sure you want to delete this file?</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="javascript:history.back();" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-danger">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
159
web/index.html
159
web/index.html
@ -196,163 +196,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
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();
|
||||
</script>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
159
web/index.js
Normal file
159
web/index.js
Normal file
@ -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();
|
||||
@ -5,7 +5,6 @@
|
||||
<title>AMS reader - Meter configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user