From 2858123c1be0ed46158c9c7fede0a45fda2f1cd1 Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Sun, 3 May 2020 16:29:38 +0200 Subject: [PATCH] Added configuration of GPIO in UI. Added initial setup page in AP mode. Major changes in storing configuration. --- lib/HanReader/src/HanReader.cpp | 12 +- scripts/makeweb.py | 15 +- src/AmsConfiguration.cpp | 764 ++++++++++++-------------------- src/AmsConfiguration.h | 249 +++++++---- src/AmsToMqttBridge.h | 59 +-- src/AmsToMqttBridge.ino | 421 +++++++++--------- src/HwTools.cpp | 174 ++++++-- src/HwTools.h | 39 +- src/web/AmsWebServer.cpp | 369 ++++++++++----- src/web/AmsWebServer.h | 9 +- web/boot.css | 153 ++----- web/configmeter.html | 2 +- web/configmqtt.html | 4 +- web/configsystem.html | 112 ++++- web/configweb.html | 4 +- web/configwifi.html | 18 +- web/delete.html | 4 +- web/gaugemeter.js | 12 +- web/index.html | 2 +- web/index.js | 102 +++-- web/restartwait.html | 42 +- web/setup.html | 136 ++++++ web/upload.html | 2 +- 23 files changed, 1472 insertions(+), 1232 deletions(-) create mode 100644 web/setup.html diff --git a/lib/HanReader/src/HanReader.cpp b/lib/HanReader/src/HanReader.cpp index acec9893..a4a46902 100644 --- a/lib/HanReader/src/HanReader.cpp +++ b/lib/HanReader/src/HanReader.cpp @@ -1,7 +1,10 @@ #include "HanReader.h" -HanReader::HanReader() -{ +HanReader::HanReader() { + // Central European Time (Frankfurt, Paris) + TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time + TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time + localZone = new Timezone(CEST, CET); } void HanReader::setup(Stream *hanPort, RemoteDebug *debug) @@ -10,11 +13,6 @@ void HanReader::setup(Stream *hanPort, RemoteDebug *debug) bytesRead = 0; debugger = debug; - // Central European Time (Frankfurt, Paris) - TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time - TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time - localZone = new Timezone(CEST, CET); - if (debug) debug->println("MBUS serial setup complete"); } diff --git a/scripts/makeweb.py b/scripts/makeweb.py index 8158478b..b2086f46 100644 --- a/scripts/makeweb.py +++ b/scripts/makeweb.py @@ -1,6 +1,7 @@ import os import re import shutil +from css_html_js_minify import html_minify, js_minify, css_minify webroot = "web" srcroot = "src/web/root" @@ -20,11 +21,19 @@ for filename in os.listdir(webroot): varname = basename.upper() + with open(srcfile, encoding="utf-8") as f: + content = f.read() + + if filename.endswith(".html"): + content = html_minify(content) + elif filename.endswith(".css"): + content = css_minify(content) + elif filename.endswith(".js") and filename != 'gaugemeter.js': + content = js_minify(content) + with open(dstfile, "w") as dst: dst.write("const char ") dst.write(varname) dst.write("[] PROGMEM = R\"==\"==(\n") - with open(srcfile, "r") as src: - for line in src.readlines(): - dst.write(line) + dst.write(content) dst.write("\n)==\"==\";\n") \ No newline at end of file diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index b64ec19f..20bd5755 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -1,75 +1,75 @@ #include "AmsConfiguration.h" -String AmsConfiguration::getWifiSsid() { - return wifiSsid; +char* AmsConfiguration::getWifiSsid() { + return config.wifiSsid; } -void AmsConfiguration::setWifiSsid(String wifiSsid) { - wifiChanged |= this->wifiSsid != wifiSsid; - this->wifiSsid = String(wifiSsid); +void AmsConfiguration::setWifiSsid(const char* wifiSsid) { + wifiChanged |= strcmp(config.wifiSsid, wifiSsid) != 0; + strcpy(config.wifiSsid, wifiSsid); } -String AmsConfiguration::getWifiPassword() { - return wifiPassword; +char* AmsConfiguration::getWifiPassword() { + return config.wifiPassword; } -void AmsConfiguration::setWifiPassword(String wifiPassword) { - wifiChanged |= this->wifiPassword != wifiPassword; - this->wifiPassword = String(wifiPassword); +void AmsConfiguration::setWifiPassword(const char* wifiPassword) { + wifiChanged |= strcmp(config.wifiPassword, wifiPassword) != 0; + strcpy(config.wifiPassword, wifiPassword); } -String AmsConfiguration::getWifiIp() { - return wifiIp; +char* AmsConfiguration::getWifiIp() { + return config.wifiIp; } -void AmsConfiguration::setWifiIp(String wifiIp) { - wifiChanged |= this->wifiIp != wifiIp; - this->wifiIp = String(wifiIp); +void AmsConfiguration::setWifiIp(const char* wifiIp) { + wifiChanged |= strcmp(config.wifiIp, wifiIp) != 0; + strcpy(config.wifiIp, wifiIp); } -String AmsConfiguration::getWifiGw() { - return wifiGw; +char* AmsConfiguration::getWifiGw() { + return config.wifiGw; } -void AmsConfiguration::setWifiGw(String wifiGw) { - wifiChanged |= this->wifiGw != wifiGw; - this->wifiGw = String(wifiGw); +void AmsConfiguration::setWifiGw(const char* wifiGw) { + wifiChanged |= strcmp(config.wifiGw, wifiGw) != 0; + strcpy(config.wifiGw, wifiGw); } -String AmsConfiguration::getWifiSubnet() { - return wifiSubnet; +char* AmsConfiguration::getWifiSubnet() { + return config.wifiSubnet; } -void AmsConfiguration::setWifiSubnet(String wifiSubnet) { - wifiChanged |= this->wifiSubnet != wifiSubnet; - this->wifiSubnet = String(wifiSubnet); +void AmsConfiguration::setWifiSubnet(const char* wifiSubnet) { + wifiChanged |= strcmp(config.wifiSubnet, wifiSubnet) != 0; + strcpy(config.wifiSubnet, wifiSubnet); } -String AmsConfiguration::getWifiDns1() { - return wifiDns1; +char* AmsConfiguration::getWifiDns1() { + return config.wifiDns1; } -void AmsConfiguration::setWifiDns1(String wifiDns1) { - wifiChanged |= this->wifiDns1 != wifiDns1; - this->wifiDns1 = wifiDns1; +void AmsConfiguration::setWifiDns1(const char* wifiDns1) { + wifiChanged |= strcmp(config.wifiDns1, wifiDns1) != 0; + strcpy(config.wifiDns1, wifiDns1); } -String AmsConfiguration::getWifiDns2() { - return wifiDns2; +char* AmsConfiguration::getWifiDns2() { + return config.wifiDns2; } -void AmsConfiguration::setWifiDns2(String wifiDns2) { - wifiChanged |= this->wifiDns2 != wifiDns2; - this->wifiDns2 = wifiDns2; +void AmsConfiguration::setWifiDns2(const char* wifiDns2) { + wifiChanged |= strcmp(config.wifiDns2, wifiDns2) != 0; + strcpy(config.wifiDns2, wifiDns2); } -String AmsConfiguration::getWifiHostname() { - return wifiHostname; +char* AmsConfiguration::getWifiHostname() { + return config.wifiHostname; } -void AmsConfiguration::setWifiHostname(String wifiHostname) { - wifiChanged |= this->wifiHostname != wifiHostname; - this->wifiHostname = wifiHostname; +void AmsConfiguration::setWifiHostname(const char* wifiHostname) { + wifiChanged |= strcmp(config.wifiHostname, wifiHostname) != 0; + strcpy(config.wifiHostname, wifiHostname); } void AmsConfiguration::clearWifiIp() { @@ -89,84 +89,84 @@ void AmsConfiguration::ackWifiChange() { } -String AmsConfiguration::getMqttHost() { - return mqttHost; +char* AmsConfiguration::getMqttHost() { + return config.mqttHost; } -void AmsConfiguration::setMqttHost(String mqttHost) { - mqttChanged |= this->mqttHost != mqttHost; - this->mqttHost = String(mqttHost); +void AmsConfiguration::setMqttHost(const char* mqttHost) { + mqttChanged |= strcmp(config.mqttHost, mqttHost) != 0; + strcpy(config.mqttHost, mqttHost); } -int AmsConfiguration::getMqttPort() { - return mqttPort; +uint16_t AmsConfiguration::getMqttPort() { + return config.mqttPort; } -void AmsConfiguration::setMqttPort(int mqttPort) { - mqttChanged |= this->mqttPort != mqttPort; - this->mqttPort = mqttPort; +void AmsConfiguration::setMqttPort(uint16_t mqttPort) { + mqttChanged |= config.mqttPort != mqttPort; + config.mqttPort = mqttPort; } -String AmsConfiguration::getMqttClientId() { - return mqttClientId; +char* AmsConfiguration::getMqttClientId() { + return config.mqttClientId; } -void AmsConfiguration::setMqttClientId(String mqttClientId) { - mqttChanged |= this->mqttClientId != mqttClientId; - this->mqttClientId = String(mqttClientId); +void AmsConfiguration::setMqttClientId(const char* mqttClientId) { + mqttChanged |= strcmp(config.mqttClientId, mqttClientId) != 0; + strcpy(config.mqttClientId, mqttClientId); } -String AmsConfiguration::getMqttPublishTopic() { - return mqttPublishTopic; +char* AmsConfiguration::getMqttPublishTopic() { + return config.mqttPublishTopic; } -void AmsConfiguration::setMqttPublishTopic(String mqttPublishTopic) { - mqttChanged |= this->mqttPublishTopic != mqttPublishTopic; - this->mqttPublishTopic = String(mqttPublishTopic); +void AmsConfiguration::setMqttPublishTopic(const char* mqttPublishTopic) { + mqttChanged |= strcmp(config.mqttPublishTopic, mqttPublishTopic) != 0; + strcpy(config.mqttPublishTopic, mqttPublishTopic); } -String AmsConfiguration::getMqttSubscribeTopic() { - return mqttSubscribeTopic; +char* AmsConfiguration::getMqttSubscribeTopic() { + return config.mqttSubscribeTopic; } -void AmsConfiguration::setMqttSubscribeTopic(String mqttSubscribeTopic) { - mqttChanged |= this->mqttSubscribeTopic != mqttSubscribeTopic; - this->mqttSubscribeTopic = String(mqttSubscribeTopic); +void AmsConfiguration::setMqttSubscribeTopic(const char* mqttSubscribeTopic) { + mqttChanged |= strcmp(config.mqttSubscribeTopic, mqttSubscribeTopic) != 0; + strcpy(config.mqttSubscribeTopic, mqttSubscribeTopic); } -String AmsConfiguration::getMqttUser() { - return mqttUser; +char* AmsConfiguration::getMqttUser() { + return config.mqttUser; } -void AmsConfiguration::setMqttUser(String mqttUser) { - mqttChanged |= this->mqttUser != mqttUser; - this->mqttUser = String(mqttUser); +void AmsConfiguration::setMqttUser(const char* mqttUser) { + mqttChanged |= strcmp(config.mqttUser, mqttUser) != 0; + strcpy(config.mqttUser, mqttUser); } -String AmsConfiguration::getMqttPassword() { - return mqttPassword; +char* AmsConfiguration::getMqttPassword() { + return config.mqttPassword; } -void AmsConfiguration::setMqttPassword(String mqttPassword) { - mqttChanged |= this->mqttPassword != mqttPassword; - this->mqttPassword = String(mqttPassword); +void AmsConfiguration::setMqttPassword(const char* mqttPassword) { + mqttChanged |= strcmp(config.mqttPassword, mqttPassword) != 0; + strcpy(config.mqttPassword, mqttPassword); } -int AmsConfiguration::getMqttPayloadFormat() { - return this->mqttPayloadFormat; +uint8_t AmsConfiguration::getMqttPayloadFormat() { + return config.mqttPayloadFormat; } -void AmsConfiguration::setMqttPayloadFormat(int mqttPayloadFormat) { - this->mqttPayloadFormat = mqttPayloadFormat; +void AmsConfiguration::setMqttPayloadFormat(uint8_t mqttPayloadFormat) { + config.mqttPayloadFormat = mqttPayloadFormat; } bool AmsConfiguration::isMqttSsl() { - return this->mqttSsl; + return config.mqttSsl; } void AmsConfiguration::setMqttSsl(bool mqttSsl) { - mqttChanged |= this->mqttSsl != mqttSsl; - this->mqttSsl = mqttSsl; + mqttChanged |= config.mqttSsl != mqttSsl; + config.mqttSsl = mqttSsl; } void AmsConfiguration::clearMqtt() { @@ -193,27 +193,27 @@ void AmsConfiguration::ackMqttChange() { byte AmsConfiguration::getAuthSecurity() { - return authSecurity; + return config.authSecurity; } void AmsConfiguration::setAuthSecurity(byte authSecurity) { - this->authSecurity = authSecurity; + config.authSecurity = authSecurity; } -String AmsConfiguration::getAuthUser() { - return authUser; +char* AmsConfiguration::getAuthUser() { + return config.authUser; } -void AmsConfiguration::setAuthUser(String authUser) { - this->authUser = String(authUser); +void AmsConfiguration::setAuthUser(const char* authUser) { + strcpy(config.authUser, authUser); } -String AmsConfiguration::getAuthPassword() { - return authPassword; +char* AmsConfiguration::getAuthPassword() { + return config.authPassword; } -void AmsConfiguration::setAuthPassword(String authPassword) { - this->authPassword = String(authPassword); +void AmsConfiguration::setAuthPassword(const char* authPassword) { + strcpy(config.authPassword, authPassword); } void AmsConfiguration::clearAuth() { @@ -222,62 +222,194 @@ void AmsConfiguration::clearAuth() { setAuthPassword(""); } -int AmsConfiguration::getMeterType() { - return this->meterType; +uint8_t AmsConfiguration::getMeterType() { + return config.meterType; } -void AmsConfiguration::setMeterType(int meterType) { - this->meterType = meterType; +void AmsConfiguration::setMeterType(uint8_t meterType) { + config.meterType = meterType; } -int AmsConfiguration::getDistributionSystem() { - return this->distributionSystem; +uint8_t AmsConfiguration::getDistributionSystem() { + return config.distributionSystem; } -void AmsConfiguration::setDistributionSystem(int distributionSystem) { - this->distributionSystem = distributionSystem; +void AmsConfiguration::setDistributionSystem(uint8_t distributionSystem) { + config.distributionSystem = distributionSystem; } -int AmsConfiguration::getMainFuse() { - return this->mainFuse; +uint8_t AmsConfiguration::getMainFuse() { + return config.mainFuse; } -void AmsConfiguration::setMainFuse(int mainFuse) { - this->mainFuse = mainFuse; +void AmsConfiguration::setMainFuse(uint8_t mainFuse) { + config.mainFuse = mainFuse; } -int AmsConfiguration::getProductionCapacity() { - return this->productionCapacity; +uint8_t AmsConfiguration::getProductionCapacity() { + return config.productionCapacity; } -void AmsConfiguration::setProductionCapacity(int productionCapacity) { - this->productionCapacity = productionCapacity; +void AmsConfiguration::setProductionCapacity(uint8_t productionCapacity) { + config.productionCapacity = productionCapacity; } bool AmsConfiguration::isDebugTelnet() { - return this->debugTelnet; + return config.debugTelnet; } void AmsConfiguration::setDebugTelnet(bool debugTelnet) { - this->debugTelnet = debugTelnet; + config.debugTelnet = debugTelnet; } bool AmsConfiguration::isDebugSerial() { - return this->debugSerial; + return config.debugSerial; } void AmsConfiguration::setDebugSerial(bool debugSerial) { - this->debugSerial = debugSerial; + config.debugSerial = debugSerial; } -int AmsConfiguration::getDebugLevel() { - return this->debugLevel; +uint8_t AmsConfiguration::getDebugLevel() { + return config.debugLevel; } -void AmsConfiguration::setDebugLevel(int debugLevel) { - this->debugLevel = debugLevel; +void AmsConfiguration::setDebugLevel(uint8_t debugLevel) { + config.debugLevel = debugLevel; } +bool AmsConfiguration::pinUsed(uint8_t pin) { + if(pin == 0xFF) + return false; + return + pin == config.hanPin || + pin == config.apPin || + pin == config.ledPinRed || + pin == config.ledPinGreen || + pin == config.ledPinBlue || + pin == config.tempSensorPin || + pin == config.vccPin + ; +} + +uint8_t AmsConfiguration::getHanPin() { + return config.hanPin; +} + +void AmsConfiguration::setHanPin(uint8_t hanPin) { + if(!pinUsed(hanPin)) { + config.hanPin = hanPin; + } +} + +uint8_t AmsConfiguration::getApPin() { + return config.apPin; +} + +void AmsConfiguration::setApPin(uint8_t apPin) { + if(!pinUsed(apPin)) { + config.apPin = apPin; + if(apPin >= 0) + pinMode(apPin, INPUT_PULLUP); + } +} + +uint8_t AmsConfiguration::getLedPin() { + return config.ledPin; +} + +void AmsConfiguration::setLedPin(uint8_t ledPin) { + if(!pinUsed(ledPin)) { + config.ledPin = ledPin; + } +} + +bool AmsConfiguration::isLedInverted() { + return config.ledInverted; +} + +void AmsConfiguration::setLedInverted(bool ledInverted) { + config.ledInverted = ledInverted; +} + + +uint8_t AmsConfiguration::getLedPinRed() { + return config.ledPinRed; +} + +void AmsConfiguration::setLedPinRed(uint8_t ledPinRed) { + if(!pinUsed(ledPinRed)) { + config.ledPinRed = ledPinRed; + } +} + +uint8_t AmsConfiguration::getLedPinGreen() { + return config.ledPinGreen; +} + +void AmsConfiguration::setLedPinGreen(uint8_t ledPinGreen) { + if(!pinUsed(ledPinGreen)) { + config.ledPinGreen = ledPinGreen; + } +} + +uint8_t AmsConfiguration::getLedPinBlue() { + return config.ledPinBlue; +} + +void AmsConfiguration::setLedPinBlue(uint8_t ledPinBlue) { + if(!pinUsed(ledPinBlue)) { + config.ledPinBlue = ledPinBlue; + } +} + +bool AmsConfiguration::isLedRgbInverted() { + return config.ledRgbInverted; +} + +void AmsConfiguration::setLedRgbInverted(bool ledRgbInverted) { + config.ledRgbInverted = ledRgbInverted; +} + + +uint8_t AmsConfiguration::getTempSensorPin() { + return config.tempSensorPin; +} + +void AmsConfiguration::setTempSensorPin(uint8_t tempSensorPin) { + if(!pinUsed(tempSensorPin)) { + config.tempSensorPin = tempSensorPin; + } +} + +uint8_t AmsConfiguration::getVccPin() { + return config.vccPin; +} + +void AmsConfiguration::setVccPin(uint8_t vccPin) { + if(!pinUsed(vccPin)) { + config.vccPin = vccPin; + } +} + +double AmsConfiguration::getVccMultiplier() { + return config.vccMultiplier / 100.0; +} + +void AmsConfiguration::setVccMultiplier(double vccMultiplier) { + config.vccMultiplier = max(0.01, min(vccMultiplier, 655.5)) * 100; +} + +double AmsConfiguration::getVccBootLimit() { + return config.vccBootLimit / 10; +} + +void AmsConfiguration::setVccBootLimit(double vccBootLimit) { + if(vccBootLimit == 0.0) + config.vccBootLimit = 0; + else + config.vccBootLimit = max(2.5, min(vccBootLimit, 3.5)) * 10; +} bool AmsConfiguration::hasConfig() { if(configVersion == 0) { @@ -311,153 +443,25 @@ bool AmsConfiguration::load() { int cs = EEPROM.read(address); address++; switch(cs) { - case 71: // Same as 72 - case 72: - success = loadConfig72(address); - break; - case 75: - success = loadConfig75(address); - break; - case 80: + case 80: // v1.1 success = loadConfig80(address); break; - case 81: + case 81: // v1.2 success = loadConfig81(address); break; - case 82: - success = loadConfig82(address); + case 82: // v1.3 + EEPROM.get(address, config); + success = true; break; } EEPROM.end(); + + if(config.apPin >= 0) + pinMode(config.apPin, INPUT_PULLUP); + return success; } -bool AmsConfiguration::loadConfig72(int address) { - char* temp; - - address += readString(address, &temp); - setWifiSsid(temp); - address += readString(address, &temp); - setWifiPassword(temp); - - byte b; - address += readByte(address, &b); - setMeterType(b); - - address += readString(address, &temp); - setMqttHost(temp); - int port; - address += readInt(address, &port); - setMqttPort(port); - address += readString(address, &temp); - setMqttClientId(temp); - address += readString(address, &temp); - setMqttPublishTopic(temp); - address += readString(address, &temp); - setMqttSubscribeTopic(temp); - - bool secure = false; - address += readBool(address, &secure); - if (secure) { - address += readString(address, &temp); - setMqttUser(temp); - address += readString(address, &temp); - setMqttPassword(temp); - } else { - setMqttUser(""); - setMqttPassword(""); - } - setMqttPayloadFormat(0); - - clearAuth(); - - setWifiIp(""); - setWifiGw(""); - setWifiSubnet(""); - setMainFuse(0); - setProductionCapacity(0); - setDistributionSystem(0); - - ackWifiChange(); - - setDebugLevel(3); // 3=Info - setDebugTelnet(false); - setDebugSerial(false); - - return true; -} - -bool AmsConfiguration::loadConfig75(int address) { - char* temp; - - address += readString(address, &temp); - setWifiSsid(temp); - address += readString(address, &temp); - setWifiPassword(temp); - - byte b; - address += readByte(address, &b); - setMeterType(b); - - bool mqtt = false; - address += readBool(address, &mqtt); - if(mqtt) { - address += readString(address, &temp); - setMqttHost(temp); - int port; - address += readInt(address, &port); - setMqttPort(port); - address += readString(address, &temp); - setMqttClientId(temp); - address += readString(address, &temp); - setMqttPublishTopic(temp); - address += readString(address, &temp); - setMqttSubscribeTopic(temp); - } - - bool secure = false; - address += readBool(address, &secure); - if (secure) { - address += readString(address, &temp); - setMqttUser(temp); - address += readString(address, &temp); - setMqttPassword(temp); - } else { - setMqttUser(""); - setMqttPassword(""); - } - setMqttPayloadFormat(0); - - address += readByte(address, &authSecurity); - if (authSecurity > 0) { - address += readString(address, &temp); - setAuthUser(temp); - address += readString(address, &temp); - setAuthPassword(temp); - } else { - clearAuth(); - } - - int i; - address += readInt(address, &i); - setMainFuse(i); - address += readByte(address, &b); - setDistributionSystem(b); - - setWifiIp(""); - setWifiGw(""); - setWifiSubnet(""); - setProductionCapacity(0); - - ackWifiChange(); - - setDebugLevel(3); // 3=Info - setDebugTelnet(false); - setDebugSerial(false); - - return true; -} - bool AmsConfiguration::loadConfig80(int address) { char* temp; @@ -504,8 +508,10 @@ bool AmsConfiguration::loadConfig80(int address) { } setMqttPayloadFormat(0); - address += readByte(address, &authSecurity); - if (authSecurity > 0) { + byte b; + address += readByte(address, &b); + setAuthSecurity(b); + if (b > 0) { address += readString(address, &temp); setAuthUser(temp); address += readString(address, &temp); @@ -591,103 +597,10 @@ bool AmsConfiguration::loadConfig81(int address) { clearMqtt(); } - address += readByte(address, &authSecurity); - if (authSecurity > 0) { - address += readString(address, &temp); - setAuthUser(temp); - address += readString(address, &temp); - setAuthPassword(temp); - } else { - clearAuth(); - } - - int i; - address += readInt(address, &i); - setMeterType(i); - address += readInt(address, &i); - setDistributionSystem(i); - address += readInt(address, &i); - setMainFuse(i); - address += readInt(address, &i); - setProductionCapacity(i); - - bool debugTelnet = false; - address += readBool(address, &debugTelnet); - setDebugTelnet(debugTelnet); - bool debugSerial = false; - address += readBool(address, &debugSerial); - setDebugSerial(debugSerial); - address += readInt(address, &i); - setDebugLevel(i); - - ackWifiChange(); - - return true; -} - -bool AmsConfiguration::loadConfig82(int address) { - char* temp; - - address += readString(address, &temp); - setWifiSsid(temp); - address += readString(address, &temp); - setWifiPassword(temp); - - bool staticIp = false; - address += readBool(address, &staticIp); - if(staticIp) { - address += readString(address, &temp); - setWifiIp(temp); - address += readString(address, &temp); - setWifiGw(temp); - address += readString(address, &temp); - setWifiSubnet(temp); - address += readString(address, &temp); - setWifiDns1(temp); - address += readString(address, &temp); - setWifiDns2(temp); - } - address += readString(address, &temp); - setWifiHostname(temp); - bool mqtt = false; - address += readBool(address, &mqtt); - if(mqtt) { - address += readString(address, &temp); - setMqttHost(temp); - int port; - address += readInt(address, &port); - setMqttPort(port); - address += readString(address, &temp); - setMqttClientId(temp); - address += readString(address, &temp); - setMqttPublishTopic(temp); - address += readString(address, &temp); - setMqttSubscribeTopic(temp); - - bool secure = false; - address += readBool(address, &secure); - if (secure) - { - address += readString(address, &temp); - setMqttUser(temp); - address += readString(address, &temp); - setMqttPassword(temp); - } else { - setMqttUser(""); - setMqttPassword(""); - } - int payloadFormat; - address += readInt(address, &payloadFormat); - setMqttPayloadFormat(payloadFormat); - bool ssl = false; - address += readBool(address, &ssl); - setMqttSsl(ssl); - } else { - clearMqtt(); - } - - address += readByte(address, &authSecurity); - if (authSecurity > 0) { + byte b; + address += readByte(address, &b); + setAuthSecurity(b); + if (b > 0) { address += readString(address, &temp); setAuthUser(temp); address += readString(address, &temp); @@ -726,60 +639,11 @@ bool AmsConfiguration::save() { EEPROM.begin(EEPROM_SIZE); EEPROM.put(address, EEPROM_CHECK_SUM); address++; - - address += saveString(address, wifiSsid.c_str()); - address += saveString(address, wifiPassword.c_str()); - if(!wifiIp.isEmpty()) { - address += saveBool(address, true); - address += saveString(address, wifiIp.c_str()); - address += saveString(address, wifiGw.c_str()); - address += saveString(address, wifiSubnet.c_str()); - address += saveString(address, wifiDns1.c_str()); - address += saveString(address, wifiDns2.c_str()); - } else { - address += saveBool(address, false); - } - address += saveString(address, wifiHostname.c_str()); - if(!mqttHost.isEmpty()) { - address += saveBool(address, true); - address += saveString(address, mqttHost.c_str()); - address += saveInt(address, mqttPort); - address += saveString(address, mqttClientId.c_str()); - address += saveString(address, mqttPublishTopic.c_str()); - address += saveString(address, mqttSubscribeTopic.c_str()); - if (!mqttUser.isEmpty()) { - address += saveBool(address, true); - address += saveString(address, mqttUser.c_str()); - address += saveString(address, mqttPassword.c_str()); - } else { - address += saveBool(address, false); - } - address += saveInt(address, mqttPayloadFormat); - address += saveBool(address, mqttSsl); - } else { - address += saveBool(address, false); - } - - address += saveByte(address, authSecurity); - if (authSecurity > 0) { - address += saveString(address, authUser.c_str()); - address += saveString(address, authPassword.c_str()); - } - - address += saveInt(address, meterType); - address += saveInt(address, distributionSystem); - address += saveInt(address, mainFuse); - address += saveInt(address, productionCapacity); - - address += saveBool(address, debugTelnet); - address += saveBool(address, debugSerial); - address += saveInt(address, debugLevel); - + EEPROM.put(address, config); bool success = EEPROM.commit(); EEPROM.end(); configVersion = EEPROM_CHECK_SUM; - return success; } @@ -797,21 +661,6 @@ int AmsConfiguration::readString(int pAddress, char* pString[]) { return address; } -int AmsConfiguration::saveString(int pAddress, const char* pString) { - int address = 0; - int length = pString ? strlen(pString) + 1 : 0; - EEPROM.put(pAddress + address, length); - address++; - - for (int i = 0; i < length; i++) - { - EEPROM.put(pAddress + address, pString[i]); - address++; - } - - return address; -} - int AmsConfiguration::readInt(int address, int *value) { int lower = EEPROM.read(address); int higher = EEPROM.read(address + 1); @@ -819,79 +668,44 @@ int AmsConfiguration::readInt(int address, int *value) { return 2; } -int AmsConfiguration::saveInt(int address, int value) { - byte lowByte = value & 0xFF; - byte highByte = ((value >> 8) & 0xFF); - - EEPROM.write(address, lowByte); - EEPROM.write(address + 1, highByte); - - return 2; -} - int AmsConfiguration::readBool(int address, bool *value) { byte y = EEPROM.read(address); *value = (bool)y; return 1; } -int AmsConfiguration::saveBool(int address, bool value) { - byte y = (byte)value; - EEPROM.write(address, y); - return 1; -} - int AmsConfiguration::readByte(int address, byte *value) { *value = EEPROM.read(address); return 1; } -int AmsConfiguration::saveByte(int address, byte value) { - EEPROM.write(address, value); - return 1; -} - -template int AmsConfiguration::writeAnything(int ee, const T& value) { - const byte* p = (const byte*)(const void*)&value; - unsigned int i; - for (i = 0; i < sizeof(value); i++) - EEPROM.write(ee++, *p++); - return i; -} - -template int AmsConfiguration::readAnything(int ee, T& value) { - byte* p = (byte*)(void*)&value; - unsigned int i; - for (i = 0; i < sizeof(value); i++) - *p++ = EEPROM.read(ee++); - return i; -} - void AmsConfiguration::print(Print* debugger) { debugger->println("Configuration:"); debugger->println("-----------------------------------------------"); - debugger->printf("WiFi SSID: %s\r\n", this->getWifiSsid().c_str()); - debugger->printf("WiFi Psk: %s\r\n", this->getWifiPassword().c_str()); + debugger->printf("WiFi SSID: '%s'\r\n", this->getWifiSsid()); + debugger->printf("WiFi Psk: '%s'\r\n", this->getWifiPassword()); - if(!getWifiIp().isEmpty()) { - debugger->printf("IP: %s\r\n", this->getWifiIp().c_str()); - debugger->printf("Gateway: %s\r\n", this->getWifiGw().c_str()); - debugger->printf("Subnet: %s\r\n", this->getWifiSubnet().c_str()); - debugger->printf("Primary DNS: %s\r\n", this->getWifiDns1().c_str()); - debugger->printf("Secondary DNS: %s\r\n", this->getWifiDns2().c_str()); + if(strlen(getWifiIp()) > 0) { + debugger->printf("IP: '%s'\r\n", this->getWifiIp()); + debugger->printf("Gateway: '%s'\r\n", this->getWifiGw()); + debugger->printf("Subnet: '%s'\r\n", this->getWifiSubnet()); + debugger->printf("Primary DNS: '%s'\r\n", this->getWifiDns1()); + debugger->printf("Secondary DNS: '%s'\r\n", this->getWifiDns2()); } + + debugger->printf("WiFi Host: '%s'\r\n", this->getWifiHostname()); - if(!getMqttHost().isEmpty()) { - debugger->printf("mqttHost: %s\r\n", this->getMqttHost().c_str()); + if(strlen(getMqttHost()) > 0) { + debugger->printf("mqttHost: '%s'\r\n", this->getMqttHost()); debugger->printf("mqttPort: %i\r\n", this->getMqttPort()); - debugger->printf("mqttClientID: %s\r\n", this->getMqttClientId().c_str()); - debugger->printf("mqttPublishTopic: %s\r\n", this->getMqttPublishTopic().c_str()); - debugger->printf("mqttSubscribeTopic: %s\r\n", this->getMqttSubscribeTopic().c_str()); + debugger->printf("mqttClientID: '%s'\r\n", this->getMqttClientId()); + debugger->printf("mqttPublishTopic: '%s'\r\n", this->getMqttPublishTopic()); + debugger->printf("mqttSubscribeTopic: '%s'\r\n", this->getMqttSubscribeTopic()); if (this->getMqttUser()) { debugger->printf("SECURE MQTT CONNECTION:\r\n"); - debugger->printf("mqttUser: %s\r\n", this->getMqttUser().c_str()); - debugger->printf("mqttPass: %s\r\n", this->getMqttPassword().c_str()); + debugger->printf("mqttUser: '%s'\r\n", this->getMqttUser()); + debugger->printf("mqttPass: '%s'\r\n", this->getMqttPassword()); } debugger->printf("payload format: %i\r\n", this->getMqttPayloadFormat()); } @@ -899,8 +713,8 @@ void AmsConfiguration::print(Print* debugger) if (this->getAuthSecurity()) { debugger->printf("WEB AUTH:\r\n"); debugger->printf("authSecurity: %i\r\n", this->getAuthSecurity()); - debugger->printf("authUser: %s\r\n", this->getAuthUser().c_str()); - debugger->printf("authPass: %s\r\n", this->getAuthPassword().c_str()); + debugger->printf("authUser: '%s'\r\n", this->getAuthUser()); + debugger->printf("authPass: '%s'\r\n", this->getAuthPassword()); } debugger->printf("meterType: %i\r\n", this->getMeterType()); @@ -908,5 +722,13 @@ void AmsConfiguration::print(Print* debugger) debugger->printf("fuseSize: %i\r\n", this->getMainFuse()); debugger->printf("productionCapacity: %i\r\n", this->getProductionCapacity()); + debugger->printf("HAN pin: %i\r\n", this->getHanPin()); + debugger->printf("LED pin: %i\r\n", this->getLedPin()); + debugger->printf("LED red pin: %i\r\n", this->getLedPinRed()); + debugger->printf("LED green pin: %i\r\n", this->getLedPinGreen()); + debugger->printf("LED blue pin: %i\r\n", this->getLedPinBlue()); + debugger->printf("AP pin: %i\r\n", this->getApPin()); + debugger->printf("Temperature pin: %i\r\n", this->getTempSensorPin()); + debugger->println("-----------------------------------------------"); } diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index e25638e5..a672c8dc 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -3,6 +3,50 @@ #include #include "Arduino.h" +struct ConfigObject { + char wifiSsid[32]; + char wifiPassword[64]; + char wifiIp[15]; + char wifiGw[15]; + char wifiSubnet[15]; + char wifiDns1[15]; + char wifiDns2[15]; + char wifiHostname[32]; + char mqttHost[128]; + uint16_t mqttPort; + char mqttClientId[32]; + char mqttPublishTopic[64]; + char mqttSubscribeTopic[64]; + char mqttUser[64]; + char mqttPassword[64]; + uint8_t mqttPayloadFormat; + bool mqttSsl; + uint8_t authSecurity; + char authUser[64]; + char authPassword[64]; + uint8_t meterType; + uint8_t distributionSystem; + uint8_t mainFuse; + uint8_t productionCapacity; + + bool debugTelnet; + bool debugSerial; + uint8_t debugLevel; + + uint8_t hanPin; + uint8_t apPin; + uint8_t ledPin; + bool ledInverted; + uint8_t ledPinRed; + uint8_t ledPinGreen; + uint8_t ledPinBlue; + bool ledRgbInverted; + uint8_t tempSensorPin; + uint8_t vccPin; + uint16_t vccMultiplier; + uint8_t vccBootLimit; +}; + class AmsConfiguration { public: bool hasConfig(); @@ -11,43 +55,43 @@ public: bool load(); bool save(); - String getWifiSsid(); - void setWifiSsid(String wifiSsid); - String getWifiPassword(); - void setWifiPassword(String wifiPassword); - String getWifiIp(); - void setWifiIp(String wifiIp); - String getWifiGw(); - void setWifiGw(String wifiGw); - String getWifiSubnet(); - void setWifiSubnet(String wifiSubnet); - String getWifiDns1(); - void setWifiDns1(String wifiDns1); - String getWifiDns2(); - void setWifiDns2(String wifiDns1); - String getWifiHostname(); - void setWifiHostname(String wifiHostname); + char* getWifiSsid(); + void setWifiSsid(const char* wifiSsid); + char* getWifiPassword(); + void setWifiPassword(const char* wifiPassword); + char* getWifiIp(); + void setWifiIp(const char* wifiIp); + char* getWifiGw(); + void setWifiGw(const char* wifiGw); + char* getWifiSubnet(); + void setWifiSubnet(const char* wifiSubnet); + char* getWifiDns1(); + void setWifiDns1(const char* wifiDns1); + char* getWifiDns2(); + void setWifiDns2(const char* wifiDns1); + char* getWifiHostname(); + void setWifiHostname(const char* wifiHostname); void clearWifiIp(); bool isWifiChanged(); void ackWifiChange(); - String getMqttHost(); - void setMqttHost(String mqttHost); - int getMqttPort(); - void setMqttPort(int mqttPort); - String getMqttClientId(); - void setMqttClientId(String mqttClientId); - String getMqttPublishTopic(); - void setMqttPublishTopic(String mqttPublishTopic); - String getMqttSubscribeTopic(); - void setMqttSubscribeTopic(String mqttSubscribeTopic); - String getMqttUser(); - void setMqttUser(String mqttUser); - String getMqttPassword(); - void setMqttPassword(String mqttPassword); - int getMqttPayloadFormat(); - void setMqttPayloadFormat(int mqttPayloadFormat); + char* getMqttHost(); + void setMqttHost(const char* mqttHost); + uint16_t getMqttPort(); + void setMqttPort(uint16_t mqttPort); + char* getMqttClientId(); + void setMqttClientId(const char* mqttClientId); + char* getMqttPublishTopic(); + void setMqttPublishTopic(const char* mqttPublishTopic); + char* getMqttSubscribeTopic(); + void setMqttSubscribeTopic(const char* mqttSubscribeTopic); + char* getMqttUser(); + void setMqttUser(const char* mqttUser); + char* getMqttPassword(); + void setMqttPassword(const char* mqttPassword); + uint8_t getMqttPayloadFormat(); + void setMqttPayloadFormat(uint8_t mqttPayloadFormat); bool isMqttSsl(); void setMqttSsl(bool mqttSsl); void clearMqtt(); @@ -58,27 +102,56 @@ public: byte getAuthSecurity(); void setAuthSecurity(byte authSecurity); - String getAuthUser(); - void setAuthUser(String authUser); - String getAuthPassword(); - void setAuthPassword(String authPassword); + char* getAuthUser(); + void setAuthUser(const char* authUser); + char* getAuthPassword(); + void setAuthPassword(const char* authPassword); void clearAuth(); - int getMeterType(); - void setMeterType(int meterType); - int getDistributionSystem(); - void setDistributionSystem(int distributionSystem); - int getMainFuse(); - void setMainFuse(int mainFuse); - int getProductionCapacity(); - void setProductionCapacity(int productionCapacity); + uint8_t getMeterType(); + void setMeterType(uint8_t meterType); + uint8_t getDistributionSystem(); + void setDistributionSystem(uint8_t distributionSystem); + uint8_t getMainFuse(); + void setMainFuse(uint8_t mainFuse); + uint8_t getProductionCapacity(); + void setProductionCapacity(uint8_t productionCapacity); bool isDebugTelnet(); void setDebugTelnet(bool debugTelnet); bool isDebugSerial(); void setDebugSerial(bool debugSerial); - int getDebugLevel(); - void setDebugLevel(int debugLevel); + uint8_t getDebugLevel(); + void setDebugLevel(uint8_t debugLevel); + + bool pinUsed(uint8_t pin); + + uint8_t getHanPin(); + void setHanPin(uint8_t hanPin); + uint8_t getApPin(); + void setApPin(uint8_t apPin); + uint8_t getLedPin(); + void setLedPin(uint8_t ledPin); + bool isLedInverted(); + void setLedInverted(bool ledInverted); + + uint8_t getLedPinRed(); + void setLedPinRed(uint8_t ledPinRed); + uint8_t getLedPinGreen(); + void setLedPinGreen(uint8_t ledPinGreen); + uint8_t getLedPinBlue(); + void setLedPinBlue(uint8_t ledPinBlue); + bool isLedRgbInverted(); + void setLedRgbInverted(bool ledRgbInverted); + + uint8_t getTempSensorPin(); + void setTempSensorPin(uint8_t tempSensorPin); + uint8_t getVccPin(); + void setVccPin(uint8_t vccPin); + double getVccMultiplier(); + void setVccMultiplier(double vccMultiplier); + double getVccBootLimit(); + void setVccBootLimit(double vccBootLimit); void print(Print* debugger); @@ -86,57 +159,59 @@ protected: private: int configVersion = 0; + ConfigObject config { + "", // SSID + "", // PSK + "", // IP + "", // GW + "", // Subnet + "", // DNS 1 + "", // DNS 2 + "", // Hostname + "", // MQTT host + 1883, // Port + "", // Client ID + "", // Publish topic + "", // Subscribe topic + "", // Username + "", // Password + 0, // Format + false, // SSL + 0, // Web security + "", // Username + "", // Password + 0, // Meter type + 0, // Distribution system + 0, // Main fuse + 0, // Production capacity + false, // Debug telnet + false, // Debug serial + 5, // Debug level + 0x03, // HAN pin + 0xFF, // AP pin + 0x02, // LED pin + true, // Inverted + 0xFF, // Red + 0xFF, // Green + 0xFF, // Blue + true, // Inverted + 0xFF, // Temp sensor + 0xFF, // Vcc + 100, // Multiplier + 0 // Boot limit + }; + bool wifiChanged, mqttChanged; - String wifiSsid; - String wifiPassword; - String wifiIp; - String wifiGw; - String wifiSubnet; - String wifiDns1; - String wifiDns2; - String wifiHostname; - bool wifiChanged = false; - - String mqttHost; - int mqttPort = 1883; - String mqttClientId; - String mqttPublishTopic; - String mqttSubscribeTopic; - String mqttUser; - String mqttPassword; - int mqttPayloadFormat = 0; - bool mqttSsl; - bool mqttChanged = false; - - byte authSecurity; - String authUser; - String authPassword; - - int meterType = 0, distributionSystem = 0, mainFuse = 0, productionCapacity = 0; - - bool debugTelnet = false, debugSerial = false; - int debugLevel = 3; - - const int EEPROM_SIZE = 512; + const int EEPROM_SIZE = 2048; const int EEPROM_CHECK_SUM = 82; // Used to check if config is stored. Change if structure changes const int EEPROM_CONFIG_ADDRESS = 0; - bool loadConfig72(int address); - bool loadConfig75(int address); bool loadConfig80(int address); bool loadConfig81(int address); - bool loadConfig82(int address); - int saveString(int pAddress, const char* pString); int readString(int pAddress, char* pString[]); - int saveInt(int pAddress, int pValue); int readInt(int pAddress, int *pValue); - int saveBool(int pAddress, bool pValue); int readBool(int pAddress, bool *pValue); - int saveByte(int pAddress, byte pValue); int readByte(int pAddress, byte *pValue); - - template int writeAnything(int ee, const T& value); - template int readAnything(int ee, T& value); }; #endif diff --git a/src/AmsToMqttBridge.h b/src/AmsToMqttBridge.h index 1d60906f..3762cf90 100644 --- a/src/AmsToMqttBridge.h +++ b/src/AmsToMqttBridge.h @@ -5,6 +5,7 @@ #define INVALID_BUTTON_PIN 0xFFFFFFFF +#include #if defined(ESP8266) #include @@ -17,62 +18,4 @@ #include "Update.h" #endif -#define RGB_RED 1 -#define RGB_GREEN 2 -#define RGB_YELLOW 3 -#define RGB_ON 1 -#define RGB_OFF 0 - -// Build settings for custom hardware by Roar Fredriksen -#if HW_ROARFRED -#define LED_PIN 2 // The blue on-board LED of the ESP8266 custom AMS board -#define LED_ACTIVE_HIGH 0 -#define AP_BUTTON_PIN 0 - -HardwareSerial *hanSerial = &Serial; - -// Build settings for Wemos Lolin D32 -#elif defined(ARDUINO_LOLIN_D32) -#define LED_PIN 5 -#define LED_ACTIVE_HIGH 0 -#define AP_BUTTON_PIN 4 - -HardwareSerial *hanSerial = &Serial2; - -// Build settings for Wemos D1 mini -#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI) -#define LED_PIN D4 -#define LED_ACTIVE_HIGH 0 -#define AP_BUTTON_PIN D2 - -#define SOFTWARE_SERIAL 1 -#include -SoftwareSerial *hanSerial = new SoftwareSerial(D1); - -// Build settings for Adafruit Feather ESP32 -#elif defined(ARDUINO_FEATHER_ESP32) -#define LED_PIN LED_BUILTIN -#define LED_ACTIVE_HIGH 1 -#define AP_BUTTON_PIN INVALID_BUTTON_PIN - -HardwareSerial *hanSerial = &Serial2; - -// Default build for ESP32 -#elif defined(ESP32) -#define LED_PIN INVALID_BUTTON_PIN -#define LED_ACTIVE_HIGH 1 -#define AP_BUTTON_PIN INVALID_BUTTON_PIN - -HardwareSerial *hanSerial = &Serial2; - -// Default build settings -#else -#define LED_PIN 2 -#define LED_ACTIVE_HIGH 0 -#define AP_BUTTON_PIN INVALID_BUTTON_PIN -#define SOFTWARE_SERIAL 1 -#include -SoftwareSerial *hanSerial = new SoftwareSerial(5); -#endif - #endif diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 07363bf6..98a67840 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -55,32 +55,92 @@ AmsConfiguration config; RemoteDebug Debug; -AmsWebServer ws(&Debug); +AmsWebServer ws(&Debug, &hw); MQTTClient mqtt(512); HanReader hanReader; +Stream *hanSerial; +int hanSerialPin = 0; + void setup() { if(config.hasConfig()) { config.load(); } -#if HW_ROARFRED - if(config.getMeterType() == 3) { - Serial.begin(2400, SERIAL_8N1); - } else { - Serial.begin(2400, SERIAL_8E1); + + if(!config.hasConfig() || config.getConfigVersion() < 81) { + debugI("Setting default hostname"); + uint16_t chipId; + #if defined(ESP32) + chipId = ESP.getEfuseMac(); + #else + chipId = ESP.getChipId(); + #endif + config.setWifiHostname((String("ams-") + String(chipId, HEX)).c_str()); + } + + if(!config.hasConfig() || config.getConfigVersion() < 82) { + config.setVccMultiplier(1.0); + config.setVccBootLimit(0); + #if HW_ROARFRED + config.setHanPin(3); + config.setApPin(0); + config.setLedPin(2); + config.setLedInverted(true); + config.setTempSensorPin(5); + #elif defined(ARDUINO_ESP8266_WEMOS_D1MINI) + config.setHanPin(5); + config.setApPin(4); + config.setLedPin(2); + config.setLedInverted(true); + config.setTempSensorPin(14); + config.setVccMultiplier(1.1); + #elif defined(ARDUINO_LOLIN_D32) + config.setHanPin(16); + config.setLedPin(5); + config.setLedInverted(true); + config.setTempSensorPin(14); + config.setVccPin(35); + config.setVccMultiplier(2.25); + #elif defined(ARDUINO_FEATHER_ESP32) + config.setHanPin(16); + config.setLedPin(2); + config.setTempSensorPin(14); + #elif defined(ESP8266) + config.setHanPin(3); + config.setLedPin(2); + config.setLedInverted(true); + #elif defined(ESP32) + config.setHanPin(16); + config.setLedPin(2); + config.setLedInverted(true); + config.setTempSensorPin(14); + #endif + } + + hw.setLed(config.getLedPin(), config.isLedInverted()); + hw.setLedRgb(config.getLedPinRed(), config.getLedPinGreen(), config.getLedPinBlue(), config.isLedRgbInverted()); + hw.setTempSensorPin(config.getTempSensorPin()); + hw.setVccPin(config.getVccPin()); + hw.setVccMultiplier(config.getVccMultiplier()); + + if(config.getHanPin() == 3) { + if(config.getMeterType() == 3) { + Serial.begin(2400, SERIAL_8N1); + } else { + Serial.begin(2400, SERIAL_8E1); + } + } else { + Serial.begin(115200); } -#else - Serial.begin(115200); -#endif if(config.hasConfig() && config.isDebugSerial()) { Debug.setSerialEnabled(config.isDebugSerial()); } else { -#if DEBUG_MODE - Debug.setSerialEnabled(true); -#endif + #if DEBUG_MODE + Debug.setSerialEnabled(true); + #endif } double vcc = hw.getVcc(); @@ -90,26 +150,16 @@ void setup() { debugI("Voltage: %.2fV", vcc); } -#if SELF_POWERED - if (vcc > 2.5 && vcc < 3.25) { // Only sleep if voltage is realistic and too low - if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Voltage is too low, sleeping"); - Serial.flush(); - } - ESP.deepSleep(10000000); //Deep sleep to allow output cap to charge up - } -#endif - - #if HAS_RGB_LED - // Initialize RGB LED pins - pinMode(LEDPIN_RGB_GREEN, OUTPUT); - pinMode(LEDPIN_RGB_RED, OUTPUT); - #endif - - pinMode(LED_PIN, OUTPUT); - pinMode(AP_BUTTON_PIN, INPUT_PULLUP); - - led_off(); + double vccBootLimit = config.getVccBootLimit(); + if(vccBootLimit > 0 && (config.getApPin() == -1 || digitalRead(config.getApPin()) == HIGH)) { // Skip if user is holding AP button while booting (HIGH = button is released) + if (vcc < vccBootLimit) { + if(Debug.isActive(RemoteDebug::INFO)) { + debugI("Voltage is too low, sleeping"); + Serial.flush(); + } + ESP.deepSleep(10000000); //Deep sleep to allow output cap to charge up + } + } WiFi.disconnect(true); WiFi.softAPdisconnect(true); @@ -178,17 +228,6 @@ void setup() { } } - if(!config.hasConfig() || config.getConfigVersion() < 81) { - debugI("Setting default hostname"); - uint16_t chipId; -#if defined(ARDUINO_ARCH_ESP32) - chipId = ESP.getEfuseMac(); -#else - chipId = ESP.getChipId(); -#endif - config.setWifiHostname(String("ams-") + String(chipId, HEX)); - } - if(config.hasConfig()) { if(Debug.isActive(RemoteDebug::INFO)) config.print(&Debug); WiFi_connect(); @@ -199,49 +238,8 @@ void setup() { swapWifiMode(); } -#if SOFTWARE_SERIAL - if(Debug.isActive(RemoteDebug::DEBUG)) debugD("HAN has software serial"); - if(config.getMeterType() == 3) { - hanSerial->begin(2400, SWSERIAL_8N1); - } else { - hanSerial->begin(2400, SWSERIAL_8E1); - } -#else - if(Debug.isActive(RemoteDebug::DEBUG)) { - debugD("HAN has hardware serial"); - Serial.flush(); - } - if(config.getMeterType() == 3) { - hanSerial->begin(2400, SERIAL_8N1); - } else { - hanSerial->begin(2400, SERIAL_8E1); - } -#if UART2 - hanSerial->swap(); -#endif -#endif - - hanReader.setup(hanSerial, &Debug); - - // Compensate for the known Kaifa bug - hanReader.compensateFor09HeaderBug = (config.getMeterType() == 1); - - // Empty buffer before starting - while (hanSerial->available() > 0) { - hanSerial->read(); - } - ws.setup(&config, &mqtt); timeClient.begin(); - -#if HAS_RGB_LED - //Signal startup by blinking red / green / yellow - rgb_led(RGB_RED, 2); - delay(250); - rgb_led(RGB_GREEN, 2); - delay(250); - rgb_led(RGB_YELLOW, 2); -#endif } int buttonTimer = 0; @@ -254,7 +252,6 @@ bool wifiConnected = false; unsigned long lastTemperatureRead = 0; double temperature = -127; -bool even = true; unsigned long lastRead = 0; unsigned long lastSuccessfulRead = 0; @@ -264,8 +261,8 @@ int lastError = 0; void loop() { Debug.handle(); unsigned long now = millis(); - if(AP_BUTTON_PIN != INVALID_BUTTON_PIN) { - if (digitalRead(AP_BUTTON_PIN) == LOW) { + if(config.getApPin() != INVALID_BUTTON_PIN) { + if (digitalRead(config.getApPin()) == LOW) { if (buttonActive == false) { buttonActive = true; buttonTimer = now; @@ -300,8 +297,6 @@ void loop() { // Only do normal stuff if we're not booted as AP if (WiFi.getMode() != WIFI_AP) { - led_off(); - if (WiFi.status() != WL_CONNECTED) { wifiConnected = false; Debug.stop(); @@ -313,6 +308,7 @@ void loop() { Debug.setPassword(config.getAuthPassword()); } Debug.begin(config.getWifiHostname(), (uint8_t) config.getDebugLevel()); + Debug.setSerialEnabled(config.isDebugSerial()); if(!config.isDebugTelnet()) { Debug.stop(); } @@ -320,12 +316,12 @@ void loop() { debugI("Successfully connected to WiFi!"); debugI("IP: %s", WiFi.localIP().toString().c_str()); } - if(!config.getWifiHostname().isEmpty()) { - MDNS.begin(config.getWifiHostname().c_str()); + if(strlen(config.getWifiHostname()) > 0) { + MDNS.begin(config.getWifiHostname()); MDNS.addService("http", "tcp", 80); } } - if (!config.getMqttHost().isEmpty()) { + 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 if(!mqtt.connected() || config.isMqttChanged()) { @@ -341,10 +337,13 @@ void loop() { } else { dnsServer.processNextRequest(); // Continously flash the LED when AP mode - if (now / 50 % 64 == 0) led_on(); - else led_off(); - + hw.ledBlink(LED_INTERNAL, 1); } + + if(hanSerialPin != config.getHanPin()) { + setupHanPort(config.getHanPin(), config.getMeterType()); + } + if(now - lastRead > 100) { yield(); readHanPort(); @@ -354,24 +353,67 @@ void loop() { delay(1); // Needed for auto modem sleep } +void setupHanPort(int pin, int meterType) { + debugI("Setting up HAN on pin %d for meter type %d", pin, meterType); -void led_on() -{ -#if LED_ACTIVE_HIGH - digitalWrite(LED_PIN, HIGH); -#else - digitalWrite(LED_PIN, LOW); -#endif -} + HardwareSerial *hwSerial = NULL; + if(pin == 3) { + hwSerial = &Serial; + } + #if defined(ESP32) + if(pin == 9) { + hwSerial = &Serial1; + } + if(pin == 16) { + hwSerial = &Serial2; + } + #endif + if(hwSerial != NULL) { + debugD("Hardware serial"); + Serial.flush(); + if(meterType == 3) { + hwSerial->begin(2400, SERIAL_8N1); + } else { + hwSerial->begin(2400, SERIAL_8E1); + } + hanSerialPin = pin; + hanSerial = hwSerial; + } else { + debugD("Software serial"); + Serial.flush(); + SoftwareSerial *swSerial = new SoftwareSerial(pin); -void led_off() -{ -#if LED_ACTIVE_HIGH - digitalWrite(LED_PIN, LOW); -#else - digitalWrite(LED_PIN, HIGH); -#endif + if(meterType == 3) { + swSerial->begin(2400, SWSERIAL_8N1); + } else { + swSerial->begin(2400, SWSERIAL_8E1); + } + hanSerialPin = pin; + hanSerial = swSerial; + + Serial.begin(115200); + } + + hanReader.setup(hanSerial, &Debug); + + // Compensate for the known Kaifa bug + hanReader.compensateFor09HeaderBug = (config.getMeterType() == 1); + + // Empty buffer before starting + while (hanSerial->available() > 0) { + hanSerial->read(); + } + + if(config.hasConfig() && config.isDebugSerial()) { + if(WiFi.status() == WL_CONNECTED) { + Debug.begin(config.getWifiHostname(), (uint8_t) config.getDebugLevel()); + } + Debug.setSerialEnabled(config.isDebugSerial()); + if(!config.isDebugTelnet()) { + Debug.stop(); + } + } } void errorBlink() { @@ -382,19 +424,19 @@ void errorBlink() { switch(lastError) { case 0: if(lastErrorBlink - lastSuccessfulRead > 30000) { - rgb_led(1, 2); // If no message received from AMS in 30 sec, blink once + hw.ledBlink(LED_RED, 1); // If no message received from AMS in 30 sec, blink once return; } break; case 1: - if(!config.getMqttHost().isEmpty() && mqtt.lastError() != 0) { - rgb_led(1, 3); // If MQTT error, blink twice + if(strlen(config.getMqttHost()) > 0 && mqtt.lastError() != 0) { + hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice return; } break; case 2: if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) { - rgb_led(1, 4); // If WiFi not connected, blink three times + hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times return; } break; @@ -403,7 +445,7 @@ void errorBlink() { } void swapWifiMode() { - led_on(); + hw.ledOn(LED_INTERNAL); WiFiMode_t mode = WiFi.getMode(); dnsServer.stop(); WiFi.disconnect(true); @@ -423,7 +465,7 @@ void swapWifiMode() { WiFi_connect(); } delay(500); - led_off(); + hw.ledOff(LED_INTERNAL); } void mqttMessageReceived(String &topic, String &payload) @@ -437,6 +479,7 @@ void mqttMessageReceived(String &topic, String &payload) // Ideas could be to query for values or to initiate OTA firmware update } +int currentMeterType = 0; AmsData lastMqttData; void readHanPort() { if (hanReader.read()) { @@ -448,13 +491,16 @@ void readHanPort() { lastSuccessfulRead = millis(); if(config.getMeterType() > 0) { - rgb_led(RGB_GREEN, 2); + if(config.getLedPinGreen() != 0xFF) + hw.ledBlink(LED_GREEN, 1); + else + hw.ledBlink(LED_INTERNAL, 1); AmsData data(config.getMeterType(), hanReader); if(data.getListType() > 0) { ws.setData(data); - if(!config.getMqttHost().isEmpty() && !config.getMqttPublishTopic().isEmpty()) { + if(strlen(config.getMqttHost()) > 0 && strlen(config.getMqttPublishTopic()) > 0) { if(config.getMqttPayloadFormat() == 0) { StaticJsonDocument<512> json; hanToJson(json, data, hw, temperature); @@ -469,55 +515,55 @@ void readHanPort() { serializeJson(json, msg); mqtt.publish(config.getMqttPublishTopic(), msg.c_str()); } else if(config.getMqttPayloadFormat() == 1 || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/dlms/timestamp", String(data.getPackageTimestamp())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/dlms/timestamp", String(data.getPackageTimestamp())); switch(data.getListType()) { case 3: // ID and type belongs to List 2, but I see no need to send that every 10s - mqtt.publish(config.getMqttPublishTopic() + "/meter/id", data.getMeterId()); - mqtt.publish(config.getMqttPublishTopic() + "/meter/type", data.getMeterType()); - mqtt.publish(config.getMqttPublishTopic() + "/meter/clock", String(data.getMeterTimestamp())); - mqtt.publish(config.getMqttPublishTopic() + "/meter/import/reactive/accumulated", String(data.getReactiveImportCounter(), 2)); - mqtt.publish(config.getMqttPublishTopic() + "/meter/import/active/accumulated", String(data.getActiveImportCounter(), 2)); - mqtt.publish(config.getMqttPublishTopic() + "/meter/export/reactive/accumulated", String(data.getReactiveExportCounter(), 2)); - mqtt.publish(config.getMqttPublishTopic() + "/meter/export/active/accumulated", String(data.getActiveExportCounter(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/id", data.getMeterId()); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/type", data.getMeterType()); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/clock", String(data.getMeterTimestamp())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/reactive/accumulated", String(data.getReactiveImportCounter(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/active/accumulated", String(data.getActiveImportCounter(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/reactive/accumulated", String(data.getReactiveExportCounter(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/active/accumulated", String(data.getActiveExportCounter(), 2)); case 2: // Only send data if changed. ID and Type is sent on the 10s interval only if changed if(lastMqttData.getMeterId() != data.getMeterId() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/id", data.getMeterId()); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/id", data.getMeterId()); } if(lastMqttData.getMeterType() != data.getMeterType() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/type", data.getMeterType()); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/type", data.getMeterType()); } if(lastMqttData.getL1Current() != data.getL1Current() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/l1/current", String(data.getL1Current(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l1/current", String(data.getL1Current(), 2)); } if(lastMqttData.getL1Voltage() != data.getL1Voltage() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/l1/voltage", String(data.getL1Voltage(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l1/voltage", String(data.getL1Voltage(), 2)); } if(lastMqttData.getL2Current() != data.getL2Current() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/l2/current", String(data.getL2Current(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l2/current", String(data.getL2Current(), 2)); } if(lastMqttData.getL2Voltage() != data.getL2Voltage() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/l2/voltage", String(data.getL2Voltage(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l2/voltage", String(data.getL2Voltage(), 2)); } if(lastMqttData.getL3Current() != data.getL3Current() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/l3/current", String(data.getL3Current(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l3/current", String(data.getL3Current(), 2)); } if(lastMqttData.getL3Voltage() != data.getL3Voltage() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/l3/voltage", String(data.getL3Voltage(), 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l3/voltage", String(data.getL3Voltage(), 2)); } if(lastMqttData.getReactiveExportPower() != data.getReactiveExportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/export/reactive", String(data.getReactiveExportPower())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/reactive", String(data.getReactiveExportPower())); } if(lastMqttData.getActiveExportPower() != data.getActiveExportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/export/active", String(data.getActiveExportPower())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/active", String(data.getActiveExportPower())); } if(lastMqttData.getReactiveImportPower() != data.getReactiveImportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/import/reactive", String(data.getReactiveImportPower())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/reactive", String(data.getReactiveImportPower())); } case 1: if(lastMqttData.getActiveImportPower() != data.getActiveImportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(config.getMqttPublishTopic() + "/meter/import/active", String(data.getActiveImportPower())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/active", String(data.getActiveImportPower())); } } } @@ -565,22 +611,10 @@ void readHanPort() { // Switch parity if meter is still not detected if(config.getMeterType() == 0 && millis() - lastSuccessfulRead > 10000) { lastSuccessfulRead = millis(); - if(Debug.isActive(RemoteDebug::DEBUG)) debugD("No data for current setting, switching parity"); + debugD("No data for current setting, switching parity"); Serial.flush(); -#if SOFTWARE_SERIAL - if(even) { - hanSerial->begin(2400, SWSERIAL_8N1); - } else { - hanSerial->begin(2400, SWSERIAL_8E1); - } -#else - if(even) { - hanSerial->begin(2400, SERIAL_8N1); - } else { - hanSerial->begin(2400, SERIAL_8E1); - } -#endif - even = !even; + if(++currentMeterType == 4) currentMeterType = 1; + setupHanPort(config.getHanPin(), currentMeterType); } } @@ -593,7 +627,7 @@ void WiFi_connect() { } lastWifiRetry = millis(); - if (Debug.isActive(RemoteDebug::INFO)) debugI("Connecting to WiFi network: %s", config.getWifiSsid().c_str()); + if (Debug.isActive(RemoteDebug::INFO)) debugI("Connecting to WiFi network: %s", config.getWifiSsid()); if (WiFi.status() != WL_CONNECTED) { MDNS.end(); @@ -602,7 +636,7 @@ void WiFi_connect() { WiFi.enableAP(false); WiFi.mode(WIFI_STA); - if(!config.getWifiIp().isEmpty()) { + if(strlen(config.getWifiIp()) > 0) { IPAddress ip, gw, sn(255,255,255,0), dns1, dns2; ip.fromString(config.getWifiIp()); gw.fromString(config.getWifiGw()); @@ -611,21 +645,21 @@ void WiFi_connect() { dns2.fromString(config.getWifiDns2()); WiFi.config(ip, gw, sn, dns1, dns2); } - if(!config.getWifiHostname().isEmpty()) { + if(strlen(config.getWifiHostname()) > 0) { #if defined(ESP8266) WiFi.hostname(config.getWifiHostname()); #elif defined(ESP32) - WiFi.setHostname(config.getWifiHostname().c_str()); + WiFi.setHostname(config.getWifiHostname()); #endif } - WiFi.begin(config.getWifiSsid().c_str(), config.getWifiPassword().c_str()); + WiFi.begin(config.getWifiSsid(), config.getWifiPassword()); yield(); } } unsigned long lastMqttRetry = -10000; void MQTT_connect() { - if(config.getMqttHost().isEmpty()) { + if(strlen(config.getMqttHost()) == 0) { if(Debug.isActive(RemoteDebug::WARNING)) debugW("No MQTT config"); return; } @@ -635,7 +669,7 @@ void MQTT_connect() { } lastMqttRetry = millis(); if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Connecting to MQTT %s:%d", config.getMqttHost().c_str(), config.getMqttPort()); + debugI("Connecting to MQTT %s:%d", config.getMqttHost(), config.getMqttPort()); } mqtt.disconnect(); @@ -680,22 +714,22 @@ void MQTT_connect() { client = new WiFiClient(); } - mqtt.begin(config.getMqttHost().c_str(), config.getMqttPort(), *client); + mqtt.begin(config.getMqttHost(), 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()))) { + if ((strlen(config.getMqttUser()) == 0 && mqtt.connect(config.getMqttClientId())) || + (strlen(config.getMqttUser()) > 0 && mqtt.connect(config.getMqttClientId(), config.getMqttUser(), config.getMqttPassword()))) { if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!"); config.ackMqttChange(); // Subscribe to the chosen MQTT topic, if set in configuration - if (!config.getMqttSubscribeTopic().isEmpty()) { + if (strlen(config.getMqttSubscribeTopic()) > 0) { mqtt.subscribe(config.getMqttSubscribeTopic()); - if (Debug.isActive(RemoteDebug::INFO)) debugI(" Subscribing to [%s]\r\n", config.getMqttSubscribeTopic().c_str()); + if (Debug.isActive(RemoteDebug::INFO)) debugI(" Subscribing to [%s]\r\n", config.getMqttSubscribeTopic()); } if(config.getMqttPayloadFormat() == 0) { @@ -722,7 +756,7 @@ void MQTT_connect() { void sendMqttData(String data) { // Make sure we have configured a publish topic - if (config.getMqttPublishTopic().isEmpty()) + if (strlen(config.getMqttPublishTopic()) == 0) return; // Build a json with the message in a "data" attribute @@ -749,63 +783,20 @@ void sendMqttData(String data) unsigned long lastSystemDataSent = -10000; void sendSystemStatusToMqtt() { - if (config.getMqttPublishTopic().isEmpty()) + if (strlen(config.getMqttPublishTopic()) == 0) return; if(millis() - lastSystemDataSent < 10000) return; lastSystemDataSent = millis(); - mqtt.publish(config.getMqttPublishTopic() + "/id", WiFi.macAddress()); - mqtt.publish(config.getMqttPublishTopic() + "/uptime", String((unsigned long) millis64()/1000)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/id", WiFi.macAddress()); + mqtt.publish(String(config.getMqttPublishTopic()) + "/uptime", String((unsigned long) millis64()/1000)); double vcc = hw.getVcc(); if(vcc > 0) { - mqtt.publish(config.getMqttPublishTopic() + "/vcc", String(vcc, 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/vcc", String(vcc, 2)); } - mqtt.publish(config.getMqttPublishTopic() + "/rssi", String(hw.getWifiRssi())); + mqtt.publish(String(config.getMqttPublishTopic()) + "/rssi", String(hw.getWifiRssi())); if(temperature != DEVICE_DISCONNECTED_C) { - mqtt.publish(config.getMqttPublishTopic() + "/temperature", String(temperature, 2)); + mqtt.publish(String(config.getMqttPublishTopic()) + "/temperature", String(temperature, 2)); } } - -void rgb_led(int color, int mode) { -// Activate red and green LEDs if RGB LED is present (HAS_RGB_LED=1) -// If no RGB LED present (HAS_RGB_LED=0 or not defined), all output goes to ESP onboard LED -// color: 1=red, 2=green, 3=yellow -// mode: 0=OFF, 1=ON, >=2 -> Short blink(s), number of blinks: (mode - 1) -#ifndef HAS_RGB_LED -#define LEDPIN_RGB_RED LED_PIN -#define LEDPIN_RGB_GREEN LED_PIN -#endif - int blinkduration = 50; // milliseconds - switch (mode) { - case RGB_OFF: //OFF - digitalWrite(LEDPIN_RGB_RED, HIGH); - digitalWrite(LEDPIN_RGB_GREEN, HIGH); - break; - case RGB_ON: //ON - switch (color) { - case RGB_RED: //Red - digitalWrite(LEDPIN_RGB_RED, LOW); - digitalWrite(LEDPIN_RGB_GREEN, HIGH); - break; - case RGB_GREEN: //Green - digitalWrite(LEDPIN_RGB_RED, HIGH); - digitalWrite(LEDPIN_RGB_GREEN, LOW); - break; - case RGB_YELLOW: //Yellow - digitalWrite(LEDPIN_RGB_RED, LOW); - digitalWrite(LEDPIN_RGB_GREEN, LOW); - break; - } - break; - default: // Blink - for(int i = 1; i < mode; i++) { - rgb_led(color, RGB_ON); - delay(blinkduration); - rgb_led(color, RGB_OFF); - if(i != mode) - delay(blinkduration); - } - break; - } -} diff --git a/src/HwTools.cpp b/src/HwTools.cpp index 8aab97cc..8fa2762a 100644 --- a/src/HwTools.cpp +++ b/src/HwTools.cpp @@ -1,44 +1,164 @@ #include "HwTools.h" +void HwTools::setTempSensorPin(int tempSensorPin) { + if(tempSensorPin != this->tempSensorPin) { + this->tempSensorInit = false; + if(tempSensor) + delete tempSensor; + if(oneWire) + delete oneWire; + if(tempSensorPin > 0 && tempSensorPin < 40) { + this->tempSensorPin = tempSensorPin; + pinMode(tempSensorPin, INPUT); + } else { + this->tempSensorPin = 0xFF; + } + } +} + +void HwTools::setVccPin(int vccPin) { + if(vccPin > 0 && vccPin < 40) { + pinMode(vccPin, INPUT); + this->vccPin = vccPin; + } else { + this->vccPin = 0xFF; + } +} + +void HwTools::setVccMultiplier(double vccMultiplier) { + this->vccMultiplier = vccMultiplier; +} + double HwTools::getVcc() { double volts = 0.0; -#if defined(ARDUINO_ESP8266_WEMOS_D1MINI) - volts = (((double) ESP.getVcc()) / 900.0); // This board has a voltage divider on VCC. -#elif defined(ARDUINO_LOLIN_D32) - volts = (analogRead(GPIO_NUM_35) / 4095.0) * 3.3 * 2.25; // We are actually reading battery voltage here -#elif defined(ESP8266) - volts = ((double) ESP.getVcc()) / 1024.0; -#endif + if(vccPin != 0xFF) { + #if defined(ESP8266) + volts = (analogRead(vccPin) / 1024.0) * 3.3; + #elif defined(ESP32) + volts = (analogRead(vccPin) / 4095.0) * 3.3; + #endif + } else { + #if defined(ESP8266) + volts = ((double) ESP.getVcc()) / 1024.0; + #endif + } -#if defined(ESP_VCC_CALIB_FACTOR) - return volts * ESP_VCC_CALIB_FACTOR; -#else - return volts; -#endif + return volts > 0.0 ? volts * vccMultiplier : 0.0; } double HwTools::getTemperature() { + if(tempSensorPin != 0xFF) { + if(!tempSensorInit) { + oneWire = new OneWire(tempSensorPin); + tempSensor = new DallasTemperature(this->oneWire); + tempSensor->begin(); + delay(50); + tempSensor->requestTemperatures(); + hasTempSensor = tempSensor->getTempCByIndex(0) != DEVICE_DISCONNECTED_C; + tempSensorInit = true; + } -#if defined TEMP_SENSOR_PIN - if(!tempSensorInit) { - tempSensor->begin(); - delay(50); - tempSensor->requestTemperatures(); - hasTempSensor = tempSensor->getTempCByIndex(0) != DEVICE_DISCONNECTED_C; - tempSensorInit = true; + if(hasTempSensor) { + tempSensor->requestTemperatures(); + return tempSensor->getTempCByIndex(0); + } else { + return DEVICE_DISCONNECTED_C; + } } - if(hasTempSensor) { - tempSensor->requestTemperatures(); - return tempSensor->getTempCByIndex(0); - } else { - return DEVICE_DISCONNECTED_C; - } -#endif return DEVICE_DISCONNECTED_C; } int HwTools::getWifiRssi() { int rssi = WiFi.RSSI(); return isnan(rssi) ? -100.0 : rssi; -} \ No newline at end of file +} + +void HwTools::setLed(uint8_t ledPin, bool ledInverted) { + if(ledPin > 0 && ledPin < 40) { + this->ledPin = ledPin; + this->ledInverted = ledInverted; + pinMode(ledPin, OUTPUT); + ledOff(LED_INTERNAL); + } else { + this->ledPin = 0xFF; + } +} + +void HwTools::setLedRgb(uint8_t ledPinRed, uint8_t ledPinGreen, uint8_t ledPinBlue, bool ledRgbInverted) { + this->ledRgbInverted = ledRgbInverted; + if(ledPinRed > 0 && ledPinRed < 40) { + this->ledPinRed = ledPinRed; + pinMode(ledPinRed, OUTPUT); + ledOff(LED_RED); + } else { + this->ledPinRed = 0xFF; + } + if(ledPinGreen > 0 && ledPinGreen < 40) { + this->ledPinGreen = ledPinGreen; + pinMode(ledPinGreen, OUTPUT); + ledOff(LED_GREEN); + } else { + this->ledPinGreen = 0xFF; + } + if(ledPinBlue > 0 && ledPinBlue < 40) { + this->ledPinBlue = ledPinBlue; + pinMode(ledPinBlue, OUTPUT); + ledOff(LED_BLUE); + } else { + this->ledPinBlue = 0xFF; + } +} + +void HwTools::ledOn(uint8_t color) { + if(color == LED_INTERNAL) { + writeLedPin(color, ledInverted ? LOW : HIGH); + } else { + writeLedPin(color, ledRgbInverted ? LOW : HIGH); + } +} + +void HwTools::ledOff(uint8_t color) { + if(color == LED_INTERNAL) { + writeLedPin(color, ledInverted ? HIGH : LOW); + } else { + writeLedPin(color, ledRgbInverted ? HIGH : LOW); + } +} + +void HwTools::ledBlink(uint8_t color, uint8_t blink) { + for(int i = 0; i < blink; i++) { + ledOn(color); + delay(50); + ledOff(color); + if(i != blink) + delay(50); + } +} + +void HwTools::writeLedPin(uint8_t color, uint8_t state) { + switch(color) { + case LED_INTERNAL: + if(ledPin != 0xFF) + digitalWrite(ledPin, state); + break; + case LED_RED: + if(ledPinRed != 0xFF) + digitalWrite(ledPinRed, state); + break; + case LED_GREEN: + if(ledPinGreen != 0xFF) + digitalWrite(ledPinGreen, state); + break; + case LED_BLUE: + if(ledPinBlue != 0xFF) + digitalWrite(ledPinBlue, state); + break; + case LED_YELLOW: + if(ledPinRed != 0xFF && ledPinGreen != 0xFF) { + digitalWrite(ledPinRed, state); + digitalWrite(ledPinGreen, state); + } + break; + } +} diff --git a/src/HwTools.h b/src/HwTools.h index c2245f4f..d6a9f957 100644 --- a/src/HwTools.h +++ b/src/HwTools.h @@ -12,35 +12,38 @@ #include #include -#if HW_ROARFRED -#define TEMP_SENSOR_PIN 5 -#elif defined(ARDUINO_LOLIN_D32) -#define TEMP_SENSOR_PIN 14 -#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI) -#define TEMP_SENSOR_PIN D5 -#else -#define TEMP_SENSOR_PIN 0xFFFFFFFF -#endif - - +#define LED_INTERNAL 0 +#define LED_RED 1 +#define LED_GREEN 2 +#define LED_BLUE 3 +#define LED_YELLOW 4 class HwTools { public: + void setTempSensorPin(int tempSensorPin); + void setVccPin(int vccPin); + void setVccMultiplier(double vccMultiplier); double getVcc(); double getTemperature(); int getWifiRssi(); + void setLed(uint8_t ledPin, bool ledInverted); + void setLedRgb(uint8_t ledPinRed, uint8_t ledPinGreen, uint8_t ledPinBlue, bool ledRgbInverted); + void ledOn(uint8_t color); + void ledOff(uint8_t color); + void ledBlink(uint8_t color, uint8_t blink); - HwTools() { -#if defined(ARDUINO_LOLIN_D32) - pinMode(GPIO_NUM_35, INPUT); -#endif - oneWire = new OneWire(TEMP_SENSOR_PIN); - tempSensor = new DallasTemperature(this->oneWire); - }; + HwTools() {}; private: + uint8_t tempSensorPin = -1; + uint8_t vccPin = -1; + uint8_t ledPin = -1, ledPinRed = -1, ledPinGreen = -1, ledPinBlue = -1; + bool ledInverted, ledRgbInverted; + double vccMultiplier = 1.0; bool tempSensorInit, hasTempSensor; OneWire *oneWire; DallasTemperature *tempSensor; + + void writeLedPin(uint8_t color, uint8_t state); }; #endif diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 2518cb62..5e106905 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -4,6 +4,7 @@ #include "root/index_html.h" #include "root/index_js.h" +#include "root/setup_html.h" #include "root/configmeter_html.h" #include "root/configwifi_html.h" #include "root/configmqtt_html.h" @@ -17,8 +18,9 @@ #include "Base64.h" -AmsWebServer::AmsWebServer(RemoteDebug* Debug) { +AmsWebServer::AmsWebServer(RemoteDebug* Debug, HwTools* hw) { this->debugger = Debug; + this->hw = hw; } void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { @@ -26,6 +28,7 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { this->mqtt = 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("/config-meter", HTTP_GET, std::bind(&AmsWebServer::configMeterHtml, this)); server.on("/config-wifi", HTTP_GET, std::bind(&AmsWebServer::configWifiHtml, this)); @@ -38,7 +41,8 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { server.on("/save", HTTP_POST, std::bind(&AmsWebServer::handleSave, this)); server.on("/config-system", HTTP_GET, std::bind(&AmsWebServer::configSystemHtml, this)); - server.on("/config-system", HTTP_POST, std::bind(&AmsWebServer::uploadPost, this), std::bind(&AmsWebServer::configSystemUpload, this)); + server.on("/firmware", HTTP_GET, std::bind(&AmsWebServer::firmwareHtml, this)); + server.on("/firmware", HTTP_POST, std::bind(&AmsWebServer::uploadPost, this), std::bind(&AmsWebServer::firmwareUpload, this)); server.on("/restart-wait", HTTP_GET, std::bind(&AmsWebServer::restartWaitHtml, this)); server.on("/is-alive", HTTP_GET, std::bind(&AmsWebServer::isAliveCheck, this)); @@ -110,62 +114,64 @@ bool AmsWebServer::checkSecurity(byte level) { void AmsWebServer::indexHtml() { printD("Serving /index.html over http..."); - if(!checkSecurity(2)) - return; + String html; + if(WiFi.getMode() == WIFI_AP) { + html = String((const __FlashStringHelper*) SETUP_HTML); + html.replace("${version}", VERSION); + } else { + if(!checkSecurity(2)) + return; - String html = String((const __FlashStringHelper*) INDEX_HTML); - html.replace("${version}", VERSION); + html = String((const __FlashStringHelper*) INDEX_HTML); + html.replace("${version}", VERSION); - if(WiFi.getMode() != WIFI_AP) { - html.replace("boot.css", BOOTSTRAP_URL); + double u1 = data.getL1Voltage(); + double u2 = data.getL2Voltage(); + double u3 = data.getL3Voltage(); + double i1 = data.getL1Current(); + double i2 = data.getL2Current(); + double i3 = data.getL3Current(); + double tpi = data.getActiveImportCounter(); + double tpo = data.getActiveExportCounter(); + double tqi = data.getReactiveImportCounter(); + double tqo = data.getReactiveExportCounter(); + + html.replace("${data.P}", String(data.getActiveImportPower())); + html.replace("${data.PO}", String(data.getActiveExportPower())); + html.replace("${display.export}", config->getProductionCapacity() > 0 ? "" : "none"); + html.replace("${text.import}", config->getProductionCapacity() > 0 ? "Import" : "Consumption"); + + html.replace("${data.U1}", u1 > 0 ? String(u1, 1) : ""); + html.replace("${data.I1}", u1 > 0 ? String(i1, 1) : ""); + html.replace("${display.P1}", u1 > 0 ? "" : "none"); + + html.replace("${data.U2}", u2 > 0 ? String(u2, 1) : ""); + html.replace("${data.I2}", u2 > 0 ? String(i2, 1) : ""); + html.replace("${display.P2}", u2 > 0 ? "" : "none"); + + html.replace("${data.U3}", u3 > 0 ? String(u3, 1) : ""); + html.replace("${data.I3}", u3 > 0 ? String(i3, 1) : ""); + html.replace("${display.P3}", u3 > 0 ? "" : "none"); + + html.replace("${data.tPI}", tpi > 0 ? String(tpi, 1) : ""); + html.replace("${data.tPO}", tpi > 0 ? String(tpo, 1) : ""); + html.replace("${data.tQI}", tpi > 0 ? String(tqi, 1) : ""); + html.replace("${data.tQO}", tpi > 0 ? String(tqo, 1) : ""); + html.replace("${display.accumulative}", tpi > 0 ? "" : "none"); + + double vcc = hw->getVcc(); + html.replace("${vcc}", vcc > 0 ? String(vcc, 2) : ""); + + double temp = hw->getTemperature(); + html.replace("${temp}", temp > 0 ? String(temp, 1) : ""); + html.replace("${display.temp}", temp != DEVICE_DISCONNECTED_C ? "" : "none"); + + int rssi = hw->getWifiRssi(); + html.replace("${wifi.rssi}", vcc > 0 ? String(rssi) : ""); + html.replace("${wifi.channel}", WiFi.channel() > 0 ? String(WiFi.channel()) : ""); + html.replace("${wifi.ssid}", !WiFi.SSID().isEmpty() ? String(WiFi.SSID()) : ""); } - double u1 = data.getL1Voltage(); - double u2 = data.getL2Voltage(); - double u3 = data.getL3Voltage(); - double i1 = data.getL1Current(); - double i2 = data.getL2Current(); - double i3 = data.getL3Current(); - double tpi = data.getActiveImportCounter(); - double tpo = data.getActiveExportCounter(); - double tqi = data.getReactiveImportCounter(); - double tqo = data.getReactiveExportCounter(); - - html.replace("${data.P}", String(data.getActiveImportPower())); - html.replace("${data.PO}", String(data.getActiveExportPower())); - html.replace("${display.export}", config->getProductionCapacity() > 0 ? "" : "none"); - html.replace("${text.import}", config->getProductionCapacity() > 0 ? "Import" : "Consumption"); - - html.replace("${data.U1}", u1 > 0 ? String(u1, 1) : ""); - html.replace("${data.I1}", u1 > 0 ? String(i1, 1) : ""); - html.replace("${display.P1}", u1 > 0 ? "" : "none"); - - html.replace("${data.U2}", u2 > 0 ? String(u2, 1) : ""); - html.replace("${data.I2}", u2 > 0 ? String(i2, 1) : ""); - html.replace("${display.P2}", u2 > 0 ? "" : "none"); - - html.replace("${data.U3}", u3 > 0 ? String(u3, 1) : ""); - html.replace("${data.I3}", u3 > 0 ? String(i3, 1) : ""); - html.replace("${display.P3}", u3 > 0 ? "" : "none"); - - html.replace("${data.tPI}", tpi > 0 ? String(tpi, 1) : ""); - html.replace("${data.tPO}", tpi > 0 ? String(tpo, 1) : ""); - html.replace("${data.tQI}", tpi > 0 ? String(tqi, 1) : ""); - html.replace("${data.tQO}", tpi > 0 ? String(tqo, 1) : ""); - html.replace("${display.accumulative}", tpi > 0 ? "" : "none"); - - double vcc = hw.getVcc(); - html.replace("${vcc}", vcc > 0 ? String(vcc, 2) : ""); - - double temp = hw.getTemperature(); - html.replace("${temp}", temp > 0 ? String(temp, 1) : ""); - html.replace("${display.temp}", temp != DEVICE_DISCONNECTED_C ? "" : "none"); - - int rssi = hw.getWifiRssi(); - html.replace("${wifi.rssi}", vcc > 0 ? String(rssi) : ""); - html.replace("${wifi.channel}", WiFi.channel() > 0 ? String(WiFi.channel()) : ""); - html.replace("${wifi.ssid}", !WiFi.SSID().isEmpty() ? String(WiFi.SSID()) : ""); - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); @@ -190,10 +196,6 @@ void AmsWebServer::configMeterHtml() { String html = String((const __FlashStringHelper*) CONFIGMETER_HTML); html.replace("${version}", VERSION); - if(WiFi.getMode() != WIFI_AP) { - html.replace("boot.css", BOOTSTRAP_URL); - } - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); @@ -224,16 +226,12 @@ void AmsWebServer::configWifiHtml() { String html = String((const __FlashStringHelper*) CONFIGWIFI_HTML); html.replace("${version}", VERSION); - if(WiFi.getMode() != WIFI_AP) { - html.replace("boot.css", BOOTSTRAP_URL); - } - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); html.replace("${config.wifiSsid}", config->getWifiSsid()); html.replace("${config.wifiPassword}", config->getWifiPassword()); - html.replace("${config.wifiIpType1}", config->getWifiIp().isEmpty() ? "" : "selected"); + html.replace("${config.wifiIpType1}", strlen(config->getWifiIp()) > 0 ? "selected" : ""); html.replace("${config.wifiIp}", config->getWifiIp()); html.replace("${config.wifiGw}", config->getWifiGw()); html.replace("${config.wifiSubnet}", config->getWifiSubnet()); @@ -254,14 +252,10 @@ void AmsWebServer::configMqttHtml() { String html = String((const __FlashStringHelper*) CONFIGMQTT_HTML); html.replace("${version}", VERSION); - if(WiFi.getMode() != WIFI_AP) { - html.replace("boot.css", BOOTSTRAP_URL); - } - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - html.replace("${config.mqtt}", config->getMqttHost() == 0 ? "" : "checked"); + html.replace("${config.mqtt}", strlen(config->getMqttHost()) == 0 ? "" : "checked"); html.replace("${config.mqttHost}", config->getMqttHost()); if(config->getMqttPort() > 0) { html.replace("${config.mqttPort}", String(config->getMqttPort())); @@ -311,10 +305,6 @@ void AmsWebServer::configWebHtml() { String html = String((const __FlashStringHelper*) CONFIGWEB_HTML); html.replace("${version}", VERSION); - if(WiFi.getMode() != WIFI_AP) { - html.replace("boot.css", BOOTSTRAP_URL); - } - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); @@ -414,10 +404,10 @@ void AmsWebServer::dataJson() { json["maxPower"] = maxPwr; json["meterType"] = config->getMeterType(); json["uptime_seconds"] = millis64() / 1000; - double vcc = hw.getVcc(); + double vcc = hw->getVcc(); json["vcc"] = serialized(String(vcc, 3)); - double temp = hw.getTemperature(); + double temp = hw->getTemperature(); json["temp"] = serialized(String(temp, 2)); json.createNestedObject("wifi"); @@ -455,7 +445,7 @@ void AmsWebServer::dataJson() { json["status"]["han"] = hanStatus; String wifiStatus; - if(config->getWifiSsid().isEmpty()) { + if(strlen(config->getWifiSsid()) == 0) { wifiStatus = "secondary"; } else if(rssi > -75) { wifiStatus = "success"; @@ -467,7 +457,7 @@ void AmsWebServer::dataJson() { json["status"]["wifi"] = wifiStatus; String mqttStatus; - if(config->getMqttHost().isEmpty()) { + if(strlen(config->getMqttHost()) == 0) { mqttStatus = "secondary"; } else if(mqtt->connected()) { mqttStatus = "success"; @@ -491,6 +481,100 @@ void AmsWebServer::dataJson() { server.send(200, "application/json", jsonStr); } +void AmsWebServer::handleSetup() { + if(!server.hasArg("wifiSsid") || server.arg("wifiSsid").isEmpty() || !server.hasArg("wifiPassword") || server.arg("wifiPassword").isEmpty()) { + server.sendHeader("Location", String("/"), true); + server.send (302, "text/plain", ""); + } else { + config->setVccMultiplier(1.0); + config->setVccBootLimit(0); + switch(server.arg("board").toInt()) { + case 0: // roarfred + config->setHanPin(3); + config->setApPin(0); + config->setLedPin(2); + config->setLedInverted(true); + config->setTempSensorPin(5); + break; + case 1: // Arnio Kamstrup + config->setHanPin(3); + config->setApPin(0); + config->setLedPin(2); + config->setLedInverted(true); + config->setTempSensorPin(5); + config->setLedPinRed(13); + config->setLedPinGreen(14); + config->setLedRgbInverted(true); + break; + case 2: // spenceme + config->setHanPin(3); + config->setApPin(0); + config->setLedPin(2); + config->setLedInverted(true); + config->setTempSensorPin(5); + config->setVccBootLimit(3.3); + break; + case 101: // D1 + config->setHanPin(5); + config->setApPin(4); + config->setLedPin(2); + config->setLedInverted(true); + config->setTempSensorPin(14); + config->setVccMultiplier(1.1); + break; + case 199: // ESP8266 + config->setHanPin(3); + config->setLedPin(2); + config->setLedInverted(true); + break; + case 201: // D32 + config->setHanPin(16); + config->setApPin(4); + config->setLedPin(5); + config->setLedInverted(true); + config->setTempSensorPin(14); + config->setVccPin(35); + config->setVccMultiplier(2.25); + break; + case 202: // Feather ESP32 + config->setHanPin(16); + config->setLedPin(2); + config->setLedInverted(false); + config->setTempSensorPin(14); + break; + case 299: // ESP32 + config->setHanPin(16); + config->setLedPin(2); + config->setLedInverted(true); + config->setTempSensorPin(14); + break; + } + config->setMeterType(server.arg("meterType").toInt()); + config->setWifiSsid(server.arg("wifiSsid").c_str()); + config->setWifiPassword(server.arg("wifiPassword").c_str()); + if(server.hasArg("wifiIpType") && server.arg("wifiIpType").toInt() == 1) { + config->setWifiIp(server.arg("wifiIp").c_str()); + config->setWifiGw(server.arg("wifiGw").c_str()); + config->setWifiSubnet(server.arg("wifiSubnet").c_str()); + config->setWifiDns1(server.arg("wifiDns1").c_str()); + } else { + config->clearWifiIp(); + } + if(server.hasArg("wifiHostname") && !server.arg("wifiHostname").isEmpty()) { + config->setWifiHostname(server.arg("wifiHostname").c_str()); + } + if(config->save()) { + performRestart = true; + server.sendHeader("Location","/restart-wait"); + server.send(303); + } else { + printE("Error saving configuration"); + String html = "

