diff --git a/.gitignore b/.gitignore index 7bed7c25..35bfdc73 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ platformio-user.ini /src/web/root /src/AmsToMqttBridge.ino.cpp /test +/web/test.html diff --git a/lib/HanReader/library.properties b/lib/HanReader/library.properties index b5fa3585..f3ee65d9 100644 --- a/lib/HanReader/library.properties +++ b/lib/HanReader/library.properties @@ -7,4 +7,4 @@ paragraph=HAN support category=Sensors url=https://github.com/roarfred/AmsToMqttBridge architectures=* -depends=Timezone +depends=Timezone,mbedtls diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index 4ac83169..5726cc45 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -309,6 +309,8 @@ void AmsConfiguration::clearMeter() { setDistributionSystem(0); setMainFuse(0); setProductionCapacity(0); + setMeterEncryptionKey(nullptr); + setMeterAuthenticationKey(nullptr); setSubstituteMissing(false); setSendUnknown(false); } @@ -500,6 +502,16 @@ void AmsConfiguration::setTempSensorPin(uint8_t tempSensorPin) { } } +uint8_t AmsConfiguration::getTempAnalogSensorPin() { + return config.tempAnalogSensorPin; +} + +void AmsConfiguration::setTempAnalogSensorPin(uint8_t tempAnalogSensorPin) { + if(!pinUsed(tempAnalogSensorPin)) { + config.tempAnalogSensorPin = tempAnalogSensorPin; + } +} + uint8_t AmsConfiguration::getVccPin() { return config.vccPin; } @@ -544,12 +556,88 @@ void AmsConfiguration::ackDomoChange() { domoChanged = false; } +bool AmsConfiguration::isMdnsEnable() { + return config.mDnsEnable; +} + +void AmsConfiguration::setMdnsEnable(bool mdnsEnable) { + config.mDnsEnable = mdnsEnable; +} + +bool AmsConfiguration::isNtpEnable() { + return config.ntpEnable; +} + +void AmsConfiguration::setNtpEnable(bool ntpEnable) { + if(config.ntpEnable != ntpEnable) { + if(!ntpEnable) { + wifiChanged = true; + } else { + ntpChanged = true; + } + config.ntpEnable = ntpEnable; + } +} + +bool AmsConfiguration::isNtpDhcp() { + return config.ntpDhcp; +} + +void AmsConfiguration::setNtpDhcp(bool ntpDhcp) { + ntpChanged |= config.ntpDhcp != ntpDhcp; + config.ntpDhcp = ntpDhcp; +} + +int32_t AmsConfiguration::getNtpOffset() { + return config.ntpOffset * 10; +} + +void AmsConfiguration::setNtpOffset(uint32_t ntpOffset) { + ntpChanged |= config.ntpOffset != ntpOffset/10; + config.ntpOffset = ntpOffset == 0 ? 0 : ntpOffset / 10; +} + +int32_t AmsConfiguration::getNtpSummerOffset() { + return config.ntpSummerOffset * 10; +} + +void AmsConfiguration::setNtpSummerOffset(uint32_t ntpSummerOffset) { + ntpChanged |= config.ntpSummerOffset != ntpSummerOffset/10; + config.ntpSummerOffset = ntpSummerOffset == 0 ? 0 : ntpSummerOffset / 10; +} + +char* AmsConfiguration::getNtpServer() { + return config.ntpServer; +} + +void AmsConfiguration::setNtpServer(const char* ntpServer) { + strcpy(config.ntpServer, ntpServer); +} + +bool AmsConfiguration::isNtpChanged() { + return ntpChanged; +} + +void AmsConfiguration::ackNtpChange() { + ntpChanged = false; +} + +void AmsConfiguration::clearNtp() { + setNtpEnable(true); + setNtpDhcp(true); + setNtpOffset(3600); + setNtpSummerOffset(3600); + setNtpServer("pool.ntp.org"); +} + + void AmsConfiguration::clear() { clearMeter(); clearWifi(); clearMqtt(); clearAuth(); clearDomo(); + clearNtp(); int address = EEPROM_CONFIG_ADDRESS; @@ -863,6 +951,7 @@ void AmsConfiguration::print(Print* debugger) debugger->printf("Vcc pin: %i\r\n", this->getVccPin()); debugger->printf("Vcc multiplier: %f\r\n", this->getVccMultiplier()); + debugger->printf("Vcc offset: %f\r\n", this->getVccOffset()); debugger->printf("Vcc boot limit: %f\r\n", this->getVccBootLimit()); if(this->getDomoELIDX() > 0) { @@ -873,5 +962,13 @@ void AmsConfiguration::print(Print* debugger) debugger->printf("Domoticz CL1IDX: %i\r\n", this->getDomoCL1IDX()); } + debugger->printf("NTP: %s\r\n", this->isNtpEnable() ? "Yes" : "No"); + if(this->isNtpEnable()) { + debugger->printf("NTP offset: %i\r\n", this->getNtpOffset()); + debugger->printf("NTP summer offset: %i\r\n", this->getNtpSummerOffset()); + debugger->printf("NTP server: %s\r\n", this->getNtpServer()); + debugger->printf("NTP DHCP: %s\r\n", this->isNtpDhcp() ? "Yes" : "No"); + } + debugger->println("-----------------------------------------------"); } diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index 6703c5bd..3c320076 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -58,6 +58,17 @@ struct ConfigObject { uint16_t domoVL2IDX; uint16_t domoVL3IDX; uint16_t domoCL1IDX; + + bool mDnsEnable; + bool ntpEnable; + bool ntpDhcp; + int16_t ntpOffset; + int16_t ntpSummerOffset; + char ntpServer[64]; + + uint8_t tempAnalogSensorPin; + int8_t tempSensorInternal; // -128 = disabled, -1 = analog, 0-127 = digital sensor index + uint8_t tempSensorCount; }; struct ConfigObject82 { @@ -228,6 +239,8 @@ public: uint8_t getTempSensorPin(); void setTempSensorPin(uint8_t tempSensorPin); + uint8_t getTempAnalogSensorPin(); + void setTempAnalogSensorPin(uint8_t tempSensorPin); uint8_t getVccPin(); void setVccPin(uint8_t vccPin); double getVccOffset(); @@ -254,6 +267,24 @@ public: bool isDomoChanged(); void ackDomoChange(); + bool isMdnsEnable(); + void setMdnsEnable(bool mdnsEnable); + + bool isNtpEnable(); + void setNtpEnable(bool ntpEnable); + bool isNtpDhcp(); + void setNtpDhcp(bool ntpDhcp); + int32_t getNtpOffset(); + void setNtpOffset(uint32_t ntpOffset); + int32_t getNtpSummerOffset(); + void setNtpSummerOffset(uint32_t ntpSummerOffset); + char* getNtpServer(); + void setNtpServer(const char* ntpServer); + void clearNtp(); + + bool isNtpChanged(); + void ackNtpChange(); + void clear(); protected: @@ -311,12 +342,21 @@ private: 0, // VL1IDX 0, // VL2IDX 0, // VL3IDX - 0 // CL1IDX - // 822 bytes + 0, // CL1IDX + true, // mDNS + true, // NTP + true, // NTP DHCP + 360, // Timezone (*10) + 360, // Summertime offset (*10) + "pool.ntp.org", // NTP server + 0xFF, // Analog temp sensor + 0xFF, // Internal temp sensor + 0, // Temp sensor count + // 900 bytes }; - bool wifiChanged, mqttChanged, meterChanged = true, domoChanged; + bool wifiChanged, mqttChanged, meterChanged = true, domoChanged, ntpChanged; - const int EEPROM_SIZE = 1024; // Config size + 4 bytes for config version + const int EEPROM_SIZE = 904; // Config size + 4 bytes for config version const int EEPROM_CHECK_SUM = 83; // Used to check if config is stored. Change if structure changes const int EEPROM_CONFIG_ADDRESS = 0; diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index f16db1c4..d521a8d5 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -22,19 +22,7 @@ #include #include #include -// Tz.h does not exist for esp32, need to include time.h, timezone offsets to be given given in sec. -#define NTP_SERVER "pool.ntp.org" // put your local NTP server here -#if defined(ESP8266) -#include -#define MYTZ TZ_Europe_Oslo -#elif defined(ESP32) -#include -#define TZ 1 // (utc+) TZ in hours -#define DST_MN 60 // use 60mn for summer time in some countries -#define GMT_OFFSET_SEC 3600 * TZ // Do not change here... -#define DAYLIGHT_OFFSET_SEC 60 * DST_MN // Do not change here... -#endif - +#include #if defined(ESP8266) ADC_MODE(ADC_VCC); @@ -257,13 +245,11 @@ void setup() { if(config.hasConfig()) { if(Debug.isActive(RemoteDebug::INFO)) config.print(&Debug); + if(config.isNtpEnable()) { + configTime(config.getNtpOffset(), config.getNtpSummerOffset(), config.getNtpServer()); + sntp_servermode_dhcp(config.isNtpDhcp() ? 1 : 0); + } WiFi_connect(); -#if defined(ESP8266) - configTime(MYTZ, NTP_SERVER); -#elif defined(ESP32) - configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER); -#endif - //sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default) } else { if(Debug.isActive(RemoteDebug::INFO)) { debugI("No configuration, booting AP"); @@ -274,6 +260,7 @@ void setup() { ws.setup(&config, &mqtt); } + int buttonTimer = 0; bool buttonActive = false; unsigned long longPressTime = 5000; @@ -350,6 +337,13 @@ void loop() { MDNS.addService("http", "tcp", 80); } } + if(config.isNtpChanged()) { + if(config.isNtpEnable()) { + configTime(config.getNtpOffset(), config.getNtpSummerOffset(), config.getNtpServer()); + sntp_servermode_dhcp(config.isNtpDhcp() ? 1 : 0); + } + config.ackNtpChange(); + } #if defined ESP8266 MDNS.update(); #endif diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 4e62313b..8103305d 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -12,7 +12,9 @@ #include "root/configmqtt_html.h" #include "root/configweb_html.h" #include "root/configdomoticz_html.h" -#include "root/configsystem_html.h" +#include "root/ntp_html.h" +#include "root/gpio_html.h" +#include "root/debugging_html.h" #include "root/restartwait_html.h" #include "root/boot_css.h" #include "root/gaugemeter_js.h" @@ -47,7 +49,10 @@ 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("/ntp", HTTP_GET, std::bind(&AmsWebServer::configNtpHtml, this)); + server.on("/gpio", HTTP_GET, std::bind(&AmsWebServer::configGpioHtml, this)); + server.on("/debugging", HTTP_GET, std::bind(&AmsWebServer::configDebugHtml, 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("/upgrade", HTTP_GET, std::bind(&AmsWebServer::firmwareDownload, this)); @@ -767,7 +772,7 @@ void AmsWebServer::handleSave() { } } - if(server.hasArg("sysConfig") && server.arg("sysConfig") == "true") { + if(server.hasArg("gpioConfig") && server.arg("gpioConfig") == "true") { // Unset all pins to avoid conflicts if GPIO have been swapped between pins config->setLedPin(0xFF); config->setLedPinRed(0xFF); @@ -775,6 +780,7 @@ void AmsWebServer::handleSave() { config->setLedPinBlue(0xFF); config->setApPin(0xFF); config->setTempSensorPin(0xFF); + config->setTempAnalogSensorPin(0xFF); config->setVccPin(0xFF); config->setHanPin(server.hasArg("hanPin") && !server.arg("hanPin").isEmpty() ? server.arg("hanPin").toInt() : 3); @@ -786,11 +792,14 @@ void AmsWebServer::handleSave() { config->setLedRgbInverted(server.hasArg("ledRgbInverted") && server.arg("ledRgbInverted") == "true"); config->setApPin(server.hasArg("apPin") && !server.arg("apPin").isEmpty() ? server.arg("apPin").toInt() : 0xFF); config->setTempSensorPin(server.hasArg("tempSensorPin") && !server.arg("tempSensorPin").isEmpty() ?server.arg("tempSensorPin").toInt() : 0xFF); + config->setTempAnalogSensorPin(server.hasArg("tempAnalogSensorPin") && !server.arg("tempAnalogSensorPin").isEmpty() ?server.arg("tempAnalogSensorPin").toInt() : 0xFF); config->setVccPin(server.hasArg("vccPin") && !server.arg("vccPin").isEmpty() ? server.arg("vccPin").toInt() : 0xFF); config->setVccOffset(server.hasArg("vccOffset") && !server.arg("vccOffset").isEmpty() ? server.arg("vccOffset").toDouble() : 0.0); config->setVccMultiplier(server.hasArg("vccMultiplier") && !server.arg("vccMultiplier").isEmpty() ? server.arg("vccMultiplier").toDouble() : 1.0); config->setVccBootLimit(server.hasArg("vccBootLimit") && !server.arg("vccBootLimit").isEmpty() ? server.arg("vccBootLimit").toDouble() : 0.0); + } + if(server.hasArg("debugConfig") && server.arg("debugConfig") == "true") { config->setDebugTelnet(server.hasArg("debugTelnet") && server.arg("debugTelnet") == "true"); config->setDebugSerial(server.hasArg("debugSerial") && server.arg("debugSerial") == "true"); config->setDebugLevel(server.arg("debugLevel").toInt()); @@ -808,6 +817,24 @@ void AmsWebServer::handleSave() { } } + if(server.hasArg("ntpConfig") && server.arg("ntpConfig") == "true") { + config->setNtpEnable(server.hasArg("ntpEnable") && server.arg("ntpEnable") == "true"); + config->setNtpDhcp(server.hasArg("ntpDhcp") && server.arg("ntpDhcp") == "true"); + if(server.hasArg("ntpOffset") && !server.arg("ntpOffset").isEmpty()) { + int offset = server.arg("ntpOffset").toInt(); + config->setNtpOffset(offset); + if(server.hasArg("ntpSummerOffset") && !server.arg("ntpSummerOffset").isEmpty()) { + int summerOffset = server.arg("ntpSummerOffset").toInt(); + config->setNtpSummerOffset(summerOffset); + } else { + config->setNtpSummerOffset(0); + } + } else { + config->setNtpOffset(0); + } + config->setNtpServer(server.arg("ntpServer").c_str()); + } + printI("Saving configuration now..."); if (debugger->isActive(RemoteDebug::DEBUG)) config->print(debugger); @@ -835,13 +862,43 @@ void AmsWebServer::handleSave() { } } -void AmsWebServer::configSystemHtml() { - printD("Serving /config-system.html over http..."); +void AmsWebServer::configNtpHtml() { + printD("Serving /ntp.html over http..."); if(!checkSecurity(1)) return; - String html = String((const __FlashStringHelper*) CONFIGSYSTEM_HTML); + String html = String((const __FlashStringHelper*) NTP_HTML); + + html.replace("${config.ntpEnable}", config->isNtpEnable() ? "checked" : ""); + + for(int i = (3600*-13); i<(3600*15); i+=3600) { + html.replace("${config.ntpOffset" + String(i) + "}", config->getNtpOffset() == i ? "selected" : ""); + } + + for(int i = 0; i<(3600*3); i+=3600) { + html.replace("${config.ntpSummerOffset" + String(i) + "}", config->getNtpSummerOffset() == i ? "selected" : ""); + } + + html.replace("${config.ntpServer}", config->getNtpServer()); + html.replace("${config.ntpDhcp}", config->isNtpDhcp() ? "checked" : ""); + + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); + + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); +} + +void AmsWebServer::configGpioHtml() { + printD("Serving /gpio.html over http..."); + + if(!checkSecurity(1)) + return; + + String html = String((const __FlashStringHelper*) GPIO_HTML); #if defined(ESP32) html.replace("${gpio.max}", "39"); @@ -865,6 +922,23 @@ void AmsWebServer::configSystemHtml() { html.replace("${config.vccMultiplier}", config->getVccMultiplier() > 0 ? String(config->getVccMultiplier(), 2) : ""); html.replace("${config.vccBootLimit}", config->getVccBootLimit() > 0.0 ? String(config->getVccBootLimit(), 1) : ""); + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); + + server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); + server.send_P(200, "text/html", HEAD_HTML); + server.sendContent(html); + server.sendContent_P(FOOT_HTML); +} + +void AmsWebServer::configDebugHtml() { + printD("Serving /debugging.html over http..."); + + if(!checkSecurity(1)) + return; + + String html = String((const __FlashStringHelper*) DEBUGGING_HTML); + html.replace("${config.debugTelnet}", config->isDebugTelnet() ? "checked" : ""); html.replace("${config.debugSerial}", config->isDebugSerial() ? "checked" : ""); html.replace("${config.debugLevel}", String(config->getDebugLevel())); diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index 90464039..7d7c83ca 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -65,6 +65,9 @@ private: void configMqttHtml(); void configWebHtml(); void configDomoticzHtml(); + void configNtpHtml(); + void configGpioHtml(); + void configDebugHtml(); void bootCss(); void gaugemeterJs(); void githubSvg(); @@ -73,7 +76,6 @@ private: void handleSetup(); void handleSave(); - void configSystemHtml(); String getSerialSelectOptions(int selected); void firmwareHtml(); void firmwareUpload(); diff --git a/web/application.js b/web/application.js index 2a17d845..0ee5866d 100644 --- a/web/application.js +++ b/web/application.js @@ -99,6 +99,13 @@ $(function() { $(this).next('.custom-file-label').html(fileName); }) + // For NTP + $('#ntpEnable').on('change', function() { + var inputs = $('.ntp-config'); + inputs.prop('disabled', !$(this).is(':checked')); + }); + $('#ntpEnable').trigger('change'); + switch(window.location.pathname) { case '/config-meter': $('#config-meter-link').addClass('active'); @@ -114,9 +121,9 @@ $(function() { $('#config-mqtt-link').addClass('active'); break; case '/config-web': - $('#config-web-link').addClass('active'); - break; - case '/config-system': + case '/ntp': + case '/gpio': + case '/debugging': case '/firmware': case '/reset': $('#config-system-link').addClass('active'); diff --git a/web/configsystem.html b/web/configsystem.html deleted file mode 100644 index fd3505f2..00000000 --- a/web/configsystem.html +++ /dev/null @@ -1,142 +0,0 @@ -
!!WARNING!!
Do not change anything here unless you know exactly what you are doing! Changing things here could cause the device to stop responding
-
- -
-
GPIO settings
-
-
-
-
- HAN -
- -
-
-
-
-
- LED -
- -
- -
-
-
-
-
-
- RGB -
- - - -
- -
-
-
-
-
-
- AP button -
- -
-
-
-
-
- Temperature -
- -
-
-
-
-
-
-
- Vcc -
- -
-
-
-
-
- Offset -
- -
-
-
-
-
- Multiplier -
- -
-
-
-
-
- Boot limit -
- -
-
-
-
-
-
-
-
Debugger
-
-
- -
-
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
-
- Back -
-
- -
-
-
diff --git a/web/debugging.html b/web/debugging.html new file mode 100644 index 00000000..b0f84f6d --- /dev/null +++ b/web/debugging.html @@ -0,0 +1,37 @@ +
!!NOTE!!
Telnet debugging is not considered safe and should be switched off when not in use
+
+ +
+
Debugging
+
+
+ +
+
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+ Back +
+
+ +
+
+
diff --git a/web/gpio.html b/web/gpio.html new file mode 100644 index 00000000..4ee95616 --- /dev/null +++ b/web/gpio.html @@ -0,0 +1,92 @@ +
!!WARNING!!
Do not change anything here unless you know exactly what you are doing! Changing things here could cause the device to stop responding
+
+ +
+
GPIO settings
+
+
+
+ HAN +
+ +
+
+
+ LED +
+ +
+ +
+
+
+
+ RGB +
+ + + +
+ +
+
+
+
+ AP button +
+ +
+
+
+ Temperature +
+ +
+
+
+ Analog temp +
+ +
+
+
+ Vcc +
+ +
+
+
+ Multiplier +
+ +
+
+
+ Offset +
+ +
+
+
+ Boot limit +
+ +
+
+
+
+
+
+ Back +
+
+ +
+
+
diff --git a/web/head.html b/web/head.html index 15ce97fd..05b0d154 100644 --- a/web/head.html +++ b/web/head.html @@ -53,6 +53,9 @@ diff --git a/web/ntp.html b/web/ntp.html new file mode 100644 index 00000000..5428708d --- /dev/null +++ b/web/ntp.html @@ -0,0 +1,54 @@ +
+ +
+
NTP
+ +
+
+
+
+ Timezone +
+ +
+
+
+
+
+ Summertime offset +
+ +
+
+
+
+
+ Server +
+ +
+
+
+
+ +
+
+
+
+
+
+
+ Back +
+
+ +
+
+