mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-21 10:22:45 +00:00
Merge branch 'master' into low_power
This commit is contained in:
commit
7e6ac860fd
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -5,6 +5,8 @@ on:
|
||||
paths:
|
||||
- src/**
|
||||
- lib/**
|
||||
- scripts/**
|
||||
- web/**
|
||||
- platformio.ini
|
||||
branches:
|
||||
- master
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,3 +8,5 @@
|
||||
.pio
|
||||
platformio-user.ini
|
||||
/src/version.h
|
||||
/src/web/root
|
||||
/src/AmsToMqttBridge.ino.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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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++;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
30
scripts/makeweb.py
Normal file
30
scripts/makeweb.py
Normal file
@ -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")
|
||||
@ -20,7 +20,7 @@ ADC_MODE(ADC_VCC);
|
||||
#include <WiFi.h>
|
||||
#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);
|
||||
|
||||
@ -1,380 +0,0 @@
|
||||
# 1 "/tmp/tmpfprbzre1"
|
||||
#include <Arduino.h>
|
||||
# 1 "/home/gunnar/src/AmsToMqttBridge/src/AmsToMqttBridge.ino"
|
||||
# 11 "/home/gunnar/src/AmsToMqttBridge/src/AmsToMqttBridge.ino"
|
||||
#include <ArduinoJson.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
#if HAS_DALLAS_TEMP_SENSOR
|
||||
#include <DallasTemperature.h>
|
||||
#include <OneWire.h>
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#elif defined(ESP32)
|
||||
#include <WiFi.h>
|
||||
#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);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
)=="==";
|
||||
@ -1,79 +0,0 @@
|
||||
const char INDEX_HTML[] PROGMEM = R"=="==(
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="/css/boot.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/application.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<script src="/js/gaugemeter.js"></script>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<div class="d-flex align-items-center p-3 my-2 text-white-50 bg-purple rounded shadow">
|
||||
<div class="lh-100">
|
||||
<h6 class="mb-0 text-white lh-100">AMS reader</h6>
|
||||
<small>${version}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<h6 class="border-bottom border-gray pb-2 mb-4">Current meter values</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter">
|
||||
${data.P} W
|
||||
</div>
|
||||
<div class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="200px"
|
||||
data-text_size="0.11"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="Green-Gold-Red"
|
||||
data-animationstep="0"
|
||||
data-animate_gauge_colors="1"
|
||||
|
||||
data-percent="0"
|
||||
data-text="-"
|
||||
data-label="Consumption"
|
||||
data-append="W"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div id="P1" class="row" style="display: ${display.P1}">
|
||||
<div class="col-2">P1</div>
|
||||
<div class="col-5 text-right"><span id="U1">${data.U1}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I1">${data.I1}</span> A</div>
|
||||
</div>
|
||||
<div id="P2" class="row" style="display: ${display.P2}">
|
||||
<div class="col-2">P2</div>
|
||||
<div class="col-5 text-right"><span id="U2">${data.U2}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I2">${data.I2}</span> A</div>
|
||||
</div>
|
||||
<div id="P3" class="row" style="display: ${display.P3}">
|
||||
<div class="col-2">P3</div>
|
||||
<div class="col-5 text-right"><span id="U3">${data.U3}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I3">${data.I3}</span> A</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/releases" class="btn btn-outline-secondary">Release notes</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<a href="/configuration" class="btn btn-primary">Configuration</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="/js/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
)=="==";
|
||||
@ -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);
|
||||
|
||||
)=="==";
|
||||
@ -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<double>();
|
||||
i3 = json["data"]["I3"].as<double>();
|
||||
|
||||
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);
|
||||
@ -45,9 +45,7 @@ private:
|
||||
void indexHtml();
|
||||
void configurationHtml();
|
||||
void bootCss();
|
||||
void applicationCss();
|
||||
void gaugemeterJs();
|
||||
void indexJs();
|
||||
void dataJson();
|
||||
|
||||
void handleSave();
|
||||
@ -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;
|
||||
}
|
||||
)=="==";
|
||||
@ -1,13 +1,17 @@
|
||||
const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="/css/boot.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/application.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<style>
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
@ -38,8 +42,18 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<h6 class="border-bottom border-gray pb-2 mb-4">AMS meter</h6>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Meter type</label>
|
||||
<div class="col-8">
|
||||
<label class="col-6">Distribution system</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control" name="distSys">
|
||||
<option value="" ${config.distSys0}></option>
|
||||
<option value="1" ${config.distSys1}>IT (230V)</option>
|
||||
<option value="2" ${config.distSys2}>TN (400V)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Meter type</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control" name="meterType">
|
||||
<option value="0" ${config.meterType0} disabled></option>
|
||||
<option value="1" ${config.meterType1}>Kaifa</option>
|
||||
@ -49,8 +63,8 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Main fuse</label>
|
||||
<div class="col-8">
|
||||
<label class="col-6">Main fuse</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control" name="fuseSize">
|
||||
<option value="" ${config.fuseSize0}></option>
|
||||
<option value="25" ${config.fuseSize25}>25A</option>
|
||||
@ -66,40 +80,46 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="my-2 p-3 bg-white rounded shadow">
|
||||
<h6 class="border-bottom border-gray pb-2 mb-4">MQTT</h6>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Enable</label>
|
||||
<div class="col-8">
|
||||
<input id="mqttEnable" type="checkbox" name="mqtt" value="true" ${config.mqtt}/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Hostname</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control" name="mqtt" value="${config.mqtt}"/>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttHost" value="${config.mqttHost}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Port</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control" name="mqttPort" value="${config.mqttPort}"/>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttPort" value="${config.mqttPort}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Client ID</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control" name="mqttClientID" value="${config.mqttClientID}"/>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttClientID" value="${config.mqttClientID}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Topic</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control" name="mqttPublishTopic" value="${config.mqttPublishTopic}"/>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttPublishTopic" value="${config.mqttPublishTopic}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Username</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control" name="mqttUser" value="${config.mqttUser}"/>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttUser" value="${config.mqttUser}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Password</label>
|
||||
<div class="col-8">
|
||||
<input type="password" class="form-control" name="mqttPass" value="${config.mqttPass}"/>
|
||||
<input type="password" class="form-control mqtt-config" name="mqttPass" value="${config.mqttPass}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -110,7 +130,7 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Security</label>
|
||||
<div class="col-8">
|
||||
<select class="form-control" name="authSecurity">
|
||||
<select id="authSecurity" class="form-control" name="authSecurity">
|
||||
<option value="0" ${config.authSecurity0}>None</option>
|
||||
<option value="1" ${config.authSecurity1}>Only configuration</option>
|
||||
<option value="2" ${config.authSecurity2}>Everything</option>
|
||||
@ -120,13 +140,13 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Username</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control" name="authUser" value="${config.authUser}"/>
|
||||
<input type="text" class="form-control auth-config" name="authUser" value="${config.authUser}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Password</label>
|
||||
<div class="col-8">
|
||||
<input type="password" class="form-control" name="authPass" value="${config.authPass}"/>
|
||||
<input type="password" class="form-control auth-config" name="authPass" value="${config.authPass}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -143,6 +163,21 @@ const char CONFIGURATION_HTML[] PROGMEM = R"=="==(
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<script>
|
||||
$('#mqttEnable').on('change', function() {
|
||||
var inputs = $('.mqtt-config');
|
||||
inputs.prop('disabled', !$(this).is(':checked'));
|
||||
});
|
||||
|
||||
$('#authSecurity').on('change', function() {
|
||||
var inputs = $('.auth-config');
|
||||
inputs.prop('disabled', $(this).val() == 0);
|
||||
});
|
||||
|
||||
$(function() {
|
||||
$('#mqttEnable').trigger('change');
|
||||
$('#authSecurity').trigger('change');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)=="==";
|
||||
@ -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);
|
||||
)=="==";
|
||||
199
web/index.html
Normal file
199
web/index.html
Normal file
@ -0,0 +1,199 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<script src="gaugemeter.js"></script>
|
||||
<style>
|
||||
.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;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<div class="d-flex align-items-center p-3 my-2 text-white-50 bg-purple rounded shadow">
|
||||
<div class="lh-100">
|
||||
<h6 class="mb-0 text-white lh-100">AMS reader</h6>
|
||||
<small>${version}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<h6 class="border-bottom border-gray pb-2 mb-4">Current meter values</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter">
|
||||
${data.P} W
|
||||
</div>
|
||||
<div class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="200px"
|
||||
data-text_size="0.11"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="Green-Gold-Red"
|
||||
data-animationstep="0"
|
||||
data-animate_gauge_colors="1"
|
||||
|
||||
data-percent="0"
|
||||
data-text="-"
|
||||
data-label="Consumption"
|
||||
data-append="W"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div id="P1" class="row" style="display: ${display.P1}">
|
||||
<div class="col-2">P1</div>
|
||||
<div class="col-5 text-right"><span id="U1">${data.U1}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I1">${data.I1}</span> A</div>
|
||||
</div>
|
||||
<div id="P2" class="row" style="display: ${display.P2}">
|
||||
<div class="col-2">P2</div>
|
||||
<div class="col-5 text-right"><span id="U2">${data.U2}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I2">${data.I2}</span> A</div>
|
||||
</div>
|
||||
<div id="P3" class="row" style="display: ${display.P3}">
|
||||
<div class="col-2">P3</div>
|
||||
<div class="col-5 text-right"><span id="U3">${data.U3}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I3">${data.I3}</span> A</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/releases" class="btn btn-outline-secondary">Release notes</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<a href="configuration" class="btn btn-primary">Configuration</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
$(".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);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user