Error saving configuration!

"; + server.send(500, "text/html", html); + } + } +} + void AmsWebServer::handleSave() { String temp; @@ -502,30 +586,30 @@ void AmsWebServer::handleSave() { } if(server.hasArg("wifiConfig") && server.arg("wifiConfig") == "true") { - config->setWifiSsid(server.arg("wifiSsid")); - config->setWifiPassword(server.arg("wifiPassword")); + config->setWifiSsid(server.arg("wifiSsid").c_str()); + config->setWifiPassword(server.arg("wifiPassword").c_str()); if(server.hasArg("wifiIpType") && server.arg("wifiIpType").toInt() == 1) { - config->setWifiIp(server.arg("wifiIp")); - config->setWifiGw(server.arg("wifiGw")); - config->setWifiSubnet(server.arg("wifiSubnet")); - config->setWifiDns1(server.arg("wifiDns1")); - config->setWifiDns2(server.arg("wifiDns2")); + config->setWifiIp(server.arg("wifiIp").c_str()); + config->setWifiGw(server.arg("wifiGw").c_str()); + config->setWifiSubnet(server.arg("wifiSubnet").c_str()); + config->setWifiDns1(server.arg("wifiDns1").c_str()); + config->setWifiDns2(server.arg("wifiDns2").c_str()); } else { config->clearWifiIp(); } - config->setWifiHostname(server.arg("wifiHostname")); + config->setWifiHostname(server.arg("wifiHostname").c_str()); } if(server.hasArg("mqttConfig") && server.arg("mqttConfig") == "true") { if(server.hasArg("mqtt") && server.arg("mqtt") == "true") { - config->setMqttHost(server.arg("mqttHost")); + config->setMqttHost(server.arg("mqttHost").c_str()); int port = server.arg("mqttPort").toInt(); config->setMqttPort(port == 0 ? 1883 : port); - config->setMqttClientId(server.arg("mqttClientId")); - config->setMqttPublishTopic(server.arg("mqttPublishTopic")); - config->setMqttSubscribeTopic(server.arg("mqttSubscribeTopic")); - config->setMqttUser(server.arg("mqttUser")); - config->setMqttPassword(server.arg("mqttPassword")); + config->setMqttClientId(server.arg("mqttClientId").c_str()); + config->setMqttPublishTopic(server.arg("mqttPublishTopic").c_str()); + config->setMqttSubscribeTopic(server.arg("mqttSubscribeTopic").c_str()); + config->setMqttUser(server.arg("mqttUser").c_str()); + config->setMqttPassword(server.arg("mqttPassword").c_str()); config->setMqttPayloadFormat(server.arg("mqttPayloadFormat").toInt()); config->setMqttSsl(server.arg("mqttSsl") == "true"); } else { @@ -536,8 +620,8 @@ void AmsWebServer::handleSave() { if(server.hasArg("authConfig") && server.arg("authConfig") == "true") { config->setAuthSecurity((byte)server.arg("authSecurity").toInt()); if(config->getAuthSecurity() > 0) { - config->setAuthUser(server.arg("authUser")); - config->setAuthPassword(server.arg("authPassword")); + config->setAuthUser(server.arg("authUser").c_str()); + config->setAuthPassword(server.arg("authPassword").c_str()); debugger->setPassword(config->getAuthPassword()); } else { debugger->setPassword(""); @@ -546,6 +630,19 @@ void AmsWebServer::handleSave() { } if(server.hasArg("sysConfig") && server.arg("sysConfig") == "true") { + config->setHanPin(server.arg("hanPin").toInt()); + config->setLedPin(server.arg("ledPin").toInt()); + config->setLedInverted(server.hasArg("ledInverted") && server.arg("ledInverted") == "true"); + config->setLedPinRed(server.arg("ledPinRed").toInt()); + config->setLedPinGreen(server.arg("ledPinGreen").toInt()); + config->setLedPinBlue(server.arg("ledPinBlue").toInt()); + config->setLedRgbInverted(server.hasArg("ledRgbInverted") && server.arg("ledRgbInverted") == "true"); + config->setApPin(server.arg("apPin").toInt()); + config->setTempSensorPin(server.arg("tempSensorPin").toInt()); + config->setVccPin(server.arg("vccPin").toInt()); + config->setVccMultiplier(server.arg("vccMultiplier").toDouble()); + config->setVccBootLimit(server.arg("vccBootLimit").toDouble()); + config->setDebugTelnet(server.hasArg("debugTelnet") && server.arg("debugTelnet") == "true"); config->setDebugSerial(server.hasArg("debugSerial") && server.arg("debugSerial") == "true"); config->setDebugLevel(server.arg("debugLevel").toInt()); @@ -575,6 +672,12 @@ void AmsWebServer::handleSave() { } else { server.sendHeader("Location", String("/"), true); server.send (302, "text/plain", ""); + + hw->setLed(config->getLedPin(), config->isLedInverted()); + hw->setLedRgb(config->getLedPinRed(), config->getLedPinGreen(), config->getLedPinBlue(), config->isLedRgbInverted()); + hw->setTempSensorPin(config->getTempSensorPin()); + hw->setVccPin(config->getVccPin()); + hw->setVccMultiplier(config->getVccMultiplier()); } } else { printE("Error saving configuration"); @@ -592,9 +695,26 @@ void AmsWebServer::configSystemHtml() { String html = String((const __FlashStringHelper*) CONFIGSYSTEM_HTML); html.replace("${version}", VERSION); - if(WiFi.getMode() != WIFI_AP) { - html.replace("boot.css", BOOTSTRAP_URL); - } + #if defined(ESP32) + html.replace("${gpio.max}", "39"); + #else + html.replace("${gpio.max}", "16"); + #endif + + html.replace("${options.han}", getSerialSelectOptions(config->getHanPin())); + + html.replace("${config.ledPin}", config->getLedPin() == 0xFF ? "" : String(config->getLedPin())); + html.replace("${config.ledInverted}", String(config->isLedInverted()) ? "checked" : ""); + html.replace("${config.ledPinRed}", config->getLedPinRed() == 0xFF ? "" : String(config->getLedPinRed())); + html.replace("${config.ledPinGreen}", config->getLedPinGreen() == 0xFF ? "" : String(config->getLedPinGreen())); + html.replace("${config.ledPinBlue}", config->getLedPinBlue() == 0xFF ? "" : String(config->getLedPinBlue())); + html.replace("${config.ledRgbInverted}", String(config->isLedRgbInverted() ? "checked" : "")); + html.replace("${config.apPin}", config->getApPin() == 0xFF ? "" : String(config->getApPin())); + html.replace("${config.tempSensorPin}", config->getTempSensorPin() == 0xFF ? "" : String(config->getTempSensorPin())); + html.replace("${config.vccPin}", config->getVccPin() == 0xFF ? "" : String(config->getVccPin())); + + html.replace("${config.vccMultiplier}", String(config->getVccMultiplier())); + html.replace("${config.vccBootLimit}", String(config->getVccBootLimit())); html.replace("${config.debugTelnet}", config->isDebugTelnet() ? "checked" : ""); html.replace("${config.debugSerial}", config->isDebugSerial() ? "checked" : ""); @@ -610,6 +730,44 @@ void AmsWebServer::configSystemHtml() { server.send(200, "text/html", html); } +String AmsWebServer::getSerialSelectOptions(int selected) { + String gpioOptions; + if(selected == 3) { + gpioOptions += "\n"; + } else { + gpioOptions += "\n"; + } + #if defined(ESP32) + int numGpio = 24; + int gpios[] = {4,5,6,7,8,10,11,12,13,14,15,17,18,19,21,22,23,25,32,33,34,35,36,39}; + if(selected == 9) { + gpioOptions += "\n"; + } else { + gpioOptions += "\n"; + } + if(selected == 16) { + gpioOptions += "\n"; + } else { + gpioOptions += "\n"; + } + #elif defined(ESP8266) + int numGpio = 9; + int gpios[] = {4,5,9,10,12,13,14,15,16}; + #endif + + for(int i = 0; i < numGpio; i++) { + int gpio = gpios[i]; + char buffer [16]; + sprintf(buffer, "%02u", gpio); + if(gpio == selected) { + gpioOptions += "\n"; + } else { + gpioOptions += "\n"; + } + } + return gpioOptions; +} + void AmsWebServer::uploadPost() { server.send(200); } @@ -648,7 +806,13 @@ void AmsWebServer::deleteFile(const char* path) { } } -void AmsWebServer::configSystemUpload() { +void AmsWebServer::firmwareHtml() { + printD("Serving /firmware.html over http..."); + + uploadHtml("CA file", "/firmware", "mqtt"); +} + +void AmsWebServer::firmwareUpload() { HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START) { String filename = upload.filename; @@ -676,7 +840,7 @@ void AmsWebServer::restartWaitHtml() { if(WiFi.getMode() != WIFI_AP) { html.replace("boot.css", BOOTSTRAP_URL); } - if(config->getWifiIp().isEmpty() && WiFi.getMode() != WIFI_AP) { + if(strlen(config->getWifiIp()) == 0 && WiFi.getMode() != WIFI_AP) { html.replace("${ip}", WiFi.localIP().toString()); } else { html.replace("${ip}", config->getWifiIp()); @@ -713,10 +877,6 @@ void AmsWebServer::uploadHtml(const char* label, const char* action, const char* 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}", ""); @@ -737,10 +897,6 @@ void AmsWebServer::deleteHtml(const char* label, const char* action, const char* 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}", ""); @@ -759,7 +915,6 @@ void AmsWebServer::deleteHtml(const char* label, const char* action, const char* 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"); @@ -797,7 +952,6 @@ void AmsWebServer::mqttCaDelete() { void AmsWebServer::mqttCert() { printD("Serving /mqtt-cert.html over http..."); - String html; if(SPIFFS.begin()) { if(SPIFFS.exists(FILE_MQTT_CERT)) { deleteHtml("Certificate", "/mqtt-cert/delete", "mqtt"); @@ -835,7 +989,6 @@ void AmsWebServer::mqttCertDelete() { void AmsWebServer::mqttKey() { printD("Serving /mqtt-key.html over http..."); - String html; if(SPIFFS.begin()) { if(SPIFFS.exists(FILE_MQTT_KEY)) { deleteHtml("Private key", "/mqtt-key/delete", "mqtt"); diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index fdffae32..57ad63c6 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -31,7 +31,7 @@ class AmsWebServer { public: - AmsWebServer(RemoteDebug* Debug); + AmsWebServer(RemoteDebug* Debug, HwTools* hw); void setup(AmsConfiguration* config, MQTTClient* mqtt); void loop(); @@ -40,7 +40,7 @@ public: private: RemoteDebug* debugger; int maxPwr = 0; - HwTools hw; + HwTools* hw; AmsConfiguration* config; AmsData data; MQTTClient* mqtt; @@ -65,10 +65,13 @@ private: void gaugemeterJs(); void dataJson(); + void handleSetup(); void handleSave(); void configSystemHtml(); - void configSystemUpload(); + String getSerialSelectOptions(int selected); + void firmwareHtml(); + void firmwareUpload(); void restartWaitHtml(); void isAliveCheck(); diff --git a/web/boot.css b/web/boot.css index 612782ef..548ffbef 100644 --- a/web/boot.css +++ b/web/boot.css @@ -56,24 +56,9 @@ body { .bg-purple { background-color: var(--purple); } -.text-white-50 { - color: rgba(255,255,255,.5)!important; -} -.mb-0, .my-0 { - margin-bottom: 0!important; -} -.m-2 { - margin: .5rem!important; -} -.mb-2, .my-2 { - margin-bottom: .5rem!important; -} .mt-2, .my-2 { margin-top: .5rem!important; } -.pb-2, .py-2 { - padding-bottom: .5rem!important; -} .p-3 { padding: 1rem!important; } @@ -89,19 +74,9 @@ body { .shadow { box-shadow: 0 .5rem 1rem rgba(0,0,0,.15)!important; } -.align-items-center { - -ms-flex-align: center!important; - align-items: center!important; -} -.border-bottom { - border-bottom: 1px solid #dee2e6!important; -} .rounded { border-radius: .25rem!important; } -div { - display: block; -} .container { width: 100%; padding-right: 15px; @@ -115,15 +90,9 @@ article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { main { display: block; } -.text-white { - color: #fff!important; -} .text-right { text-align: right!important; } -.text-center { - text-align: center!important; -} .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { margin-bottom: .5rem; font-weight: 500; @@ -133,6 +102,9 @@ h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: .5rem; } +.h5, h5 { + font-size: 1.25rem; +} .h6, h6 { font-size: 1rem; } @@ -150,48 +122,14 @@ h1, h2, h3, h4, h5, h6 { padding-right: 15px; padding-left: 15px; } -.col-2 { - -ms-flex: 0 0 16.666667%; - flex: 0 0 16.666667%; - max-width: 16.666667%; -} -.col-3 { - -ms-flex: 0 0 25%; - flex: 0 0 25%; - max-width: 25%; -} -.col-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; -} -.col-5 { - -ms-flex: 0 0 41.666667%; - flex: 0 0 41.666667%; - max-width: 41.666667%; -} .col-6 { -ms-flex: 0 0 50%; flex: 0 0 50%; max-width: 50%; } -.col-8 { - -ms-flex: 0 0 66.666667%; - flex: 0 0 66.666667%; - max-width: 66.666667%; -} -.col-9 { - -ms-flex: 0 0 75%; - flex: 0 0 75%; - max-width: 75%; -} .d-none { display: none!important; } -.d-flex { - display: -ms-flexbox!important; - display: flex!important; -} .flex-row { -ms-flex-direction: row!important; flex-direction: row!important; @@ -231,20 +169,11 @@ a { line-height: 1.5; border-radius: .2rem; } -.btn-outline-secondary { - color: #6c757d; - border-color: #6c757d; -} .btn-primary { color: #fff; background-color: #007bff; border-color: #007bff; } -.btn-danger { - color: #fff; - background-color: #dc3545; - border-color: #dc3545; -} .navbar { position: relative; display: -ms-flexbox; @@ -306,46 +235,6 @@ a { .navbar-dark .navbar-nav .active>.nav-link, .navbar-dark .navbar-nav .nav-link.active, .navbar-dark .navbar-nav .nav-link.show, .navbar-dark .navbar-nav .show>.nav-link { color: #fff; } -.badge { - display: inline-block; - padding: .25em .4em; - font-size: 75%; - font-weight: 700; - line-height: 1; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - 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; -} -.badge-secondary { - color: #fff; - background-color: #6c757d; -} -.badge-success { - color: #fff; - background-color: #28a745; -} -.badge-warning { - color: #212529; - background-color: #ffc107; -} -.badge-danger { - color: #fff; - background-color: #dc3545; -} -.alert { - position: relative; - padding: .75rem 1.25rem; - margin-bottom: 1rem; - border: 1px solid transparent; - border-radius: .25rem; -} -.alert-warning { - color: #856404; - background-color: #fff3cd; - border-color: #ffeeba; -} .form-group { margin-bottom: 1rem; } @@ -397,6 +286,9 @@ input[type="radio"], input[type="checkbox"] { .input-group-append { margin-left: -1px; } +.input-group-prepend { + margin-right: -1px; +} .input-group-append, .input-group-prepend { display: -ms-flexbox; display: flex; @@ -405,6 +297,14 @@ input[type="radio"], input[type="checkbox"] { border-top-left-radius: 0; border-bottom-left-radius: 0; } +.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle), .input-group>.input-group-append:last-child>.input-group-text:not(:last-child), .input-group>.input-group-append:not(:last-child)>.btn, .input-group>.input-group-append:not(:last-child)>.input-group-text, .input-group>.input-group-prepend>.btn, .input-group>.input-group-prepend>.input-group-text { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group>.custom-select:not(:first-child), .input-group>.form-control:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} .input-group-text { display: -ms-flexbox; display: flex; @@ -464,6 +364,11 @@ dl, ol, ul { .container, .container-sm { max-width: 540px; } + .col-sm-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; + } } @media (min-width: 768px) { .container, .container-md, .container-sm { @@ -474,11 +379,6 @@ dl, ol, ul { flex: 0 0 25%; max-width: 25%; } - .col-md-4 { - -ms-flex: 0 0 33.333333%; - flex: 0 0 33.333333%; - max-width: 33.333333%; - } .col-md-6 { -ms-flex: 0 0 50%; flex: 0 0 50%; @@ -510,6 +410,21 @@ dl, ol, ul { .container, .container-lg, .container-md, .container-sm, .container-xl { max-width: 1140px; } + .col-xl-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; + } + .col-xl-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; + } + .col-xl-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; + } } *, ::after, ::before { diff --git a/web/configmeter.html b/web/configmeter.html index 9ea83508..bd396d7a 100644 --- a/web/configmeter.html +++ b/web/configmeter.html @@ -4,7 +4,7 @@ AMS reader - Meter configuration - +
diff --git a/web/configmqtt.html b/web/configmqtt.html index 0fe13b34..f3a2f577 100644 --- a/web/configmqtt.html +++ b/web/configmqtt.html @@ -2,9 +2,9 @@ - AMS reader - WiFi configuration + AMS reader - MQTT configuration - + diff --git a/web/configsystem.html b/web/configsystem.html index fc27bed1..86fc1df3 100644 --- a/web/configsystem.html +++ b/web/configsystem.html @@ -4,7 +4,6 @@ AMS reader - System configuration - @@ -38,10 +37,97 @@ +
!!WARNING!!
Do not change anything here unless you know exactly what you are doing! Changing things here coulds cause the device to stop responding
-
!!WARNING!!
Remote debugging is considered insecure and should not be left enabled when not debugging
+
GPIO settings
+
+
+
+
+ HAN +
+ +
+
+
+
+
+ LED +
+ +
+ +
+
+
+
+
+
+ RGB +
+ + + +
+ +
+
+
+
+
+
+ AP button +
+ +
+
+
+
+
+ Temperature +
+ +
+
+
+
+
+
+
+ Vcc +
+ +
+
+
+
+
+ Multiplier +
+ +
+
+
+
+
+ Boot limit +
+ +
+
+
+
+
+
+
@@ -62,29 +148,10 @@
-
- -
-
- -
-
!!WARNING!!
Do not use this unless you know what you are doing. Uploading the wrong image could cause your device to stop working. Use with extreme caution!
-
-
-
- -
- -
-
-
-
- -
-
+ Upload firmware

@@ -92,6 +159,7 @@ Back
+
diff --git a/web/configweb.html b/web/configweb.html index f65cc211..8c1291d0 100644 --- a/web/configweb.html +++ b/web/configweb.html @@ -2,9 +2,9 @@ - AMS reader - Meter configuration + AMS reader - Web configuration - + diff --git a/web/configwifi.html b/web/configwifi.html index a8fec9e7..2c72a97b 100644 --- a/web/configwifi.html +++ b/web/configwifi.html @@ -4,7 +4,7 @@ AMS reader - WiFi configuration - + @@ -46,19 +46,19 @@
- +
- +
- +
@@ -75,13 +75,13 @@
- +
- +
@@ -89,19 +89,19 @@
- +
- +
- +
diff --git a/web/delete.html b/web/delete.html index 07cffe54..62ccc29a 100644 --- a/web/delete.html +++ b/web/delete.html @@ -2,9 +2,9 @@ - AMS reader - Meter configuration + AMS reader - Delete ${file.label} - +
diff --git a/web/gaugemeter.js b/web/gaugemeter.js index fc4e5b9e..0e9b54fb 100644 --- a/web/gaugemeter.js +++ b/web/gaugemeter.js @@ -58,7 +58,7 @@ "White" === option.theme && (t = "#fff"), "Black" === option.theme && (t = "#000"), t; - } + }; /* The label below gauge. */ function createLabel(t, a) { if(t.children("b").length === 0){ @@ -67,7 +67,7 @@ color: option.label_color }); } - } + }; /* Prepend and append text, the gauge text or percentage value. */ function createSpanTag(t) { var fgcolor = ""; @@ -90,7 +90,7 @@ "font-size": option.text_size * option.size + "px", color: fgcolor }); - } + }; /* Get data attributes as options from div tag. Fall back to defaults when not exists. */ function getDataAttr(t) { $.each(dataAttr, function (index, element) { @@ -116,10 +116,10 @@ option[element] = parseFloat(option[element]); } }); - } + }; /* Draws the gauge. */ function drawGauge(a) { - if(M < 0) M = 0; + if(M < 0) M = 0; if(M > 100) M = 100; var lw = option.width < 1 || isNaN(option.width) ? option.size / 20 : option.width; g.clearRect(0, 0, b.width, b.height); @@ -141,7 +141,7 @@ c > M && (M += z, requestAnimationFrame(function(){ drawGauge(Math.min(M, c) / 100); }, p)); - } + }; $(this).attr("data-id", $(this).attr("id")); var r, diff --git a/web/index.html b/web/index.html index 0a903d21..23b87174 100644 --- a/web/index.html +++ b/web/index.html @@ -4,7 +4,7 @@ AMS reader - + diff --git a/web/index.js b/web/index.js index b4e51c59..d557b968 100644 --- a/web/index.js +++ b/web/index.js @@ -1,18 +1,22 @@ +var im, em; $(function() { - -}); -var im = $("#importMeter") -im.gaugeMeter({ - percent: 0, - text: "-", - append: "W" -}); - -var em = $("#exportMeter") -em.gaugeMeter({ - percent: 0, - text: "-", - append: "W" + im = $("#importMeter"); + if(im && im.gaugeMeter) { + im.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + } + + em = $("#exportMeter"); + if(em && em.gaugeMeter) { + em.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + } }); var setStatus = function(id, status) { @@ -31,9 +35,11 @@ var fetch = function() { timeout: 10000, dataType: 'json', }).done(function(json) { - $(".SimpleMeter").hide(); - im.show(); - em.show(); + if(im && em) { + $(".SimpleMeter").hide(); + im.show(); + em.show(); + } for(var id in json) { var str = json[id]; @@ -89,11 +95,13 @@ var fetch = function() { p_append = "kW"; } } - im.gaugeMeter({ - percent: p_pct, - text: p, - append: p_append - }); + if(im && im.gaugeMeter) { + im.gaugeMeter({ + percent: p_pct, + text: p, + append: p_append + }); + } var po = 0; var po_pct = parseInt(json.po_pct); @@ -105,11 +113,13 @@ var fetch = function() { po_append = "kW"; } } - em.gaugeMeter({ - percent: po_pct, - text: po, - append: po_append - }); + if(em && em.gaugeMeter) { + em.gaugeMeter({ + percent: po_pct, + text: po, + append: po_append + }); + } for(var id in json.data) { var str = json.data[id]; @@ -122,33 +132,41 @@ var fetch = function() { } } } else { + if(im && im.gaugeMeter) { + im.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + } + + if(em && em.gaugeMeter) { + em.gaugeMeter({ + percent: 0, + text: "-", + append: "W" + }); + } + } + setTimeout(fetch, interval); + }).fail(function() { + setTimeout(fetch, interval*4); + + if(im && im.gaugeMeter) { im.gaugeMeter({ percent: 0, text: "-", append: "W" }); + } + if(em && em.gaugeMeter) { 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"); diff --git a/web/restartwait.html b/web/restartwait.html index 605f6958..4fc5eaed 100644 --- a/web/restartwait.html +++ b/web/restartwait.html @@ -5,31 +5,11 @@ AMS reader - Restarting, please wait -
diff --git a/web/setup.html b/web/setup.html new file mode 100644 index 00000000..99e8b34a --- /dev/null +++ b/web/setup.html @@ -0,0 +1,136 @@ + + + + + AMS reader - Setup + + + + +
+ +
+
+
+
+
Hardware
+ +
+
+
Meter
+ +
+
+
+
+
WiFi
+
+
+
+
+ SSID +
+ +
+
+
+
+
+ PSK +
+ +
+
+
+
+
+ Hostname +
+ +
+
+
+ +
+
+
+
+
+
+ IP +
+ +
+
+
+
+
+ Subnet +
+ +
+
+
+
+
+ Gateway +
+ +
+
+
+
+
+ DNS +
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + diff --git a/web/upload.html b/web/upload.html index caf45909..da49f598 100644 --- a/web/upload.html +++ b/web/upload.html @@ -2,7 +2,7 @@ - AMS reader - Meter configuration + AMS reader - Upload ${file.label}