mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-20 10:04:59 +00:00
Support older config versions. Fixed css for AP mode. Some cleanup and changes to preserve power
This commit is contained in:
parent
227eb7b6ff
commit
4786735d4c
@ -205,13 +205,19 @@ void AmsConfiguration::setProductionCapacity(int productionCapacity) {
|
||||
}
|
||||
|
||||
|
||||
bool AmsConfiguration::hasConfig()
|
||||
{
|
||||
bool hasConfig = false;
|
||||
bool AmsConfiguration::hasConfig() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
hasConfig = EEPROM.read(EEPROM_CONFIG_ADDRESS) == EEPROM_CHECK_SUM;
|
||||
int configVersion = EEPROM.read(EEPROM_CONFIG_ADDRESS);
|
||||
EEPROM.end();
|
||||
return hasConfig;
|
||||
switch(configVersion) {
|
||||
case 71:
|
||||
case 72:
|
||||
case 75:
|
||||
case 80:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AmsConfiguration::load() {
|
||||
@ -220,80 +226,209 @@ bool AmsConfiguration::load() {
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
int cs = EEPROM.read(address);
|
||||
if (cs == EEPROM_CHECK_SUM)
|
||||
{
|
||||
char* temp;
|
||||
address++;
|
||||
|
||||
address += readString(address, &temp);
|
||||
setWifiSsid(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiPassword(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiIp(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiGw(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiSubnet(temp);
|
||||
|
||||
bool mqtt = false;
|
||||
address += readBool(address, &mqtt);
|
||||
if(mqtt) {
|
||||
address += readString(address, &temp);
|
||||
setMqttHost(temp);
|
||||
int port;
|
||||
address += readInt(address, &port);
|
||||
setMqttPort(port);
|
||||
address += readString(address, &temp);
|
||||
setMqttClientId(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPublishTopic(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttSubscribeTopic(temp);
|
||||
|
||||
bool secure = false;
|
||||
address += readBool(address, &secure);
|
||||
if (secure)
|
||||
{
|
||||
address += readString(address, &temp);
|
||||
setMqttUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPassword(temp);
|
||||
} else {
|
||||
setMqttUser("");
|
||||
setMqttPassword("");
|
||||
}
|
||||
} else {
|
||||
clearMqtt();
|
||||
}
|
||||
|
||||
address += readByte(address, &authSecurity);
|
||||
if (authSecurity > 0) {
|
||||
address += readString(address, &temp);
|
||||
setAuthUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setAuthPassword(temp);
|
||||
} else {
|
||||
clearAuth();
|
||||
}
|
||||
|
||||
int i;
|
||||
address += readInt(address, &i);
|
||||
setMeterType(i);
|
||||
address += readInt(address, &i);
|
||||
setDistributionSystem(i);
|
||||
address += readInt(address, &i);
|
||||
setMainFuse(i);
|
||||
address += readInt(address, &i);
|
||||
setProductionCapacity(i);
|
||||
|
||||
ackWifiChange();
|
||||
|
||||
success = true;
|
||||
}
|
||||
address++;
|
||||
switch(cs) {
|
||||
case 71: // Same as 72
|
||||
case 72:
|
||||
success = loadConfig72(address);
|
||||
break;
|
||||
case 75:
|
||||
success = loadConfig75(address);
|
||||
break;
|
||||
case 80:
|
||||
success = loadConfig80(address);
|
||||
break;
|
||||
}
|
||||
EEPROM.end();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::loadConfig72(int address) {
|
||||
char* temp;
|
||||
|
||||
address += readString(address, &temp);
|
||||
setWifiSsid(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiPassword(temp);
|
||||
|
||||
byte b;
|
||||
address += readByte(address, &b);
|
||||
setMeterType(b);
|
||||
|
||||
address += readString(address, &temp);
|
||||
setMqttHost(temp);
|
||||
int port;
|
||||
address += readInt(address, &port);
|
||||
setMqttPort(port);
|
||||
address += readString(address, &temp);
|
||||
setMqttClientId(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPublishTopic(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttSubscribeTopic(temp);
|
||||
|
||||
bool secure = false;
|
||||
address += readBool(address, &secure);
|
||||
if (secure) {
|
||||
address += readString(address, &temp);
|
||||
setMqttUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPassword(temp);
|
||||
} else {
|
||||
setMqttUser("");
|
||||
setMqttPassword("");
|
||||
}
|
||||
|
||||
clearAuth();
|
||||
|
||||
setWifiIp("");
|
||||
setWifiGw("");
|
||||
setWifiSubnet("");
|
||||
setMainFuse(0);
|
||||
setProductionCapacity(0);
|
||||
setDistributionSystem(0);
|
||||
|
||||
ackWifiChange();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::loadConfig75(int address) {
|
||||
char* temp;
|
||||
|
||||
address += readString(address, &temp);
|
||||
setWifiSsid(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiPassword(temp);
|
||||
|
||||
byte b;
|
||||
address += readByte(address, &b);
|
||||
setMeterType(b);
|
||||
|
||||
bool mqtt = false;
|
||||
address += readBool(address, &mqtt);
|
||||
if(mqtt) {
|
||||
address += readString(address, &temp);
|
||||
setMqttHost(temp);
|
||||
int port;
|
||||
address += readInt(address, &port);
|
||||
setMqttPort(port);
|
||||
address += readString(address, &temp);
|
||||
setMqttClientId(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPublishTopic(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttSubscribeTopic(temp);
|
||||
}
|
||||
|
||||
bool secure = false;
|
||||
address += readBool(address, &secure);
|
||||
if (secure) {
|
||||
address += readString(address, &temp);
|
||||
setMqttUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPassword(temp);
|
||||
} else {
|
||||
setMqttUser("");
|
||||
setMqttPassword("");
|
||||
}
|
||||
|
||||
address += readByte(address, &authSecurity);
|
||||
if (authSecurity > 0) {
|
||||
address += readString(address, &temp);
|
||||
setAuthUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setAuthPassword(temp);
|
||||
} else {
|
||||
clearAuth();
|
||||
}
|
||||
|
||||
int i;
|
||||
address += readInt(address, &i);
|
||||
setMainFuse(i);
|
||||
address += readByte(address, &b);
|
||||
setDistributionSystem(b);
|
||||
|
||||
setWifiIp("");
|
||||
setWifiGw("");
|
||||
setWifiSubnet("");
|
||||
setProductionCapacity(0);
|
||||
|
||||
ackWifiChange();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::loadConfig80(int address) {
|
||||
char* temp;
|
||||
|
||||
address += readString(address, &temp);
|
||||
setWifiSsid(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiPassword(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiIp(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiGw(temp);
|
||||
address += readString(address, &temp);
|
||||
setWifiSubnet(temp);
|
||||
|
||||
bool mqtt = false;
|
||||
address += readBool(address, &mqtt);
|
||||
if(mqtt) {
|
||||
address += readString(address, &temp);
|
||||
setMqttHost(temp);
|
||||
int port;
|
||||
address += readInt(address, &port);
|
||||
setMqttPort(port);
|
||||
address += readString(address, &temp);
|
||||
setMqttClientId(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPublishTopic(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttSubscribeTopic(temp);
|
||||
|
||||
bool secure = false;
|
||||
address += readBool(address, &secure);
|
||||
if (secure)
|
||||
{
|
||||
address += readString(address, &temp);
|
||||
setMqttUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setMqttPassword(temp);
|
||||
} else {
|
||||
setMqttUser("");
|
||||
setMqttPassword("");
|
||||
}
|
||||
} else {
|
||||
clearMqtt();
|
||||
}
|
||||
|
||||
address += readByte(address, &authSecurity);
|
||||
if (authSecurity > 0) {
|
||||
address += readString(address, &temp);
|
||||
setAuthUser(temp);
|
||||
address += readString(address, &temp);
|
||||
setAuthPassword(temp);
|
||||
} else {
|
||||
clearAuth();
|
||||
}
|
||||
|
||||
int i;
|
||||
address += readInt(address, &i);
|
||||
setMeterType(i);
|
||||
address += readInt(address, &i);
|
||||
setDistributionSystem(i);
|
||||
address += readInt(address, &i);
|
||||
setMainFuse(i);
|
||||
address += readInt(address, &i);
|
||||
setProductionCapacity(i);
|
||||
|
||||
ackWifiChange();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::save() {
|
||||
int address = EEPROM_CONFIG_ADDRESS;
|
||||
|
||||
|
||||
@ -88,9 +88,13 @@ private:
|
||||
int meterType, distributionSystem, mainFuse, productionCapacity;
|
||||
|
||||
const int EEPROM_SIZE = 512;
|
||||
const byte EEPROM_CHECK_SUM = 80; // Used to check if config is stored. Change if structure changes
|
||||
const int EEPROM_CHECK_SUM = 80; // Used to check if config is stored. Change if structure changes
|
||||
const int EEPROM_CONFIG_ADDRESS = 0;
|
||||
|
||||
bool loadConfig72(int address);
|
||||
bool loadConfig75(int address);
|
||||
bool loadConfig80(int address);
|
||||
|
||||
int saveString(int pAddress, const char* pString);
|
||||
int readString(int pAddress, char* pString[]);
|
||||
int saveInt(int pAddress, int pValue);
|
||||
|
||||
@ -19,12 +19,15 @@
|
||||
#define AP_BUTTON_PIN 0
|
||||
|
||||
#if DEBUG_MODE
|
||||
#define SOFTWARE_SERIAL 1
|
||||
#if SOFTWARE_SERIAL
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial *hanSerial = new SoftwareSerial(3);
|
||||
#else
|
||||
HardwareSerial *hanSerial = &Serial;
|
||||
#endif
|
||||
#else
|
||||
HardwareSerial *hanSerial = &Serial;
|
||||
#endif
|
||||
|
||||
// Build settings for Wemos Lolin D32
|
||||
#elif defined(ARDUINO_LOLIN_D32)
|
||||
|
||||
@ -44,8 +44,6 @@ Stream* debugger = NULL;
|
||||
// The HAN Port reader, used to read serial data and decode DLMS
|
||||
HanReader hanReader;
|
||||
|
||||
boolean hasTempSensor = false;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup() {
|
||||
if(config.hasConfig()) {
|
||||
@ -54,9 +52,18 @@ void setup() {
|
||||
|
||||
#if DEBUG_MODE
|
||||
#if HW_ROARFRED
|
||||
#if SOFTWARE_SERIAL
|
||||
SoftwareSerial *ser = new SoftwareSerial(-1, 1);
|
||||
ser->begin(115200, SWSERIAL_8N1);
|
||||
debugger = ser;
|
||||
#else
|
||||
HardwareSerial *ser = &Serial;
|
||||
if(config.getMeterType() == 3) {
|
||||
ser->begin(2400, SERIAL_8N1);
|
||||
} else {
|
||||
ser->begin(2400, SERIAL_8E1);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
HardwareSerial *ser = &Serial;
|
||||
ser->begin(115200, SERIAL_8N1);
|
||||
@ -76,9 +83,7 @@ void setup() {
|
||||
|
||||
if (vcc > 0 && vcc < 3.1) {
|
||||
if(debugger) {
|
||||
debugger->print("Voltage is too low: ");
|
||||
debugger->print(vcc);
|
||||
debugger->println("mV");
|
||||
debugger->println("Voltage is too low, sleeping");
|
||||
debugger->flush();
|
||||
}
|
||||
ESP.deepSleep(10000000); //Deep sleep to allow output cap to charge up
|
||||
@ -88,20 +93,15 @@ void setup() {
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
pinMode(AP_BUTTON_PIN, INPUT_PULLUP);
|
||||
|
||||
led_off();
|
||||
|
||||
WiFi.disconnect(true);
|
||||
WiFi.softAPdisconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
|
||||
if(debugger) {
|
||||
if(hasTempSensor) {
|
||||
debugger->println("Has temp sensor");
|
||||
} else {
|
||||
debugger->println("No temp sensor found");
|
||||
}
|
||||
}
|
||||
|
||||
if(config.hasConfig()) {
|
||||
if(debugger) config.print(debugger);
|
||||
WiFi_connect();
|
||||
client = new WiFiClient();
|
||||
} else {
|
||||
if(debugger) {
|
||||
@ -116,7 +116,6 @@ void setup() {
|
||||
} else {
|
||||
hanSerial->begin(2400, SWSERIAL_8E1);
|
||||
}
|
||||
#elif defined DEBUG_MODE
|
||||
#else
|
||||
if(config.getMeterType() == 3) {
|
||||
hanSerial->begin(2400, SERIAL_8N1);
|
||||
@ -143,14 +142,18 @@ bool longPressActive = false;
|
||||
|
||||
bool wifiConnected = false;
|
||||
|
||||
unsigned long lastTemperatureRead = 0;
|
||||
double temperature = -127;
|
||||
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
if (digitalRead(AP_BUTTON_PIN) == LOW) {
|
||||
if (buttonActive == false) {
|
||||
buttonActive = true;
|
||||
buttonTimer = millis();
|
||||
buttonTimer = now;
|
||||
}
|
||||
|
||||
if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) {
|
||||
if ((now - buttonTimer > longPressTime) && (longPressActive == false)) {
|
||||
longPressActive = true;
|
||||
swapWifiMode();
|
||||
}
|
||||
@ -165,6 +168,11 @@ void loop() {
|
||||
}
|
||||
}
|
||||
|
||||
if(now - lastTemperatureRead > 10000) {
|
||||
temperature = hw.getTemperature();
|
||||
lastTemperatureRead = now;
|
||||
}
|
||||
|
||||
// Only do normal stuff if we're not booted as AP
|
||||
if (WiFi.getMode() != WIFI_AP) {
|
||||
// Turn off the LED
|
||||
@ -181,29 +189,20 @@ void loop() {
|
||||
}
|
||||
if (!config.getMqttHost().isEmpty()) {
|
||||
mqtt.loop();
|
||||
yield();
|
||||
delay(10);
|
||||
if(!mqtt.connected() || config.isMqttChanged()) {
|
||||
MQTT_connect();
|
||||
}
|
||||
} else if(mqtt.connected()) {
|
||||
mqtt.disconnect();
|
||||
yield();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dnsServer.processNextRequest();
|
||||
// Continously flash the LED when AP mode
|
||||
if (millis() / 50 % 64 == 0) led_on();
|
||||
if (now / 50 % 64 == 0) led_on();
|
||||
else led_off();
|
||||
|
||||
// Make sure there is enough power to run
|
||||
double vcc = hw.getVcc();
|
||||
if(vcc > 0) {
|
||||
delay(max(10, 3500-(int)(vcc*1000)));
|
||||
} else {
|
||||
delay(10);
|
||||
}
|
||||
|
||||
}
|
||||
readHanPort();
|
||||
ws.loop();
|
||||
@ -239,7 +238,7 @@ void swapWifiMode() {
|
||||
WiFi.mode(WIFI_OFF);
|
||||
yield();
|
||||
|
||||
if (mode != WIFI_AP) {
|
||||
if (mode != WIFI_AP || !config.hasConfig()) {
|
||||
if(debugger) debugger->println("Swapping to AP mode");
|
||||
WiFi.softAP("AMS2MQTT");
|
||||
WiFi.mode(WIFI_AP);
|
||||
@ -298,9 +297,8 @@ void readHanPort() {
|
||||
float rssi = WiFi.RSSI();
|
||||
rssi = isnan(rssi) ? -100.0 : rssi;
|
||||
json["rssi"] = rssi;
|
||||
double temp = hw.getTemperature();
|
||||
if(temp != -127) {
|
||||
json["temp"] = temp;
|
||||
if(temperature != -127) {
|
||||
json["temp"] = temperature;
|
||||
}
|
||||
|
||||
// Add a sub-structure to the json object,
|
||||
@ -406,6 +404,7 @@ void WiFi_connect() {
|
||||
|
||||
WiFi.enableAP(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
// WiFi.setOutputPower(0);
|
||||
if(!config.getWifiIp().isEmpty()) {
|
||||
IPAddress ip, gw, sn(255,255,255,0);
|
||||
ip.fromString(config.getWifiIp());
|
||||
|
||||
@ -23,10 +23,10 @@ void AmsWebServer::setup(AmsConfiguration* config, Stream* debugger, MQTTClient*
|
||||
this->mqtt = mqtt;
|
||||
|
||||
server.on("/", std::bind(&AmsWebServer::indexHtml, this));
|
||||
server.on("/config/meter", std::bind(&AmsWebServer::configMeterHtml, this));
|
||||
server.on("/config/wifi", std::bind(&AmsWebServer::configWifiHtml, this));
|
||||
server.on("/config/mqtt", std::bind(&AmsWebServer::configMqttHtml, this));
|
||||
server.on("/config/web", std::bind(&AmsWebServer::configWebHtml, this));
|
||||
server.on("/config-meter", std::bind(&AmsWebServer::configMeterHtml, this));
|
||||
server.on("/config-wifi", std::bind(&AmsWebServer::configWifiHtml, this));
|
||||
server.on("/config-mqtt", std::bind(&AmsWebServer::configMqttHtml, this));
|
||||
server.on("/config-web", std::bind(&AmsWebServer::configWebHtml, 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));
|
||||
@ -57,14 +57,15 @@ void AmsWebServer::setJson(StaticJsonDocument<1024> json) {
|
||||
u3 = json["data"]["U3"].as<double>();
|
||||
i3 = json["data"]["I3"].as<double>();
|
||||
}
|
||||
}
|
||||
|
||||
if(maxPwr == 0 && config->hasConfig() && config->getMainFuse() > 0 && config->getDistributionSystem() > 0) {
|
||||
int volt = config->getDistributionSystem() == 2 ? 400 : 230;
|
||||
if(u2 > 0) {
|
||||
maxPwr = config->getMainFuse() * sqrt(3) * volt;
|
||||
} else {
|
||||
maxPwr = config->getMainFuse() * 230;
|
||||
// Only way to determine if you have more than one phase is to run this code here
|
||||
if(maxPwr == 0 && config->hasConfig() && config->getMainFuse() > 0 && config->getDistributionSystem() > 0) {
|
||||
int volt = config->getDistributionSystem() == 2 ? 400 : 230;
|
||||
if(u2 > 0) {
|
||||
maxPwr = config->getMainFuse() * sqrt(3) * volt;
|
||||
} else {
|
||||
maxPwr = config->getMainFuse() * 230;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,8 +303,6 @@ void AmsWebServer::dataJson() {
|
||||
|
||||
String jsonStr;
|
||||
if(!this->json.isNull() && this->json.containsKey("data")) {
|
||||
println(" json has data");
|
||||
|
||||
int maxPwr = this->maxPwr;
|
||||
if(maxPwr == 0) {
|
||||
if(u2 > 0) {
|
||||
@ -312,18 +311,20 @@ void AmsWebServer::dataJson() {
|
||||
maxPwr = 10000;
|
||||
}
|
||||
}
|
||||
int maxPrd = config->getProductionCapacity() * 1000;
|
||||
|
||||
json["up"] = this->json["up"];
|
||||
json["t"] = this->json["t"];
|
||||
json["data"] = this->json["data"];
|
||||
|
||||
json["p_pct"] = min(p*100/maxPwr, 100);
|
||||
json["po_pct"] = min(po*100/maxPrd, 100);
|
||||
json["p_pct"] = min(p*100/maxPwr, 100);
|
||||
|
||||
if(config->getProductionCapacity() > 0) {
|
||||
int maxPrd = config->getProductionCapacity() * 1000;
|
||||
json["po_pct"] = min(po*100/maxPrd, 100);
|
||||
}
|
||||
} else {
|
||||
json["p_pct"] = -1;
|
||||
json["po_pct"] = -1;
|
||||
println(" json is empty");
|
||||
json["p_pct"] = -1;
|
||||
json["po_pct"] = -1;
|
||||
}
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
206
web/boot.css
206
web/boot.css
@ -1,3 +1,15 @@
|
||||
/* Common custom style */
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.navbar .navbar-nav-svg {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@ -62,6 +74,9 @@ body {
|
||||
.mb-0, .my-0 {
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
.m-2 {
|
||||
margin: .5rem!important;
|
||||
}
|
||||
.mb-2, .my-2 {
|
||||
margin-bottom: .5rem!important;
|
||||
}
|
||||
@ -92,7 +107,8 @@ body {
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #dee2e6!important;
|
||||
}.rounded {
|
||||
}
|
||||
.rounded {
|
||||
border-radius: .25rem!important;
|
||||
}
|
||||
div {
|
||||
@ -140,10 +156,6 @@ h1, h2, h3, h4, h5, h6 {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
.d-flex {
|
||||
display: -ms-flexbox!important;
|
||||
display: flex!important;
|
||||
}
|
||||
.col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-auto, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-auto, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-auto, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-auto, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@ -185,6 +197,22 @@ h1, h2, h3, h4, h5, h6 {
|
||||
flex: 0 0 75%;
|
||||
max-width: 75%;
|
||||
}
|
||||
.d-none {
|
||||
display: none!important;
|
||||
}
|
||||
.d-flex {
|
||||
display: -ms-flexbox!important;
|
||||
display: flex!important;
|
||||
}
|
||||
.flex-row {
|
||||
-ms-flex-direction: row!important;
|
||||
flex-direction: row!important;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
-ms-flex-direction: column!important;
|
||||
flex-direction: column!important;
|
||||
}
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
@ -218,6 +246,92 @@ a {
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
.navbar {
|
||||
position: relative;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
.navbar-dark .navbar-brand {
|
||||
color: #fff;
|
||||
}
|
||||
.navbar-expand {
|
||||
-ms-flex-flow: row nowrap;
|
||||
flex-flow: row nowrap;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.navbar-nav {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.navbar-expand .navbar-nav {
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
}
|
||||
.navbar-brand {
|
||||
display: inline-block;
|
||||
padding-top: .3125rem;
|
||||
padding-bottom: .3125rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
line-height: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.navbar-dark .navbar-nav .nav-link {
|
||||
color: rgba(255,255,255,.5);
|
||||
}
|
||||
.navbar-expand .navbar-nav .nav-link {
|
||||
padding-right: .5rem;
|
||||
padding-left: .5rem;
|
||||
}
|
||||
.navbar-nav .nav-link {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.nav-link {
|
||||
display: block;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: .25em .4em;
|
||||
font-size: 75%;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: .25rem;
|
||||
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||
}
|
||||
.badge-secondary {
|
||||
color: #fff;
|
||||
background-color: #6c757d;
|
||||
}
|
||||
.badge-success {
|
||||
color: #fff;
|
||||
background-color: #28a745;
|
||||
}
|
||||
.badge-warning {
|
||||
color: #212529;
|
||||
background-color: #ffc107;
|
||||
}
|
||||
.badge-danger {
|
||||
color: #fff;
|
||||
background-color: #dc3545;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@ -256,6 +370,55 @@ input[type="radio"], input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
.input-group {
|
||||
position: relative;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-ms-flex-align: stretch;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.input-group-append {
|
||||
margin-left: -1px;
|
||||
}
|
||||
.input-group-append, .input-group-prepend {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.input-group>.input-group-append>.btn, .input-group>.input-group-append>.input-group-text, .input-group>.input-group-prepend:first-child>.btn:not(:first-child), .input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child), .input-group>.input-group-prepend:not(:first-child)>.btn, .input-group>.input-group-prepend:not(:first-child)>.input-group-text {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.input-group-text {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding: .375rem .75rem;
|
||||
margin-bottom: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #495057;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
background-color: #e9ecef;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: .25rem;
|
||||
}
|
||||
.input-group>.custom-select:not(:last-child), .input-group>.form-control:not(:last-child) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.input-group>.custom-file, .input-group>.custom-select, .input-group>.form-control, .input-group>.form-control-plaintext {
|
||||
position: relative;
|
||||
-ms-flex: 1 1 0%;
|
||||
flex: 1 1 0%;
|
||||
min-width: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
hr {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
@ -265,6 +428,23 @@ hr {
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
ul {
|
||||
display: block;
|
||||
list-style-type: disc;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
padding-inline-start: 40px;
|
||||
}
|
||||
li {
|
||||
display: list-item;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
dl, ol, ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.container, .container-sm {
|
||||
@ -275,6 +455,11 @@ hr {
|
||||
.container, .container-md, .container-sm {
|
||||
max-width: 720px;
|
||||
}
|
||||
.col-md-3 {
|
||||
-ms-flex: 0 0 25%;
|
||||
flex: 0 0 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
.col-md-4 {
|
||||
-ms-flex: 0 0 33.333333%;
|
||||
flex: 0 0 33.333333%;
|
||||
@ -285,6 +470,17 @@ hr {
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
.d-md-flex {
|
||||
display: -ms-flexbox!important;
|
||||
display: flex!important;
|
||||
}
|
||||
.flex-md-row {
|
||||
-ms-flex-direction: row!important;
|
||||
flex-direction: row!important;
|
||||
}
|
||||
.ml-md-auto, .mx-md-auto {
|
||||
margin-left: auto!important;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.container, .container-lg, .container-md, .container-sm {
|
||||
|
||||
@ -6,18 +6,6 @@
|
||||
<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.min.css"/>
|
||||
<style>
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.navbar .navbar-nav-svg {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
@ -26,16 +14,16 @@
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config/meter">Meter</a>
|
||||
<a class="nav-link active" href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/wifi">WiFi</a>
|
||||
<a class="nav-link " href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/mqtt">MQTT</a>
|
||||
<a class="nav-link " href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/web">Web</a>
|
||||
<a class="nav-link " href="/config-web">Web</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -7,18 +7,6 @@
|
||||
<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.min.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<style>
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.navbar .navbar-nav-svg {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
@ -27,16 +15,16 @@
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/meter">Meter</a>
|
||||
<a class="nav-link " href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/wifi">WiFi</a>
|
||||
<a class="nav-link " href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config/mqtt">MQTT</a>
|
||||
<a class="nav-link active" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/web">Web</a>
|
||||
<a class="nav-link " href="/config-web">Web</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -7,18 +7,6 @@
|
||||
<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.min.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<style>
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.navbar .navbar-nav-svg {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
@ -27,16 +15,16 @@
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config/meter">Meter</a>
|
||||
<a class="nav-link" href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/wifi">WiFi</a>
|
||||
<a class="nav-link " href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/mqtt">MQTT</a>
|
||||
<a class="nav-link " href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config/web">Web</a>
|
||||
<a class="nav-link active" href="/config-web">Web</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -7,18 +7,6 @@
|
||||
<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.min.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<style>
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.navbar .navbar-nav-svg {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
@ -27,16 +15,16 @@
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/meter">Meter</a>
|
||||
<a class="nav-link " href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config/wifi">WiFi</a>
|
||||
<a class="nav-link active" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/mqtt">MQTT</a>
|
||||
<a class="nav-link " href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/web">Web</a>
|
||||
<a class="nav-link " href="/config-web">Web</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -10,17 +10,6 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
|
||||
<script src="gaugemeter.js"></script>
|
||||
<style>
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.navbar .navbar-nav-svg {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.GaugeMeter {
|
||||
position: Relative;
|
||||
text-align: Center;
|
||||
@ -69,16 +58,16 @@
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/meter">Meter</a>
|
||||
<a class="nav-link " href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/wifi">WiFi</a>
|
||||
<a class="nav-link " href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/mqtt">MQTT</a>
|
||||
<a class="nav-link " href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config/web">Web</a>
|
||||
<a class="nav-link " href="/config-web">Web</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -218,7 +207,16 @@ pm.gaugeMeter({
|
||||
append: "W"
|
||||
});
|
||||
|
||||
var interval = 2500;
|
||||
var setStatus = function(id, status) {
|
||||
var item = $('#'+id);
|
||||
item.removeClass('d-none');
|
||||
item.removeClass (function (index, className) {
|
||||
return (className.match (/(^|\s)badge-\S+/g) || []).join(' ');
|
||||
});
|
||||
item.addClass('badge badge-' + status);
|
||||
};
|
||||
|
||||
var interval = 10000;
|
||||
var fetch = function() {
|
||||
$.ajax({
|
||||
url: '/data.json',
|
||||
@ -248,13 +246,7 @@ var fetch = function() {
|
||||
|
||||
if(json.status) {
|
||||
for(var id in json.status) {
|
||||
var badge = json.status[id];
|
||||
var item = $('#'+id);
|
||||
item.removeClass('d-none');
|
||||
item.removeClass (function (index, className) {
|
||||
return (className.match (/(^|\s)badge-\S+/g) || []).join(' ');
|
||||
});
|
||||
item.addClass('badge badge-'+badge);
|
||||
setStatus(id, json.status[id]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,6 +328,8 @@ var fetch = function() {
|
||||
}
|
||||
setTimeout(fetch, interval);
|
||||
}).fail(function() {
|
||||
setTimeout(fetch, interval*4);
|
||||
|
||||
cm.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
@ -347,7 +341,11 @@ var fetch = function() {
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
setTimeout(fetch, interval*4);
|
||||
|
||||
setStatus("mqtt", "secondary");
|
||||
setStatus("wifi", "secondary");
|
||||
setStatus("han", "secondary");
|
||||
setStatus("esp", "danger");
|
||||
});
|
||||
}
|
||||
fetch();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user