diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1a0a1a6..158595c8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,8 @@ on: paths: - src/** - lib/** + - scripts/** + - web/** - platformio.ini branches: - master diff --git a/.gitignore b/.gitignore index 63ae6684..8f43c6fb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ .pio platformio-user.ini /src/version.h +/src/web/root +/src/AmsToMqttBridge.ino.cpp diff --git a/lib/HanConfigAp/src/HanConfigAp.cpp b/lib/HanConfigAp/src/HanConfigAp.cpp index daa09dda..0db20c8d 100644 --- a/lib/HanConfigAp/src/HanConfigAp.cpp +++ b/lib/HanConfigAp/src/HanConfigAp.cpp @@ -3,15 +3,16 @@ Stream* HanConfigAp::debugger; bool HanConfigAp::hasConfig() { - return config.hasConfig(); + return config->hasConfig(); } -void HanConfigAp::setup(int accessPointButtonPin, Stream* debugger) +void HanConfigAp::setup(int accessPointButtonPin, configuration* config, Stream* debugger) { this->debugger = debugger; + this->config = config; // Test if we're missing configuration - if (!config.hasConfig()) + if (!config->hasConfig()) { print("No config. We're booting as AP. Look for SSID "); println(this->AP_SSID); @@ -20,8 +21,7 @@ void HanConfigAp::setup(int accessPointButtonPin, Stream* debugger) else { // Load the configuration - config.load(); - if (this->debugger) config.print(this->debugger); + if (this->debugger) config->print(this->debugger); if (accessPointButtonPin != INVALID_BUTTON_PIN) { diff --git a/lib/HanConfigAp/src/HanConfigAp.h b/lib/HanConfigAp/src/HanConfigAp.h index e62dce16..401b8656 100644 --- a/lib/HanConfigAp/src/HanConfigAp.h +++ b/lib/HanConfigAp/src/HanConfigAp.h @@ -24,15 +24,16 @@ class HanConfigAp { public: - void setup(int accessPointButtonPin, Stream* debugger); + void setup(int accessPointButtonPin, configuration* config, Stream* debugger); bool loop(); bool hasConfig(); - configuration config; bool isActivated = false; private: const char* AP_SSID = "AMS2MQTT"; + configuration* config; + // DNS server const byte DNS_PORT = 53; DNSServer dnsServer; diff --git a/lib/HanConfigAp/src/configuration.cpp b/lib/HanConfigAp/src/configuration.cpp index 0a14ae95..3c14091c 100644 --- a/lib/HanConfigAp/src/configuration.cpp +++ b/lib/HanConfigAp/src/configuration.cpp @@ -24,11 +24,18 @@ bool configuration::save() address += saveString(address, ssid); address += saveString(address, ssidPassword); address += saveByte(address, meterType); - address += saveString(address, mqtt); - address += saveInt(address, mqttPort); - address += saveString(address, mqttClientID); - address += saveString(address, mqttPublishTopic); - address += saveString(address, mqttSubscribeTopic); + + + if(mqttHost) { + address += saveBool(address, true); + address += saveString(address, mqttHost); + address += saveInt(address, mqttPort); + address += saveString(address, mqttClientID); + address += saveString(address, mqttPublishTopic); + address += saveString(address, mqttSubscribeTopic); + } else { + address += saveBool(address, false); + } if (isSecure()) { address += saveBool(address, true); @@ -46,6 +53,7 @@ bool configuration::save() } address += saveInt(address, fuseSize); + address += saveInt(address, distSys); bool success = EEPROM.commit(); EEPROM.end(); @@ -59,13 +67,13 @@ bool configuration::load() int address = EEPROM_CONFIG_ADDRESS; bool success = false; - ssid = (char*)String("").c_str(); - ssidPassword = (char*)String("").c_str(); + ssid = 0; + ssidPassword = 0; meterType = (byte)0; - mqtt = (char*)String("").c_str(); - mqttClientID = (char*)String("").c_str(); - mqttPublishTopic = (char*)String("").c_str(); - mqttSubscribeTopic = (char*)String("").c_str(); + mqttHost = 0; + mqttClientID = 0; + mqttPublishTopic = 0; + mqttSubscribeTopic = 0; mqttUser = 0; mqttPass = 0; mqttPort = 1883; @@ -73,25 +81,30 @@ bool configuration::load() authUser = 0; authPass = 0; fuseSize = 0; + distSys = 0; EEPROM.begin(EEPROM_SIZE); int cs = EEPROM.read(address); - if (cs >= 71) + if (cs == EEPROM_CHECK_SUM) { address++; address += readString(address, &ssid); address += readString(address, &ssidPassword); address += readByte(address, &meterType); - address += readString(address, &mqtt); - address += readInt(address, &mqttPort); - address += readString(address, &mqttClientID); - address += readString(address, &mqttPublishTopic); - address += readString(address, &mqttSubscribeTopic); + + bool mqtt = false; + address += readBool(address, &mqtt); + if(mqtt) { + address += readString(address, &mqttHost); + address += readInt(address, &mqttPort); + address += readString(address, &mqttClientID); + address += readString(address, &mqttPublishTopic); + address += readString(address, &mqttSubscribeTopic); + } bool secure = false; address += readBool(address, &secure); - if (secure) { address += readString(address, &mqttUser); @@ -103,9 +116,6 @@ bool configuration::load() mqttPass = 0; } - success = true; - } - if(cs >= 72) { address += readByte(address, &authSecurity); if (authSecurity > 0) { address += readString(address, &authUser); @@ -114,9 +124,11 @@ bool configuration::load() authUser = 0; authPass = 0; } - } - if(cs >= 73) { + address += readInt(address, &fuseSize); + address += readByte(address, &distSys); + + success = true; } EEPROM.end(); return success; @@ -177,11 +189,13 @@ void configuration::print(Stream* debugger) debugger->printf("ssid: %s\r\n", this->ssid); debugger->printf("ssidPassword: %s\r\n", this->ssidPassword); debugger->printf("meterType: %i\r\n", this->meterType); - debugger->printf("mqtt: %s\r\n", this->mqtt); - debugger->printf("mqttPort: %i\r\n", this->mqttPort); - debugger->printf("mqttClientID: %s\r\n", this->mqttClientID); - debugger->printf("mqttPublishTopic: %s\r\n", this->mqttPublishTopic); - debugger->printf("mqttSubscribeTopic: %s\r\n", this->mqttSubscribeTopic); + if(this->mqttHost) { + debugger->printf("mqttHost: %s\r\n", this->mqttHost); + debugger->printf("mqttPort: %i\r\n", this->mqttPort); + debugger->printf("mqttClientID: %s\r\n", this->mqttClientID); + debugger->printf("mqttPublishTopic: %s\r\n", this->mqttPublishTopic); + debugger->printf("mqttSubscribeTopic: %s\r\n", this->mqttSubscribeTopic); + } if (this->isSecure()) { @@ -197,6 +211,7 @@ void configuration::print(Stream* debugger) debugger->printf("authPass: %s\r\n", this->authPass); } debugger->printf("fuseSize: %i\r\n", this->fuseSize); + debugger->printf("distSys: %i\r\n", this->distSys); debugger->println("-----------------------------------------------"); } @@ -236,7 +251,7 @@ int configuration::readString(int pAddress, char* pString[]) int configuration::saveString(int pAddress, char* pString) { int address = 0; - int length = strlen(pString) + 1; + int length = pString ? strlen(pString) + 1 : 0; EEPROM.put(pAddress + address, length); address++; diff --git a/lib/HanConfigAp/src/configuration.h b/lib/HanConfigAp/src/configuration.h index 68a142ba..13640773 100644 --- a/lib/HanConfigAp/src/configuration.h +++ b/lib/HanConfigAp/src/configuration.h @@ -16,7 +16,7 @@ class configuration { public: char* ssid; char* ssidPassword; - char* mqtt; + char* mqttHost; int mqttPort; char* mqttClientID; char* mqttPublishTopic; @@ -30,6 +30,7 @@ public: char* authPass; int fuseSize; + byte distSys; bool hasConfig(); bool isSecure(); @@ -41,7 +42,7 @@ protected: private: const int EEPROM_SIZE = 512; - const byte EEPROM_CHECK_SUM = 73; // Used to check if config is stored. Change if structure changes + const byte EEPROM_CHECK_SUM = 75; // Used to check if config is stored. Change if structure changes const int EEPROM_CONFIG_ADDRESS = 0; int saveString(int pAddress, char* pString); diff --git a/platformio.ini b/platformio.ini index 1b452904..40f5cfde 100755 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,8 @@ build_flags = -D HAS_DALLAS_TEMP_SENSOR=0 -D IS_CUSTOM_AMS_BOARD=0 extra_scripts = - pre:addversion.py + pre:scripts/addversion.py + scripts/makeweb.py [env:hw1esp12e] platform = espressif8266 @@ -26,7 +27,8 @@ build_flags = -D HAS_DALLAS_TEMP_SENSOR=1 -D IS_CUSTOM_AMS_BOARD=1 extra_scripts = - pre:addversion.py + pre:scripts/addversion.py + scripts/makeweb.py [env:featheresp32] platform = espressif32 @@ -37,4 +39,5 @@ build_flags = -D HAS_DALLAS_TEMP_SENSOR=0 -D IS_CUSTOM_AMS_BOARD=0 extra_scripts = - pre:addversion.py + pre:scripts/addversion.py + scripts/makeweb.py diff --git a/addversion.py b/scripts/addversion.py similarity index 100% rename from addversion.py rename to scripts/addversion.py diff --git a/scripts/makeweb.py b/scripts/makeweb.py new file mode 100644 index 00000000..8158478b --- /dev/null +++ b/scripts/makeweb.py @@ -0,0 +1,30 @@ +import os +import re +import shutil + +webroot = "web" +srcroot = "src/web/root" + + +if os.path.exists(srcroot): + shutil.rmtree(srcroot) + os.mkdir(srcroot) +else: + os.mkdir(srcroot) + +for filename in os.listdir(webroot): + basename = re.sub("[^0-9a-zA-Z]+", "_", filename) + + srcfile = webroot + "/" + filename + dstfile = srcroot + "/" + basename + ".h" + + varname = basename.upper() + + 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("\n)==\"==\";\n") \ No newline at end of file diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 9f0c56e7..1545f374 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -20,7 +20,7 @@ ADC_MODE(ADC_VCC); #include #endif -#include "AmsWebServer.h" +#include "web/AmsWebServer.h" #include "HanConfigAp.h" #include "HanReader.h" #include "HanToJson.h" @@ -31,6 +31,10 @@ ADC_MODE(ADC_VCC); #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 +#elif defined(ARDUINO_LOLIN_D32) +#define LED_PIN 5 +#define LED_ACTIVE_HIGH 0 +#define AP_BUTTON_PIN INVALID_BUTTON_PIN #else #define LED_PIN LED_BUILTIN #define LED_ACTIVE_HIGH 1 @@ -44,6 +48,8 @@ OneWire oneWire(TEMP_SENSOR_PIN); DallasTemperature tempSensor(&oneWire); #endif +configuration config; + // Object used to boot as Access Point HanConfigAp ap; @@ -66,11 +72,18 @@ void setup() { debugger = &Serial; #endif + if(config.hasConfig()) { + config.load(); + } + + if(config.meterType == 3) { + Serial.begin(2400, SERIAL_8N1); + } else { + Serial.begin(2400, SERIAL_8E1); + } + while (!Serial); + if (debugger) { - // Setup serial port for debugging - debugger->begin(2400, SERIAL_8E1); - //debugger->begin(115200); - while (!debugger); debugger->println(""); debugger->println("Started..."); debugger->print("Voltage: "); @@ -94,28 +107,29 @@ void setup() { delay(1000); // Initialize the AP - ap.setup(AP_BUTTON_PIN, debugger); + ap.setup(AP_BUTTON_PIN, &config, debugger); led_off(); if (!ap.isActivated) { setupWiFi(); - // Configure uart for AMS data - if(ap.config.meterType == 3) { - Serial.begin(2400, SERIAL_8N1); - } else { - Serial.begin(2400, SERIAL_8E1); + + if(config.mqttHost) { + mqtt.begin(config.mqttHost, *client); + + // Notify everyone we're here! + sendMqttData("Connected!"); } - while (!Serial); + // Configure uart for AMS data hanReader.setup(&Serial, debugger); // Compensate for the known Kaifa bug - hanReader.compensateFor09HeaderBug = (ap.config.meterType == 1); + hanReader.compensateFor09HeaderBug = (config.meterType == 1); } - ws.setup(&ap.config, debugger); + ws.setup(&config, debugger); } // the loop function runs over and over again until power down or reset @@ -127,16 +141,19 @@ void loop() // Turn off the LED led_off(); - // allow the MQTT client some resources - mqtt.loop(); - delay(10); // <- fixes some issues with WiFi stability - // Reconnect to WiFi and MQTT as needed - if (!mqtt.connected()) { - MQTT_connect(); - } else { - readHanPort(); + if (WiFi.status() != WL_CONNECTED) { + WiFi_connect(); } + + if (config.mqttHost) { + mqtt.loop(); + delay(10); // <- fixes some issues with WiFi stability + if(!mqtt.connected()) { + MQTT_connect(); + } + } + readHanPort(); } else { @@ -178,7 +195,7 @@ void setupWiFi() // Connect to WiFi WiFi.mode(WIFI_STA); - WiFi.begin(ap.config.ssid, ap.config.ssidPassword); + WiFi.begin(config.ssid, config.ssidPassword); // Wait for WiFi connection if (debugger) debugger->print("\nWaiting for WiFi to connect..."); @@ -189,16 +206,6 @@ void setupWiFi() if (debugger) debugger->println(" connected"); client = new WiFiClient(); - mqtt.begin(ap.config.mqtt, *client); - - // Direct incoming MQTT messages - if (ap.config.mqttSubscribeTopic != 0 && strlen(ap.config.mqttSubscribeTopic) > 0) { - mqtt.subscribe(ap.config.mqttSubscribeTopic); - mqtt.onMessage(mqttMessageReceived); - } - - // Notify everyone we're here! - sendMqttData("Connected!"); } void mqttMessageReceived(String &topic, String &payload) @@ -218,7 +225,7 @@ void mqttMessageReceived(String &topic, String &payload) void readHanPort() { - if (hanReader.read() && ap.config.hasConfig()) + if (hanReader.read() && config.hasConfig()) { // Flash LED on, this shows us that data is received led_on(); @@ -247,9 +254,9 @@ void readHanPort() data["temp"] = tempSensor.getTempCByIndex(0); #endif - hanToJson(data, ap.config.meterType, hanReader); + hanToJson(data, config.meterType, hanReader); - if(ap.config.mqtt != 0 && strlen(ap.config.mqtt) != 0 && ap.config.mqttPublishTopic != 0 && strlen(ap.config.mqttPublishTopic) != 0) { + if(config.mqttHost != 0 && strlen(config.mqttHost) != 0 && config.mqttPublishTopic != 0 && strlen(config.mqttPublishTopic) != 0) { // Write the json to the debug port if (debugger) { debugger->print("Sending data to MQTT: "); @@ -261,7 +268,7 @@ void readHanPort() String msg; serializeJson(json, msg); - mqtt.publish(ap.config.mqttPublishTopic, msg.c_str()); + mqtt.publish(config.mqttPublishTopic, msg.c_str()); mqtt.loop(); } ws.setJson(json); @@ -271,25 +278,21 @@ void readHanPort() } } - -// Function to connect and reconnect as necessary to the MQTT server. -// Should be called in the loop function and it will take care if connecting. -void MQTT_connect() -{ +void WiFi_connect() { // Connect to WiFi access point. if (debugger) { debugger->println(); debugger->println(); debugger->print("Connecting to WiFi network "); - debugger->println(ap.config.ssid); + debugger->println(config.ssid); } if (WiFi.status() != WL_CONNECTED) { // Make one first attempt at connect, this seems to considerably speed up the first connection WiFi.disconnect(); - WiFi.begin(ap.config.ssid, ap.config.ssidPassword); + WiFi.begin(config.ssid, config.ssidPassword); delay(1000); } @@ -308,7 +311,7 @@ void MQTT_connect() debugger->println(WiFi.status()); } WiFi.disconnect(); - WiFi.begin(ap.config.ssid, ap.config.ssidPassword); + WiFi.begin(config.ssid, config.ssidPassword); vTimeout = millis() + WIFI_CONNECTION_TIMEOUT; } yield(); @@ -319,26 +322,33 @@ void MQTT_connect() debugger->println("WiFi connected"); debugger->println("IP address: "); debugger->println(WiFi.localIP()); - debugger->print("\nconnecting to MQTT: "); - debugger->print(ap.config.mqtt); + } +} + +// Function to connect and reconnect as necessary to the MQTT server. +// Should be called in the loop function and it will take care if connecting. +void MQTT_connect() +{ + if(debugger) { + debugger->print("Connecting to MQTT: "); + debugger->print(config.mqttHost); debugger->print(", port: "); - debugger->print(ap.config.mqttPort); + debugger->print(config.mqttPort); debugger->println(); } - // Wait for the MQTT connection to complete while (!mqtt.connected()) { // Connect to a unsecure or secure MQTT server - if ((ap.config.mqttUser == 0 && mqtt.connect(ap.config.mqttClientID)) || - (ap.config.mqttUser != 0 && mqtt.connect(ap.config.mqttClientID, ap.config.mqttUser, ap.config.mqttPass))) + if ((config.mqttUser == 0 && mqtt.connect(config.mqttClientID)) || + (config.mqttUser != 0 && mqtt.connect(config.mqttClientID, config.mqttUser, config.mqttPass))) { if (debugger) debugger->println("\nSuccessfully connected to MQTT!"); // Subscribe to the chosen MQTT topic, if set in configuration - if (ap.config.mqttSubscribeTopic != 0 && strlen(ap.config.mqttSubscribeTopic) > 0) + if (config.mqttSubscribeTopic != 0 && strlen(config.mqttSubscribeTopic) > 0) { - mqtt.subscribe(ap.config.mqttSubscribeTopic); - if (debugger) debugger->printf(" Subscribing to [%s]\r\n", ap.config.mqttSubscribeTopic); + mqtt.subscribe(config.mqttSubscribeTopic); + if (debugger) debugger->printf(" Subscribing to [%s]\r\n", config.mqttSubscribeTopic); } } else @@ -366,7 +376,7 @@ void MQTT_connect() void sendMqttData(String data) { // Make sure we have configured a publish topic - if (ap.config.mqttPublishTopic == 0 || strlen(ap.config.mqttPublishTopic) == 0) + if (config.mqttPublishTopic == 0 || strlen(config.mqttPublishTopic) == 0) return; // Make sure we're connected @@ -386,7 +396,7 @@ void sendMqttData(String data) serializeJson(json, msg); // Send the json over MQTT - mqtt.publish(ap.config.mqttPublishTopic, msg.c_str()); + mqtt.publish(config.mqttPublishTopic, msg.c_str()); if (debugger) debugger->print("sendMqttData: "); if (debugger) debugger->println(data); diff --git a/src/AmsToMqttBridge.ino.cpp b/src/AmsToMqttBridge.ino.cpp deleted file mode 100644 index 924fdb94..00000000 --- a/src/AmsToMqttBridge.ino.cpp +++ /dev/null @@ -1,380 +0,0 @@ -# 1 "/tmp/tmpfprbzre1" -#include -# 1 "/home/gunnar/src/AmsToMqttBridge/src/AmsToMqttBridge.ino" -# 11 "/home/gunnar/src/AmsToMqttBridge/src/AmsToMqttBridge.ino" -#include -#include - -#if HAS_DALLAS_TEMP_SENSOR -#include -#include -#endif - -#if defined(ESP8266) -#include -#elif defined(ESP32) -#include -#endif - -#include "AmsWebServer.h" -#include "HanConfigAp.h" -#include "HanReader.h" -#include "HanToJson.h" - -#define WIFI_CONNECTION_TIMEOUT 30000; - -#if IS_CUSTOM_AMS_BOARD -#define LED_PIN 2 -#define LED_ACTIVE_HIGH 0 -#define AP_BUTTON_PIN 0 -#else -#define LED_PIN LED_BUILTIN -#define LED_ACTIVE_HIGH 1 -#define AP_BUTTON_PIN INVALID_BUTTON_PIN -#endif - -#if HAS_DALLAS_TEMP_SENSOR -#define TEMP_SENSOR_PIN 5 - -OneWire oneWire(TEMP_SENSOR_PIN); -DallasTemperature tempSensor(&oneWire); -#endif - - -HanConfigAp ap; - -AmsWebServer ws; - - -WiFiClient *client; -MQTTClient mqtt(384); - - -HardwareSerial* debugger = NULL; - - -HanReader hanReader; -void setup(); -void loop(); -void led_on(); -void led_off(); -void setupWiFi(); -void mqttMessageReceived(String &topic, String &payload); -void readHanPort(); -void MQTT_connect(); -void sendMqttData(String data); -#line 65 "/home/gunnar/src/AmsToMqttBridge/src/AmsToMqttBridge.ino" -void setup() { - -#if DEBUG_MODE - debugger = &Serial; -#endif - - if (debugger) { - - debugger->begin(2400, SERIAL_8E1); - - while (!debugger); - debugger->println(""); - debugger->println("Started..."); - } - - - pinMode(LED_PIN, OUTPUT); - led_on(); - - delay(1000); - - - ap.setup(AP_BUTTON_PIN, debugger); - - led_off(); - - if (!ap.isActivated) - { - setupWiFi(); - - if(ap.config.meterType == 3) { - Serial.begin(2400, SERIAL_8N1); - } else { - Serial.begin(2400, SERIAL_8E1); - } - while (!Serial); - - hanReader.setup(&Serial, debugger); - - - hanReader.compensateFor09HeaderBug = (ap.config.meterType == 1); - } - - ws.setup(&ap.config, debugger); -} - - -void loop() -{ - - if (!ap.loop()) - { - - led_off(); - - - mqtt.loop(); - delay(10); - - - if (!mqtt.connected()) { - MQTT_connect(); - } else { - readHanPort(); - } - } - else - { - - if (millis() / 1000 % 2 == 0) led_on(); - else led_off(); - } - ws.loop(); -} - - -void led_on() -{ -#if LED_ACTIVE_HIGH - digitalWrite(LED_PIN, HIGH); -#else - digitalWrite(LED_PIN, LOW); -#endif -} - - -void led_off() -{ -#if LED_ACTIVE_HIGH - digitalWrite(LED_PIN, LOW); -#else - digitalWrite(LED_PIN, HIGH); -#endif -} - - -void setupWiFi() -{ - - WiFi.enableAP(false); - - - WiFi.mode(WIFI_STA); - WiFi.begin(ap.config.ssid, ap.config.ssidPassword); - - - if (debugger) debugger->print("\nWaiting for WiFi to connect..."); - while (WiFi.status() != WL_CONNECTED) { - if (debugger) debugger->print("."); - delay(500); - } - if (debugger) debugger->println(" connected"); - - client = new WiFiClient(); - mqtt.begin(ap.config.mqtt, *client); - - - if (ap.config.mqttSubscribeTopic != 0 && strlen(ap.config.mqttSubscribeTopic) > 0) { - mqtt.subscribe(ap.config.mqttSubscribeTopic); - mqtt.onMessage(mqttMessageReceived); - } - - - sendMqttData("Connected!"); -} - -void mqttMessageReceived(String &topic, String &payload) -{ - - if (debugger) { - debugger->println("Incoming MQTT message:"); - debugger->print("["); - debugger->print(topic); - debugger->print("] "); - debugger->println(payload); - } - - - -} - -void readHanPort() -{ - if (hanReader.read() && ap.config.hasConfig()) - { - - led_on(); - - - time_t time = hanReader.getPackageTime(); - if (debugger) debugger->print("Time of the package is: "); - if (debugger) debugger->println(time); - - - StaticJsonDocument<500> json; - - - json["id"] = WiFi.macAddress(); - json["up"] = millis(); - json["t"] = time; - - - - JsonObject data = json.createNestedObject("data"); - -#if HAS_DALLAS_TEMP_SENSOR - - tempSensor.requestTemperatures(); - data["temp"] = tempSensor.getTempCByIndex(0); -#endif - - hanToJson(data, ap.config.meterType, hanReader); - - if(ap.config.mqtt != 0 && strlen(ap.config.mqtt) != 0 && ap.config.mqttPublishTopic != 0 && strlen(ap.config.mqttPublishTopic) != 0) { - - if (debugger) { - debugger->print("Sending data to MQTT: "); - serializeJsonPretty(json, *debugger); - debugger->println(); - } - - - String msg; - serializeJson(json, msg); - - mqtt.publish(ap.config.mqttPublishTopic, msg.c_str()); - mqtt.loop(); - } - ws.setJson(json); - - - led_off(); - } -} - - - - -void MQTT_connect() -{ - - if (debugger) - { - debugger->println(); - debugger->println(); - debugger->print("Connecting to WiFi network "); - debugger->println(ap.config.ssid); - } - - if (WiFi.status() != WL_CONNECTED) - { - - WiFi.disconnect(); - WiFi.begin(ap.config.ssid, ap.config.ssidPassword); - delay(1000); - } - - - long vTimeout = millis() + WIFI_CONNECTION_TIMEOUT; - while (WiFi.status() != WL_CONNECTED) { - delay(50); - if (debugger) debugger->print("."); - - - if (vTimeout < millis()) - { - if (debugger) - { - debugger->print("Timout during connect. WiFi status is: "); - debugger->println(WiFi.status()); - } - WiFi.disconnect(); - WiFi.begin(ap.config.ssid, ap.config.ssidPassword); - vTimeout = millis() + WIFI_CONNECTION_TIMEOUT; - } - yield(); - } - - if (debugger) { - debugger->println(); - debugger->println("WiFi connected"); - debugger->println("IP address: "); - debugger->println(WiFi.localIP()); - debugger->print("\nconnecting to MQTT: "); - debugger->print(ap.config.mqtt); - debugger->print(", port: "); - debugger->print(ap.config.mqttPort); - debugger->println(); - } - - - while (!mqtt.connected()) { - - if ((ap.config.mqttUser == 0 && mqtt.connect(ap.config.mqttClientID)) || - (ap.config.mqttUser != 0 && mqtt.connect(ap.config.mqttClientID, ap.config.mqttUser, ap.config.mqttPass))) - { - if (debugger) debugger->println("\nSuccessfully connected to MQTT!"); - - - if (ap.config.mqttSubscribeTopic != 0 && strlen(ap.config.mqttSubscribeTopic) > 0) - { - mqtt.subscribe(ap.config.mqttSubscribeTopic); - if (debugger) debugger->printf(" Subscribing to [%s]\r\n", ap.config.mqttSubscribeTopic); - } - } - else - { - if (debugger) - { - debugger->print("."); - debugger->print("failed, "); - debugger->println(" trying again in 5 seconds"); - } - - - mqtt.disconnect(); - - delay(2000); - } - - - yield(); - delay(2000); - } -} - - -void sendMqttData(String data) -{ - - if (ap.config.mqttPublishTopic == 0 || strlen(ap.config.mqttPublishTopic) == 0) - return; - - - if (!client->connected() || !mqtt.connected()) { - MQTT_connect(); - } - - - StaticJsonDocument<500> json; - json["id"] = WiFi.macAddress(); - json["up"] = millis(); - json["data"] = data; - - - String msg; - serializeJson(json, msg); - - - mqtt.publish(ap.config.mqttPublishTopic, msg.c_str()); - - if (debugger) debugger->print("sendMqttData: "); - if (debugger) debugger->println(data); -} \ No newline at end of file diff --git a/src/application_css.h b/src/application_css.h deleted file mode 100644 index 661348ff..00000000 --- a/src/application_css.h +++ /dev/null @@ -1,46 +0,0 @@ -const char APPLICATION_CSS[] PROGMEM = R"=="==( -.bg-purple { - background-color: var(--purple); -} - - -.GaugeMeter { - position: Relative; - text-align: Center; - overflow: Hidden; - cursor: Default; - display: inline-block; -} - -.GaugeMeter SPAN, .GaugeMeter B { - width: 54%; - position: Absolute; - text-align: Center; - display: Inline-Block; - color: RGBa(0,0,0,.8); - font-weight: 100; - font-family: "Open Sans", Arial; - overflow: Hidden; - white-space: NoWrap; - text-overflow: Ellipsis; - margin: 0 23%; -} - -.GaugeMeter[data-style="Semi"] B { - width: 80%; - margin: 0 10%; -} - -.GaugeMeter S, .GaugeMeter U { - text-decoration: None; - font-size: .60em; - font-weight: 200; - opacity: .6; -} - -.GaugeMeter B { - color: #000; - font-weight: 200; - opacity: .8; -} -)=="=="; diff --git a/src/index_html.h b/src/index_html.h deleted file mode 100644 index 3fbeb677..00000000 --- a/src/index_html.h +++ /dev/null @@ -1,79 +0,0 @@ -const char INDEX_HTML[] PROGMEM = R"=="==( - - - - - AMS reader - - - - - - - - -
-
-
-
AMS reader
- ${version} -
-
-
-
Current meter values
-
-
-
-
- ${data.P} W -
- -
-
-
-
-
P1
-
${data.U1} V
-
${data.I1} A
-
-
-
P2
-
${data.U2} V
-
${data.I2} A
-
-
-
P3
-
${data.U3} V
-
${data.I3} A
-
-
-
-
-
- -
- - - -)=="=="; diff --git a/src/index_js.h b/src/index_js.h deleted file mode 100644 index 5a02bfe4..00000000 --- a/src/index_js.h +++ /dev/null @@ -1,80 +0,0 @@ -const char INDEX_JS[] PROGMEM = R"=="==( -$(".GaugeMeter").gaugeMeter(); - -var wait = 500; -var nextrefresh = wait; -var fetch = function() { - $.ajax({ - url: '/data.json', - dataType: 'json', - }).done(function(json) { - $(".SimpleMeter").hide(); - var el = $(".GaugeMeter"); - el.show(); - var rate = 2500; - if(json.data) { - el.data('percent', json.pct); - if(json.data.P) { - var num = parseFloat(json.data.P); - if(num > 1000) { - num = num / 1000; - el.data('text', num.toFixed(1)); - el.data('append','kW'); - } else { - el.data('text', num); - el.data('append','W'); - } - } - el.gaugeMeter(); - - for(var id in json.data) { - var str = json.data[id]; - if(isNaN(str)) { - $('#'+id).html(str); - } else { - var num = parseFloat(str); - $('#'+id).html(num.toFixed(1)); - } - } - - if(json.data.U1 > 0) { - $('#P1').show(); - } - - if(json.data.U2 > 0) { - $('#P2').show(); - } - - if(json.data.U3 > 0) { - $('#P3').show(); - } - - if(json.meterType == 3) { - rate = 10000; - } - if(json.currentMillis && json.up) { - nextrefresh = rate - ((json.currentMillis - json.up) % rate) + wait; - } else { - nextrefresh = 2500; - } - } else { - el.data('percent', 0); - el.data('text', '-'); - el.gaugeMeter(); - nextrefresh = 2500; - } - if(!nextrefresh || nextrefresh < 500) { - nextrefresh = 2500; - } - setTimeout(fetch, nextrefresh); - }).fail(function() { - el.data('percent', 0); - el.data('text', '-'); - el.gaugeMeter(); - nextrefresh = 10000; - setTimeout(fetch, nextrefresh); - }); -} -setTimeout(fetch, nextrefresh); - -)=="=="; diff --git a/src/AmsWebServer.cpp b/src/web/AmsWebServer.cpp similarity index 76% rename from src/AmsWebServer.cpp rename to src/web/AmsWebServer.cpp index 36abe811..e83fbebb 100644 --- a/src/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -1,12 +1,10 @@ #include "AmsWebServer.h" #include "version.h" -#include "index_html.h" -#include "configuration_html.h" -#include "boot_css.h" -#include "application_css.h" -#include "gaugemeter_js.h" -#include "index_js.h" +#include "root/index_html.h" +#include "root/configuration_html.h" +#include "root/boot_css.h" +#include "root/gaugemeter_js.h" #include "Base64.h" @@ -22,10 +20,8 @@ void AmsWebServer::setup(configuration* config, Stream* debugger) { server.on("/", std::bind(&AmsWebServer::indexHtml, this)); server.on("/configuration", std::bind(&AmsWebServer::configurationHtml, this)); - server.on("/css/boot.css", std::bind(&AmsWebServer::bootCss, this)); - server.on("/css/application.css", std::bind(&AmsWebServer::applicationCss, this)); - server.on("/js/gaugemeter.js", std::bind(&AmsWebServer::gaugemeterJs, this)); - server.on("/js/index.js", std::bind(&AmsWebServer::indexJs, this)); + server.on("/boot.css", std::bind(&AmsWebServer::bootCss, this)); + server.on("/gaugemeter.js", std::bind(&AmsWebServer::gaugemeterJs, this)); server.on("/data.json", std::bind(&AmsWebServer::dataJson, this)); server.on("/save", std::bind(&AmsWebServer::handleSave, this)); @@ -39,12 +35,6 @@ void AmsWebServer::setup(configuration* config, Stream* debugger) { print(WiFi.localIP()); } println("/"); - - if(config->hasConfig() && config->fuseSize > 0) { - maxPwr = config->fuseSize * 230; - } else { - maxPwr = 20000; - } } void AmsWebServer::loop() { @@ -62,13 +52,12 @@ void AmsWebServer::setJson(StaticJsonDocument<500> json) { i2 = json["data"]["I2"].as(); i3 = json["data"]["I3"].as(); - if(config->hasConfig() && u1 > 0) { - maxPwr = config->fuseSize * u1; + if(maxPwr == 0 && config->hasConfig() && config->fuseSize > 0 && config->distSys > 0) { + int volt = config->distSys == 2 ? 400 : 230; if(u2 > 0) { - maxPwr += config->fuseSize * u2; - if(u3 > 0) { - maxPwr += config->fuseSize * u3; - } + maxPwr = config->fuseSize * sqrt(3) * volt; + } else { + maxPwr = config->fuseSize * 230; } } } else { @@ -165,7 +154,8 @@ void AmsWebServer::configurationHtml() { for(int i = 0; i<4; i++) { html.replace("${config.meterType" + String(i) + "}", config->meterType == i ? "selected" : ""); } - html.replace("${config.mqtt}", config->mqtt); + html.replace("${config.mqtt}", config->mqttHost == 0 ? "" : "checked"); + html.replace("${config.mqttHost}", config->mqttHost); html.replace("${config.mqttPort}", String(config->mqttPort)); html.replace("${config.mqttClientID}", config->mqttClientID); html.replace("${config.mqttPublishTopic}", config->mqttPublishTopic); @@ -182,6 +172,9 @@ void AmsWebServer::configurationHtml() { for(int i = 0; i<64; i++) { html.replace("${config.fuseSize" + String(i) + "}", config->fuseSize == i ? "selected" : ""); } + for(int i = 0; i<3; i++) { + html.replace("${config.distSys" + String(i) + "}", config->distSys == i ? "selected" : ""); + } } else { html.replace("${config.ssid}", ""); html.replace("${config.ssidPassword}", ""); @@ -190,6 +183,7 @@ void AmsWebServer::configurationHtml() { html.replace("${config.meterType" + String(i) + "}", i == 0 ? "selected" : ""); } html.replace("${config.mqtt}", ""); + html.replace("${config.mqttHost}", ""); html.replace("${config.mqttPort}", "1883"); html.replace("${config.mqttClientID}", ""); html.replace("${config.mqttPublishTopic}", ""); @@ -206,6 +200,9 @@ void AmsWebServer::configurationHtml() { for(int i = 0; i<64; i++) { html.replace("${config.fuseSize" + String(i) + "}", i == 0 ? "selected" : ""); } + for(int i = 0; i<3; i++) { + html.replace("${config.distSys" + String(i) + "}", i == 0 ? "selected" : ""); + } } server.send(200, "text/html", html); } @@ -219,31 +216,13 @@ void AmsWebServer::bootCss() { server.send(200, "text/css", BOOT_CSS); } -void AmsWebServer::applicationCss() { - println("Serving /application.css over http..."); - - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - server.sendHeader("Pragma", "no-cache"); - server.sendHeader("Expires", "-1"); - server.send(200, "text/css", APPLICATION_CSS); -} - void AmsWebServer::gaugemeterJs() { println("Serving /gaugemeter.js over http..."); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); - server.send(200, "application/javascript", GAUEGMETER_JS); -} - -void AmsWebServer::indexJs() { - println("Serving /index.js over http..."); - - server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - server.sendHeader("Pragma", "no-cache"); - server.sendHeader("Expires", "-1"); - server.send(200, "application/javascript", INDEX_JS); + server.send(200, "application/javascript", GAUGEMETER_JS); } void AmsWebServer::dataJson() { @@ -256,6 +235,15 @@ void AmsWebServer::dataJson() { if(!json.isNull()) { println(" json has data"); + int maxPwr = this->maxPwr; + if(maxPwr == 0) { + if(u2 > 0) { + maxPwr = 20000; + } else { + maxPwr = 10000; + } + } + json["maxPower"] = maxPwr; json["pct"] = min(p*100/maxPwr, 100); json["meterType"] = config->meterType; @@ -286,44 +274,56 @@ void AmsWebServer::handleSave() { config->meterType = (byte)server.arg("meterType").toInt(); - temp = server.arg("mqtt"); - config->mqtt = new char[temp.length() + 1]; - temp.toCharArray(config->mqtt, temp.length() + 1, 0); + if(server.hasArg("mqtt") && server.arg("mqtt") == "true") { + println("MQTT enabled"); + temp = server.arg("mqttHost"); + config->mqttHost = new char[temp.length() + 1]; + temp.toCharArray(config->mqttHost, temp.length() + 1, 0); - config->mqttPort = (int)server.arg("mqttPort").toInt(); + config->mqttPort = (int)server.arg("mqttPort").toInt(); - temp = server.arg("mqttClientID"); - config->mqttClientID = new char[temp.length() + 1]; - temp.toCharArray(config->mqttClientID, temp.length() + 1, 0); + temp = server.arg("mqttClientID"); + config->mqttClientID = new char[temp.length() + 1]; + temp.toCharArray(config->mqttClientID, temp.length() + 1, 0); - temp = server.arg("mqttPublishTopic"); - config->mqttPublishTopic = new char[temp.length() + 1]; - temp.toCharArray(config->mqttPublishTopic, temp.length() + 1, 0); + temp = server.arg("mqttPublishTopic"); + config->mqttPublishTopic = new char[temp.length() + 1]; + temp.toCharArray(config->mqttPublishTopic, temp.length() + 1, 0); - temp = server.arg("mqttSubscribeTopic"); - config->mqttSubscribeTopic = new char[temp.length() + 1]; - temp.toCharArray(config->mqttSubscribeTopic, temp.length() + 1, 0); + temp = server.arg("mqttSubscribeTopic"); + config->mqttSubscribeTopic = new char[temp.length() + 1]; + temp.toCharArray(config->mqttSubscribeTopic, temp.length() + 1, 0); - temp = server.arg("mqttUser"); - config->mqttUser = new char[temp.length() + 1]; - temp.toCharArray(config->mqttUser, temp.length() + 1, 0); + temp = server.arg("mqttUser"); + config->mqttUser = new char[temp.length() + 1]; + temp.toCharArray(config->mqttUser, temp.length() + 1, 0); - temp = server.arg("mqttPass"); - config->mqttPass = new char[temp.length() + 1]; - temp.toCharArray(config->mqttPass, temp.length() + 1, 0); + temp = server.arg("mqttPass"); + config->mqttPass = new char[temp.length() + 1]; + temp.toCharArray(config->mqttPass, temp.length() + 1, 0); + } else { + println("MQTT disabled"); + config->mqttHost = NULL; + config->mqttUser = NULL; + config->mqttPass = NULL; + } config->authSecurity = (byte)server.arg("authSecurity").toInt(); - temp = server.arg("authUser"); - config->authUser = new char[temp.length() + 1]; - temp.toCharArray(config->authUser, temp.length() + 1, 0); + if(config->authSecurity > 0) { + temp = server.arg("authUser"); + config->authUser = new char[temp.length() + 1]; + temp.toCharArray(config->authUser, temp.length() + 1, 0); - temp = server.arg("authPass"); - config->authPass = new char[temp.length() + 1]; - temp.toCharArray(config->authPass, temp.length() + 1, 0); + temp = server.arg("authPass"); + config->authPass = new char[temp.length() + 1]; + temp.toCharArray(config->authPass, temp.length() + 1, 0); + } config->fuseSize = (int)server.arg("fuseSize").toInt(); + config->distSys = (byte)server.arg("distSys").toInt(); + println("Saving configuration now..."); if (debugger) config->print(debugger); diff --git a/src/AmsWebServer.h b/src/web/AmsWebServer.h similarity index 96% rename from src/AmsWebServer.h rename to src/web/AmsWebServer.h index 921fa3d8..cc9e0d01 100644 --- a/src/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -45,9 +45,7 @@ private: void indexHtml(); void configurationHtml(); void bootCss(); - void applicationCss(); void gaugemeterJs(); - void indexJs(); void dataJson(); void handleSave(); diff --git a/src/boot_css.h b/web/boot.css similarity index 98% rename from src/boot_css.h rename to web/boot.css index 342066a8..c3239894 100644 --- a/src/boot_css.h +++ b/web/boot.css @@ -1,4 +1,3 @@ -const char BOOT_CSS[] PROGMEM = R"=="==( /* Ripped necessary style from bootstrap 4.4.1 to make the page look good without internet access. Meant to be overridden by CSS from CDN */ :root { --blue: #007bff; @@ -237,6 +236,10 @@ a { border-radius: .25rem; transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; } +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} input:not([type="image" i]) { box-sizing: border-box; } @@ -324,4 +327,3 @@ hr { *, ::after, ::before { box-sizing: border-box; } -)=="=="; diff --git a/src/configuration_html.h b/web/configuration.html similarity index 74% rename from src/configuration_html.h rename to web/configuration.html index 28e8028c..f89f10cd 100644 --- a/src/configuration_html.h +++ b/web/configuration.html @@ -1,13 +1,17 @@ -const char CONFIGURATION_HTML[] PROGMEM = R"=="==( AMS reader - configuration - + - + +
@@ -38,8 +42,18 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
AMS meter
- -
+ +
+ +
+
+
+ +
@@ -66,40 +80,46 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
MQTT
+
+ +
+ +
+
- +
- +
- +
- +
- +
- +
@@ -110,7 +130,7 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
- @@ -120,13 +140,13 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
- +
- +
@@ -143,6 +163,21 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
+ -)=="=="; diff --git a/src/gaugemeter_js.h b/web/gaugemeter.js similarity index 99% rename from src/gaugemeter_js.h rename to web/gaugemeter.js index 5eeb432a..fc4e5b9e 100644 --- a/src/gaugemeter_js.h +++ b/web/gaugemeter.js @@ -1,4 +1,3 @@ -const char GAUEGMETER_JS[] PROGMEM = R"=="==( /* * AshAlom Gauge Meter. Version 2.0.0 * Copyright AshAlom.com All rights reserved. @@ -274,4 +273,3 @@ const char GAUEGMETER_JS[] PROGMEM = R"=="==( }; } (jQuery); -)=="=="; diff --git a/web/index.html b/web/index.html new file mode 100644 index 00000000..87a7a4e8 --- /dev/null +++ b/web/index.html @@ -0,0 +1,199 @@ + + + + + AMS reader + + + + + + + + +
+
+
+
AMS reader
+ ${version} +
+
+
+
Current meter values
+
+
+
+
+ ${data.P} W +
+ +
+
+
+
+
P1
+
${data.U1} V
+
${data.I1} A
+
+
+
P2
+
${data.U2} V
+
${data.I2} A
+
+
+
P3
+
${data.U3} V
+
${data.I3} A
+
+
+
+
+
+ +
+ + +