diff --git a/scripts/makeweb.py b/scripts/makeweb.py index 4b054d82..f3682eb4 100644 --- a/scripts/makeweb.py +++ b/scripts/makeweb.py @@ -42,9 +42,7 @@ for filename in os.listdir(webroot): dst.write(")==\"==\";\n") dst.write("const int "); dst.write(varname) - dst.write("_LEN = sizeof("); - dst.write(varname) - dst.write(")/sizeof("); - dst.write(varname) - dst.write("[0]);"); + dst.write("_LEN = "); + dst.write(str(len(content))) + dst.write(";"); \ No newline at end of file diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index bc913588..89083299 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -72,6 +72,13 @@ void AmsConfiguration::setWifiHostname(const char* wifiHostname) { strcpy(config.wifiHostname, wifiHostname); } +void AmsConfiguration::clearWifi() { + setWifiSsid(""); + setWifiPassword(""); + setWifiHostname(""); + clearWifiIp(); +} + void AmsConfiguration::clearWifiIp() { setWifiIp(""); setWifiGw(""); @@ -262,6 +269,24 @@ void AmsConfiguration::setSubstituteMissing(bool substituteMissing) { config.substituteMissing = substituteMissing; } +bool AmsConfiguration::isSendUnknown() { + return config.sendUnknown; +} + +void AmsConfiguration::setSendUnknown(bool sendUnknown) { + config.sendUnknown = sendUnknown; +} + +void AmsConfiguration::clearMeter() { + setMeterType(0); + setDistributionSystem(0); + setMainFuse(0); + setProductionCapacity(0); + setSubstituteMissing(false); + setSendUnknown(false); +} + + bool AmsConfiguration::isDebugTelnet() { return config.debugTelnet; } @@ -475,6 +500,23 @@ void AmsConfiguration::ackDomoChange() { domoChanged = false; } +void AmsConfiguration::clear() { + clearMeter(); + clearWifi(); + clearMqtt(); + clearAuth(); + clearDomo(); + + int address = EEPROM_CONFIG_ADDRESS; + + EEPROM.begin(EEPROM_SIZE); + while(address < EEPROM_CONFIG_ADDRESS+EEPROM_SIZE) { + EEPROM.put(address++, 0); + } + EEPROM.commit(); + EEPROM.end(); +} + bool AmsConfiguration::hasConfig() { if(configVersion == 0) { EEPROM.begin(EEPROM_SIZE); @@ -768,7 +810,8 @@ int AmsConfiguration::readByte(int address, byte *value) { void AmsConfiguration::print(Print* debugger) { - debugger->println("Configuration:"); + debugger->print("Configuration size: "); + debugger->println(sizeof(config)); debugger->println("-----------------------------------------------"); debugger->printf("WiFi SSID: '%s'\r\n", this->getWifiSsid()); debugger->printf("WiFi Psk: '%s'\r\n", this->getWifiPassword()); diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index ff102962..b368bd9d 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -29,6 +29,7 @@ struct ConfigObject { uint8_t mainFuse; uint8_t productionCapacity; bool substituteMissing; + bool sendUnknown; bool debugTelnet; bool debugSerial; @@ -78,6 +79,7 @@ public: void setWifiDns2(const char* wifiDns1); char* getWifiHostname(); void setWifiHostname(const char* wifiHostname); + void clearWifi(); void clearWifiIp(); bool isWifiChanged(); @@ -125,6 +127,9 @@ public: void setProductionCapacity(uint8_t productionCapacity); bool isSubstituteMissing(); void setSubstituteMissing(bool substituteMissing); + bool isSendUnknown(); + void setSendUnknown(bool sendUnknown); + void clearMeter(); bool isDebugTelnet(); void setDebugTelnet(bool debugTelnet); @@ -179,6 +184,8 @@ public: bool isDomoChanged(); void ackDomoChange(); + void clear(); + protected: private: @@ -209,6 +216,7 @@ private: 0, // Main fuse 0, // Production capacity false, // Substitute + false, // Send unknown false, // Debug telnet false, // Debug serial 5, // Debug level @@ -230,10 +238,11 @@ private: 0, // VL2IDX 0, // VL3IDX 0 // CL1IDX + // 786 bytes }; bool wifiChanged, mqttChanged, domoChanged; - const int EEPROM_SIZE = 2048; + const int EEPROM_SIZE = 790; // Config size + 4 bytes for config version const int EEPROM_CHECK_SUM = 82; // Used to check if config is stored. Change if structure changes const int EEPROM_CONFIG_ADDRESS = 0; diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 03f4670e..688f1a53 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -235,6 +235,7 @@ void setup() { if(config.hasConfig()) { if(Debug.isActive(RemoteDebug::INFO)) config.print(&Debug); WiFi_connect(); + timeClient.begin(); } else { if(Debug.isActive(RemoteDebug::INFO)) { debugI("No configuration, booting AP"); @@ -243,7 +244,6 @@ void setup() { } ws.setup(&config, &mqtt); - timeClient.begin(); } int buttonTimer = 0; @@ -296,12 +296,6 @@ void loop() { lastTemperatureRead = now; } - if(now > 10000 && now - lastErrorBlink > 3000) { - errorBlink(); - } - - timeClient.update(); - // Only do normal stuff if we're not booted as AP if (WiFi.getMode() != WIFI_AP) { if (WiFi.status() != WL_CONNECTED) { @@ -328,6 +322,13 @@ void loop() { MDNS.addService("http", "tcp", 80); } } + + if(now > 10000 && now - lastErrorBlink > 3000) { + errorBlink(); + } + + timeClient.update(); + if (strlen(config.getMqttHost()) > 0) { mqtt.loop(); delay(10); // Needed to preserve power. After adding this, the voltage is super smooth on a HAN powered device @@ -344,7 +345,7 @@ void loop() { } else { dnsServer.processNextRequest(); // Continously flash the LED when AP mode - hw.ledBlink(LED_INTERNAL, 1); + if (now / 50 % 64 == 0) hw.ledBlink(LED_INTERNAL, 1); } if(hanSerialPin != config.getHanPin()) { @@ -716,7 +717,7 @@ void readHanPort() { delay(10); } } else { - if(strlen(config.getMqttHost()) > 0 && strlen(config.getMqttPublishTopic()) > 0) { + if(config.isSendUnknown() && strlen(config.getMqttHost()) > 0 && strlen(config.getMqttPublishTopic()) > 0) { byte buf[512]; int length = hanReader.getBuffer(buf); String hexstring = ""; diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 07b82b46..20d50b7f 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -5,7 +5,7 @@ #include "root/head_html.h" #include "root/foot_html.h" #include "root/index_html.h" -#include "root/index_js.h" +#include "root/application_js.h" #include "root/setup_html.h" #include "root/configmeter_html.h" #include "root/configwifi_html.h" @@ -19,6 +19,7 @@ #include "root/github_svg.h" #include "root/upload_html.h" #include "root/delete_html.h" +#include "root/reset_html.h" #include "Base64.h" @@ -33,7 +34,7 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { server.on("/", HTTP_GET, std::bind(&AmsWebServer::indexHtml, this)); server.on("/", HTTP_POST, std::bind(&AmsWebServer::handleSetup, this)); - server.on("/index.js", HTTP_GET, std::bind(&AmsWebServer::indexJs, this)); + server.on("/application.js", HTTP_GET, std::bind(&AmsWebServer::applicationJs, 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)); @@ -59,6 +60,11 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { server.on("/mqtt-key", HTTP_GET, std::bind(&AmsWebServer::mqttKey, this)); server.on("/mqtt-key", HTTP_POST, std::bind(&AmsWebServer::mqttKeyDelete, this), std::bind(&AmsWebServer::mqttKeyUpload, this)); + server.on("/reset", HTTP_GET, std::bind(&AmsWebServer::factoryResetHtml, this)); + server.on("/reset", HTTP_POST, std::bind(&AmsWebServer::factoryResetPost, this)); + + server.onNotFound(std::bind(&AmsWebServer::notFound, this)); + server.begin(); // Web server start } @@ -175,16 +181,18 @@ void AmsWebServer::indexHtml() { html.replace("${wifi.channel}", WiFi.channel() > 0 ? String(WiFi.channel()) : ""); html.replace("${wifi.ssid}", !WiFi.SSID().isEmpty() ? String(WiFi.SSID()) : ""); - server.setContentLength(html.length()); - server.send(200, "text/html", html); + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); } } -void AmsWebServer::indexJs() { - printD("Serving /index.js over http..."); +void AmsWebServer::applicationJs() { + printD("Serving /application.js over http..."); server.sendHeader("Cache-Control", "public, max-age=3600"); - server.send_P(200, "application/javascript", INDEX_JS); + server.send_P(200, "application/javascript", APPLICATION_JS); } void AmsWebServer::configMeterHtml() { @@ -212,9 +220,12 @@ void AmsWebServer::configMeterHtml() { } html.replace("${config.productionCapacity}", String(config->getProductionCapacity())); html.replace("${config.substituteMissing}", config->isSubstituteMissing() ? "checked" : ""); + html.replace("${config.sendUnknown}", config->isSendUnknown() ? "checked" : ""); - server.setContentLength(html.length()); - server.send(200, "text/html", html); + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); } void AmsWebServer::configWifiHtml() { @@ -238,8 +249,10 @@ void AmsWebServer::configWifiHtml() { html.replace("${config.wifiDns2}", config->getWifiDns2()); html.replace("${config.wifiHostname}", config->getWifiHostname()); - server.setContentLength(html.length()); - server.send(200, "text/html", html); + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); } void AmsWebServer::configMqttHtml() { @@ -322,8 +335,11 @@ void AmsWebServer::configDomoticzHtml() { } else { html.replace("${config.domoVL3IDX}", ""); } if(config->getDomoCL1IDX() > 0){ html.replace("${config.domoCL1IDX}", String(config->getDomoCL1IDX())); } else { html.replace("${config.domoCL1IDX}", ""); } - server.setContentLength(html.length()); - server.send(200, "text/html", html); + + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); } @@ -345,8 +361,10 @@ void AmsWebServer::configWebHtml() { html.replace("${config.authUser}", config->getAuthUser()); html.replace("${config.authPassword}", config->getAuthPassword()); - server.setContentLength(html.length()); - server.send(200, "text/html", html); + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); } void AmsWebServer::bootCss() { @@ -639,6 +657,7 @@ void AmsWebServer::handleSave() { config->setMainFuse(server.arg("mainFuse").toInt()); config->setProductionCapacity(server.arg("productionCapacity").toInt()); config->setSubstituteMissing(server.hasArg("substituteMissing") && server.arg("substituteMissing") == "true"); + config->setSendUnknown(server.hasArg("sendUnknown") && server.arg("sendUnknown") == "true"); } if(server.hasArg("wifiConfig") && server.arg("wifiConfig") == "true") { @@ -795,8 +814,10 @@ void AmsWebServer::configSystemHtml() { 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); + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); } String AmsWebServer::getSerialSelectOptions(int selected) { @@ -949,14 +970,20 @@ void AmsWebServer::uploadHtml(const char* label, const char* action, const char* server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - server.send_P(200, "text/html", UPLOAD_HTML); + server.setContentLength(UPLOAD_HTML_LEN + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent_P(UPLOAD_HTML); + server.sendContent_P(FOOT_HTML); } void AmsWebServer::deleteHtml(const char* label, const char* action, const char* menu) { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - server.send_P(200, "text/html", DELETE_HTML); + server.setContentLength(DELETE_HTML_LEN + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent_P(DELETE_HTML); + server.sendContent_P(FOOT_HTML); } void AmsWebServer::mqttCa() { @@ -1085,6 +1112,34 @@ void AmsWebServer::mqttKeyDelete() { } } +void AmsWebServer::factoryResetHtml() { + server.sendHeader("Cache-Control", "public, max-age=3600"); + + server.setContentLength(RESET_HTML_LEN + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent_P(RESET_HTML); + server.sendContent_P(FOOT_HTML); +} + +void AmsWebServer::factoryResetPost() { + if(server.hasArg("perform") && server.arg("perform") == "true") { + SPIFFS.format(); + config->clear(); + performRestart = true; + server.sendHeader("Location","/restart-wait"); + server.send(303); + } else { + server.sendHeader("Location","/"); + server.send(303); + } +} + + +void AmsWebServer::notFound() { + server.sendHeader("Location","/"); + server.send(303); +} + void AmsWebServer::printD(String fmt, ...) { va_list args; diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index 994fe5fe..8ce294a1 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -57,7 +57,7 @@ private: bool checkSecurity(byte level); void indexHtml(); - void indexJs(); + void applicationJs(); void configMeterHtml(); void configWifiHtml(); void configMqttHtml(); @@ -93,6 +93,11 @@ private: void mqttKeyUpload(); void mqttKeyDelete(); + void factoryResetHtml(); + void factoryResetPost(); + + void notFound(); + void printD(String fmt, ...); void printI(String fmt, ...); void printW(String fmt, ...); diff --git a/web/index.js b/web/application.js similarity index 69% rename from web/index.js rename to web/application.js index e0b13edc..c8cd5d8b 100644 --- a/web/index.js +++ b/web/application.js @@ -18,7 +18,80 @@ $(function() { }); } - fetch(); + if($('.SimpleMeter').length > 0) { + fetch(); + } + + // For config-mqtt + $('#mqttEnable').on('change', function() { + var inputs = $('.mqtt-config'); + inputs.prop('disabled', !$(this).is(':checked')); + }); + + $('#mqttPayloadFormat').on('change', function() { + var val = parseInt($(this).val()); + if(val == 3) { + $('.format-type-domoticz').show(); + } else { + $('.format-type-domoticz').hide(); + } + }); + + $('#mqttEnable').trigger('change'); + $('#mqttPayloadFormat').trigger('change'); + + // For config-meter + $('.subtitute-dependent').on('change', function() { + console.log("test"); + if($('#meterType').val() == 2 && $('#distributionSystem').val() == 1) { + $('#substitute').show(); + } else { + $('#substitute').hide(); + } + }); + $('#meterType').trigger('change'); + + // For config-wifi + $('#wifiIpType').on('change', function() { + if($(this).is(':checked')) { + $('#staticIp').show(); + } else { + $('#staticIp').hide(); + } + }); + $('#wifiIpType').trigger('change'); + + // For config-web + $('#authSecurity').on('change', function() { + var inputs = $('.auth-config'); + inputs.prop('disabled', $(this).val() == 0); + }); + + $('#authSecurity').trigger('change'); + + switch(window.location.pathname) { + case '/config-meter': + $('#config-meter-link').addClass('active'); + break; + case '/config-wifi': + $('#config-wifi-link').addClass('active'); + break; + case '/config-mqtt': + case '/mqtt-ca': + case '/mqtt-cert': + case '/mqtt-key': + case '/config-domoticz': + $('#config-mqtt-link').addClass('active'); + break; + case '/config-web': + $('#config-web-link').addClass('active'); + break; + case '/config-system': + case '/firmware': + case '/reset': + $('#config-system-link').addClass('active'); + break; + } }); var setStatus = function(id, status) { diff --git a/web/configdomoticz.html b/web/configdomoticz.html index 2e898819..6dec843f 100644 --- a/web/configdomoticz.html +++ b/web/configdomoticz.html @@ -1,102 +1,60 @@ - - - - - AMS reader - WiFi configuration - - - - -
- - - -
-

Domoticz Configuration. Requires that a Domoticz MQTT-message-broker is setup. HOWTO: https://www.domoticz.com/wiki/MQTT.

-

The following virtual sensors can currently be used:

- -

see: https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's

-

Create the sensors in Domoticz under Hardware > Dummy > Create virtual sensor, and use the IDX assigned to the sensor as input here.

-

"Electricity (instant and counter)" relies on Total energy import "tPI" and will not start before the first value is read (once an hour).

-
-
-
-
-
- Electricity IDX -
- -
-
-
- Current (3 Phase) IDX -
- +

see: https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's

+

Create the sensors in Domoticz under Hardware > Dummy > Create virtual sensor, and use the IDX assigned to the sensor as input here.

+

"Electricity (instant and counter)" relies on Total energy import "tPI" and will not start before the first value is read (once an hour).

+
+
+
+
+
+ Electricity IDX
+
-
-
-
- Voltage L1 IDX -
- -
-
-
- Voltage L1 IDX -
- -
-
-
- Voltage L1 IDX -
- +
+
+ Current (3 Phase) IDX
+
-
-
-
- Back +
+
+
+ Voltage L1 IDX +
+
-
- +
+
+ Voltage L1 IDX +
+ +
+
+
+ Voltage L1 IDX +
+
- -
- - + +
+
+
+ Back +
+
+ +
+
+ diff --git a/web/configmeter.html b/web/configmeter.html index c545f3b0..a647c283 100644 --- a/web/configmeter.html +++ b/web/configmeter.html @@ -1,127 +1,78 @@ - - - - - AMS reader - Meter configuration - - - - - -
- -
- -
-
-
-
-
- Meter type -
- + + +
+
+
+
+
+ Meter type
+
-
-
-
- Distribution system -
- +
+
+
+
+ Distribution system
+
-
-
-
- Main fuse -
- +
+
+
+
+ Main fuse
+
-
-
-
- Production capacity -
- -
- kWp -
+
+
+
+
+ Production capacity
-
-
-
- + +
+ kWp
-
-
-
-
- Back +
+
+ +
-
- +
+
+ +
- -
- - - + +
+
+
+ Back +
+
+ +
+
+ diff --git a/web/configmqtt.html b/web/configmqtt.html index abab7964..06b7da2d 100644 --- a/web/configmqtt.html +++ b/web/configmqtt.html @@ -133,21 +133,3 @@ - diff --git a/web/configsystem.html b/web/configsystem.html index 56fc4f66..b926e308 100644 --- a/web/configsystem.html +++ b/web/configsystem.html @@ -1,169 +1,134 @@ - - - - - AMS reader - System configuration - - - - -
- -
!!WARNING!!
Do not change anything here unless you know exactly what you are doing! Changing things here coulds cause the device to stop responding
-
- -
-
GPIO settings
-
-
-
-
- HAN +
!!WARNING!!
Do not change anything here unless you know exactly what you are doing! Changing things here coulds cause the device to stop responding
+ + +
+
GPIO settings
+
+
+
+
+ HAN +
+ +
+
+
+
+
+ LED +
+ +
+ +
+
+
+
+
+
+ RGB +
+ + + +
+ +
+
+
+
+
+
+ AP button +
+ +
+
+
+
+
+ Temperature +
+ +
+
+
+
+
+
+
+ Vcc +
+
- +
+
+
+
+
+ Boot limit +
+ +
+
+
+
+
+
+
+
Debugger
+
+
+ +
+
+ +
+
+
+ +
+
-
-
-
- LED -
- -
- -
-
-
-
-
-
- RGB -
- - - -
- -
-
-
-
-
-
- AP button -
- -
-
-
-
-
- Temperature -
- -
-
-
-
-
-
-
- Vcc -
- -
-
-
-
-
- Multiplier -
- -
-
-
-
-
- Boot limit -
- -
-
-
-
-
-
Debugger
-
-
- -
-
- -
-
-
- -
- -
-
-
-
-
- -
-
+
+
+ - -
- - + +
+
+
+ Back +
+
+ +
+
+ diff --git a/web/configweb.html b/web/configweb.html index 85ef2c60..89fbf1de 100644 --- a/web/configweb.html +++ b/web/configweb.html @@ -1,97 +1,44 @@ - - - - - AMS reader - Web configuration - - - - - -
- -
- -
-
-
-
-
- Security -
- + + +
+
+
+
+
+ Security
+
-
-
-
- Username -
- +
+
+
+
+ Username
+
-
-
-
- Password -
- +
+
+
+
+ Password
+
-
-
-
- Back -
-
- -
+
+
+
+
+ Back
- -
- - - +
+ +
+ + diff --git a/web/configwifi.html b/web/configwifi.html index 7869a166..578aa501 100644 --- a/web/configwifi.html +++ b/web/configwifi.html @@ -1,133 +1,85 @@ - - - - - AMS reader - WiFi configuration - - - - -
- -
- -
-
-
-
-
- SSID -
- + + +
+
+
+
+
+ SSID
-
-
-
-
- PSK -
- -
-
-
-
-
- Hostname -
- -
-
-
- +
-
-
-
-
- IP -
- +
+
+
+ PSK
+
-
-
-
- Subnet -
- +
+
+
+
+ Hostname
+
-
-
-
- Gateway -
- +
+
+ +
+
+
+
+
+
+ IP
+
-
-
-
- Primary DNS -
- +
+
+
+
+ Subnet
+
-
-
-
- Secondary DNS -
- +
+
+
+
+ Gateway
+ +
+
+
+
+
+ Primary DNS +
+ +
+
+
+
+
+ Secondary DNS +
+
-
-
-
- Back -
-
- -
+
+
+
+
+ Back
- -
- - - +
+ +
+ + diff --git a/web/delete.html b/web/delete.html index d966ae4f..c03d0859 100644 --- a/web/delete.html +++ b/web/delete.html @@ -1,56 +1,14 @@ - - - - - AMS reader - Delete - - - - -
- - -
-
Are you sure you want to delete this file?
+
+
-
-
-
- Back -
-
- -
-
- -
- - + + diff --git a/web/foot.html b/web/foot.html index 98653613..775a564c 100644 --- a/web/foot.html +++ b/web/foot.html @@ -1,3 +1,9 @@ + + + + + + diff --git a/web/head.html b/web/head.html index 103ea372..ee3f1255 100644 --- a/web/head.html +++ b/web/head.html @@ -2,9 +2,50 @@ - AMS reader - WiFi configuration + AMS reader +
@@ -13,22 +54,28 @@ +
+
ESP
+
HAN
+
WiFi
+
MQTT
+