mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-10 04:45:12 +00:00
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
- web/**
|
||||
- platformio.ini
|
||||
branches:
|
||||
- master
|
||||
- '*'
|
||||
tags:
|
||||
- '*'
|
||||
- '!v*.*.*'
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
pip install -U platformio css_html_js_minify
|
||||
- name: Configure build targets
|
||||
run: echo "[platformio]\ndefault_envs = hw1esp12e, esp12e, esp32" > platformio-user.ini
|
||||
- name: PlatformIO lib install
|
||||
|
||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -U platformio
|
||||
pip install -U platformio css_html_js_minify
|
||||
- name: PlatformIO lib install
|
||||
run: pio lib install
|
||||
- name: PlatformIO run
|
||||
@@ -109,3 +109,21 @@ jobs:
|
||||
asset_path: .pio/build/featheresp32/firmware.bin
|
||||
asset_name: ams2mqtt-featheresp32-${{ steps.release_tag.outputs.tag }}.bin
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload azdevkit4 binary to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: .pio/build/az-delivery-devkit-v4/firmware.bin
|
||||
asset_name: ams2mqtt-azdevkit4-${{ steps.release_tag.outputs.tag }}.bin
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Upload doitdevkit1 binary to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: .pio/build/esp32doit-devkit-v1/firmware.bin
|
||||
asset_name: ams2mqtt-doitdevkit1-${{ steps.release_tag.outputs.tag }}.bin
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "HanReader.h"
|
||||
|
||||
HanReader::HanReader()
|
||||
{
|
||||
HanReader::HanReader() {
|
||||
// Central European Time (Frankfurt, Paris)
|
||||
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time
|
||||
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time
|
||||
localZone = new Timezone(CEST, CET);
|
||||
}
|
||||
|
||||
void HanReader::setup(Stream *hanPort, RemoteDebug *debug)
|
||||
@@ -10,11 +13,6 @@ void HanReader::setup(Stream *hanPort, RemoteDebug *debug)
|
||||
bytesRead = 0;
|
||||
debugger = debug;
|
||||
|
||||
// Central European Time (Frankfurt, Paris)
|
||||
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120}; // Central European Summer Time
|
||||
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60}; // Central European Standard Time
|
||||
localZone = new Timezone(CEST, CET);
|
||||
|
||||
if (debug) debug->println("MBUS serial setup complete");
|
||||
}
|
||||
|
||||
@@ -112,6 +110,12 @@ String HanReader::getString(int objectId) {
|
||||
return getString(objectId, buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
int HanReader::getBuffer(byte* buf) {
|
||||
for (int i = 0; i < bytesRead; i++) {
|
||||
buf[i] = buffer[i];
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int HanReader::findValuePosition(int dataPosition, byte *buffer, int start, int length) {
|
||||
// The first byte after the header gives the length
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
uint32_t getUint(int objectId); // Only for uint32
|
||||
String getString(int objectId);
|
||||
time_t getTime(int objectId);
|
||||
int getBuffer(byte* buf);
|
||||
|
||||
private:
|
||||
RemoteDebug* debugger;
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
|
||||
enum class Kamstrup
|
||||
{
|
||||
List1PhaseShort = 0x11,
|
||||
List1PhaseLong = 0x1B,
|
||||
List3PhaseShort = 0x19,
|
||||
List3PhaseLong = 0x23,
|
||||
List1PhaseShort = 0x11,
|
||||
List1PhaseLong = 0x1B
|
||||
List3PhaseITShort = 0x17,
|
||||
List3PhaseITLong = 0x21
|
||||
};
|
||||
|
||||
enum class Kamstrup_List3Phase
|
||||
@@ -83,5 +85,43 @@ enum class Kamstrup_List1Phase
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
enum class Kamstrup_List3PhaseIT
|
||||
{
|
||||
ListSize,
|
||||
ListVersionIdentifier,
|
||||
MeterID_OBIS,
|
||||
MeterID,
|
||||
MeterType_OBIS,
|
||||
MeterType,
|
||||
ActiveImportPower_OBIS,
|
||||
ActiveImportPower,
|
||||
ActiveExportPower_OBIS,
|
||||
ActiveExportPower,
|
||||
ReactiveImportPower_OBIS,
|
||||
ReactiveImportPower,
|
||||
ReactiveExportPower_OBIS,
|
||||
ReactiveExportPower,
|
||||
CurrentL1_OBIS,
|
||||
CurrentL1,
|
||||
CurrentL3_OBIS,
|
||||
CurrentL3,
|
||||
VoltageL1_OBIS,
|
||||
VoltageL1,
|
||||
VoltageL2_OBIS,
|
||||
VoltageL2,
|
||||
VoltageL3_OBIS,
|
||||
VoltageL3,
|
||||
MeterClock_OBIS,
|
||||
MeterClock,
|
||||
CumulativeActiveImportEnergy_OBIS,
|
||||
CumulativeActiveImportEnergy,
|
||||
CumulativeActiveExportEnergy_OBIS,
|
||||
CumulativeActiveExportEnergy,
|
||||
CumulativeReactiveImportEnergy_OBIS,
|
||||
CumulativeReactiveImportEnergy,
|
||||
CumulativeReactiveExportEnergy_OBIS,
|
||||
CumulativeReactiveExportEnergy
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ framework = arduino
|
||||
lib_deps = HanReader@1.0.1, ArduinoJson@6.14.1, MQTT@2.4.7, DallasTemperature@3.8.1, EspSoftwareSerial@6.7.1, Base64@1.0.0, RemoteDebug@3.0.5, Time@1.6
|
||||
|
||||
[env:hw1esp12e]
|
||||
platform = espressif8266@2.3.3
|
||||
platform = espressif8266@2.5.1
|
||||
board = esp12e
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
@@ -18,7 +18,7 @@ extra_scripts =
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:esp12e]
|
||||
platform = espressif8266@2.3.3
|
||||
platform = espressif8266@2.5.1
|
||||
board = esp12e
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
@@ -27,7 +27,7 @@ extra_scripts =
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:d1mini]
|
||||
platform = espressif8266@2.3.3
|
||||
platform = espressif8266@2.5.1
|
||||
board = d1_mini
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
@@ -36,7 +36,7 @@ extra_scripts =
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:esp32]
|
||||
platform = espressif32@1.11.2
|
||||
platform = espressif32@1.12.1
|
||||
board = esp32dev
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
@@ -45,7 +45,7 @@ extra_scripts =
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:lolind32]
|
||||
platform = espressif32@1.11.2
|
||||
platform = espressif32@1.12.1
|
||||
board = lolin_d32
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
@@ -54,10 +54,28 @@ extra_scripts =
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:featheresp32]
|
||||
platform = espressif32@1.11.2
|
||||
platform = espressif32@1.12.1
|
||||
board = featheresp32
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
extra_scripts =
|
||||
pre:scripts/addversion.py
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:az-delivery-devkit-v4]
|
||||
platform = espressif32@1.12.1
|
||||
board = az-delivery-devkit-v4
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
extra_scripts =
|
||||
pre:scripts/addversion.py
|
||||
scripts/makeweb.py
|
||||
|
||||
[env:esp32doit-devkit-v1]
|
||||
platform = espressif32@1.12.1
|
||||
board = esp32doit-devkit-v1
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
extra_scripts =
|
||||
pre:scripts/addversion.py
|
||||
scripts/makeweb.py
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from css_html_js_minify import html_minify, js_minify, css_minify
|
||||
|
||||
webroot = "web"
|
||||
srcroot = "src/web/root"
|
||||
|
||||
version = os.environ.get('GITHUB_TAG')
|
||||
if version == None:
|
||||
version = "SNAPSHOT"
|
||||
|
||||
if os.path.exists(srcroot):
|
||||
shutil.rmtree(srcroot)
|
||||
@@ -20,11 +24,25 @@ for filename in os.listdir(webroot):
|
||||
|
||||
varname = basename.upper()
|
||||
|
||||
with open(srcfile, encoding="utf-8") as f:
|
||||
content = f.read().replace("${version}", version)
|
||||
|
||||
if filename.endswith(".html"):
|
||||
content = html_minify(content)
|
||||
elif filename.endswith(".css"):
|
||||
content = css_minify(content)
|
||||
elif filename.endswith(".js") and filename != 'gaugemeter.js':
|
||||
content = js_minify(content)
|
||||
|
||||
with open(dstfile, "w") as dst:
|
||||
dst.write("const char ")
|
||||
dst.write(varname)
|
||||
dst.write("[] PROGMEM = R\"==\"==(\n")
|
||||
with open(srcfile, "r") as src:
|
||||
for line in src.readlines():
|
||||
dst.write(line)
|
||||
dst.write("\n)==\"==\";\n")
|
||||
dst.write("[] PROGMEM = R\"==\"==(")
|
||||
dst.write(content)
|
||||
dst.write(")==\"==\";\n")
|
||||
dst.write("const int ");
|
||||
dst.write(varname)
|
||||
dst.write("_LEN = ");
|
||||
dst.write(str(len(content)))
|
||||
dst.write(";");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,59 @@
|
||||
#include <EEPROM.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
struct ConfigObject {
|
||||
uint8_t boardType;
|
||||
char wifiSsid[32];
|
||||
char wifiPassword[64];
|
||||
char wifiIp[15];
|
||||
char wifiGw[15];
|
||||
char wifiSubnet[15];
|
||||
char wifiDns1[15];
|
||||
char wifiDns2[15];
|
||||
char wifiHostname[32];
|
||||
char mqttHost[128];
|
||||
uint16_t mqttPort;
|
||||
char mqttClientId[32];
|
||||
char mqttPublishTopic[64];
|
||||
char mqttSubscribeTopic[64];
|
||||
char mqttUser[64];
|
||||
char mqttPassword[64];
|
||||
uint8_t mqttPayloadFormat;
|
||||
bool mqttSsl;
|
||||
uint8_t authSecurity;
|
||||
char authUser[64];
|
||||
char authPassword[64];
|
||||
uint8_t meterType;
|
||||
uint8_t distributionSystem;
|
||||
uint8_t mainFuse;
|
||||
uint8_t productionCapacity;
|
||||
bool substituteMissing;
|
||||
bool sendUnknown;
|
||||
|
||||
bool debugTelnet;
|
||||
bool debugSerial;
|
||||
uint8_t debugLevel;
|
||||
|
||||
uint8_t hanPin;
|
||||
uint8_t apPin;
|
||||
uint8_t ledPin;
|
||||
bool ledInverted;
|
||||
uint8_t ledPinRed;
|
||||
uint8_t ledPinGreen;
|
||||
uint8_t ledPinBlue;
|
||||
bool ledRgbInverted;
|
||||
uint8_t tempSensorPin;
|
||||
uint8_t vccPin;
|
||||
uint16_t vccMultiplier;
|
||||
uint8_t vccBootLimit;
|
||||
|
||||
uint16_t domoELIDX;
|
||||
uint16_t domoVL1IDX;
|
||||
uint16_t domoVL2IDX;
|
||||
uint16_t domoVL3IDX;
|
||||
uint16_t domoCL1IDX;
|
||||
};
|
||||
|
||||
class AmsConfiguration {
|
||||
public:
|
||||
bool hasConfig();
|
||||
@@ -10,128 +63,200 @@ public:
|
||||
|
||||
bool load();
|
||||
bool save();
|
||||
|
||||
uint8_t getBoardType();
|
||||
void setBoardType(uint8_t boardType);
|
||||
|
||||
String getWifiSsid();
|
||||
void setWifiSsid(String wifiSsid);
|
||||
String getWifiPassword();
|
||||
void setWifiPassword(String wifiPassword);
|
||||
String getWifiIp();
|
||||
void setWifiIp(String wifiIp);
|
||||
String getWifiGw();
|
||||
void setWifiGw(String wifiGw);
|
||||
String getWifiSubnet();
|
||||
void setWifiSubnet(String wifiSubnet);
|
||||
String getWifiDns1();
|
||||
void setWifiDns1(String wifiDns1);
|
||||
String getWifiDns2();
|
||||
void setWifiDns2(String wifiDns1);
|
||||
String getWifiHostname();
|
||||
void setWifiHostname(String wifiHostname);
|
||||
char* getWifiSsid();
|
||||
void setWifiSsid(const char* wifiSsid);
|
||||
char* getWifiPassword();
|
||||
void setWifiPassword(const char* wifiPassword);
|
||||
char* getWifiIp();
|
||||
void setWifiIp(const char* wifiIp);
|
||||
char* getWifiGw();
|
||||
void setWifiGw(const char* wifiGw);
|
||||
char* getWifiSubnet();
|
||||
void setWifiSubnet(const char* wifiSubnet);
|
||||
char* getWifiDns1();
|
||||
void setWifiDns1(const char* wifiDns1);
|
||||
char* getWifiDns2();
|
||||
void setWifiDns2(const char* wifiDns1);
|
||||
char* getWifiHostname();
|
||||
void setWifiHostname(const char* wifiHostname);
|
||||
void clearWifi();
|
||||
void clearWifiIp();
|
||||
|
||||
bool isWifiChanged();
|
||||
void ackWifiChange();
|
||||
|
||||
String getMqttHost();
|
||||
void setMqttHost(String mqttHost);
|
||||
int getMqttPort();
|
||||
void setMqttPort(int mqttPort);
|
||||
String getMqttClientId();
|
||||
void setMqttClientId(String mqttClientId);
|
||||
String getMqttPublishTopic();
|
||||
void setMqttPublishTopic(String mqttPublishTopic);
|
||||
String getMqttSubscribeTopic();
|
||||
void setMqttSubscribeTopic(String mqttSubscribeTopic);
|
||||
String getMqttUser();
|
||||
void setMqttUser(String mqttUser);
|
||||
String getMqttPassword();
|
||||
void setMqttPassword(String mqttPassword);
|
||||
int getMqttPayloadFormat();
|
||||
void setMqttPayloadFormat(int mqttPayloadFormat);
|
||||
char* getMqttHost();
|
||||
void setMqttHost(const char* mqttHost);
|
||||
uint16_t getMqttPort();
|
||||
void setMqttPort(uint16_t mqttPort);
|
||||
char* getMqttClientId();
|
||||
void setMqttClientId(const char* mqttClientId);
|
||||
char* getMqttPublishTopic();
|
||||
void setMqttPublishTopic(const char* mqttPublishTopic);
|
||||
char* getMqttSubscribeTopic();
|
||||
void setMqttSubscribeTopic(const char* mqttSubscribeTopic);
|
||||
char* getMqttUser();
|
||||
void setMqttUser(const char* mqttUser);
|
||||
char* getMqttPassword();
|
||||
void setMqttPassword(const char* mqttPassword);
|
||||
uint8_t getMqttPayloadFormat();
|
||||
void setMqttPayloadFormat(uint8_t mqttPayloadFormat);
|
||||
bool isMqttSsl();
|
||||
void setMqttSsl(bool mqttSsl);
|
||||
void clearMqtt();
|
||||
|
||||
void setMqttChanged();
|
||||
bool isMqttChanged();
|
||||
void ackMqttChange();
|
||||
|
||||
byte getAuthSecurity();
|
||||
void setAuthSecurity(byte authSecurity);
|
||||
String getAuthUser();
|
||||
void setAuthUser(String authUser);
|
||||
String getAuthPassword();
|
||||
void setAuthPassword(String authPassword);
|
||||
char* getAuthUser();
|
||||
void setAuthUser(const char* authUser);
|
||||
char* getAuthPassword();
|
||||
void setAuthPassword(const char* authPassword);
|
||||
void clearAuth();
|
||||
|
||||
int getMeterType();
|
||||
void setMeterType(int meterType);
|
||||
int getDistributionSystem();
|
||||
void setDistributionSystem(int distributionSystem);
|
||||
int getMainFuse();
|
||||
void setMainFuse(int mainFuse);
|
||||
int getProductionCapacity();
|
||||
void setProductionCapacity(int productionCapacity);
|
||||
uint8_t getMeterType();
|
||||
void setMeterType(uint8_t meterType);
|
||||
uint8_t getDistributionSystem();
|
||||
void setDistributionSystem(uint8_t distributionSystem);
|
||||
uint8_t getMainFuse();
|
||||
void setMainFuse(uint8_t mainFuse);
|
||||
uint8_t getProductionCapacity();
|
||||
void setProductionCapacity(uint8_t productionCapacity);
|
||||
bool isSubstituteMissing();
|
||||
void setSubstituteMissing(bool substituteMissing);
|
||||
bool isSendUnknown();
|
||||
void setSendUnknown(bool sendUnknown);
|
||||
void clearMeter();
|
||||
|
||||
bool isDebugTelnet();
|
||||
void setDebugTelnet(bool debugTelnet);
|
||||
bool isDebugSerial();
|
||||
void setDebugSerial(bool debugSerial);
|
||||
int getDebugLevel();
|
||||
void setDebugLevel(int debugLevel);
|
||||
uint8_t getDebugLevel();
|
||||
void setDebugLevel(uint8_t debugLevel);
|
||||
|
||||
bool pinUsed(uint8_t pin);
|
||||
|
||||
uint8_t getHanPin();
|
||||
void setHanPin(uint8_t hanPin);
|
||||
uint8_t getApPin();
|
||||
void setApPin(uint8_t apPin);
|
||||
uint8_t getLedPin();
|
||||
void setLedPin(uint8_t ledPin);
|
||||
bool isLedInverted();
|
||||
void setLedInverted(bool ledInverted);
|
||||
|
||||
uint8_t getLedPinRed();
|
||||
void setLedPinRed(uint8_t ledPinRed);
|
||||
uint8_t getLedPinGreen();
|
||||
void setLedPinGreen(uint8_t ledPinGreen);
|
||||
uint8_t getLedPinBlue();
|
||||
void setLedPinBlue(uint8_t ledPinBlue);
|
||||
bool isLedRgbInverted();
|
||||
void setLedRgbInverted(bool ledRgbInverted);
|
||||
|
||||
uint8_t getTempSensorPin();
|
||||
void setTempSensorPin(uint8_t tempSensorPin);
|
||||
uint8_t getVccPin();
|
||||
void setVccPin(uint8_t vccPin);
|
||||
double getVccMultiplier();
|
||||
void setVccMultiplier(double vccMultiplier);
|
||||
double getVccBootLimit();
|
||||
void setVccBootLimit(double vccBootLimit);
|
||||
|
||||
void print(Print* debugger);
|
||||
|
||||
|
||||
uint16_t getDomoELIDX();
|
||||
uint16_t getDomoVL1IDX();
|
||||
uint16_t getDomoVL2IDX();
|
||||
uint16_t getDomoVL3IDX();
|
||||
uint16_t getDomoCL1IDX();
|
||||
void setDomoELIDX(uint16_t domoELIDX);
|
||||
void setDomoVL1IDX(uint16_t domoVL1IDX);
|
||||
void setDomoVL2IDX(uint16_t domoVL2IDX);
|
||||
void setDomoVL3IDX(uint16_t domoVL3IDX);
|
||||
void setDomoCL1IDX(uint16_t domoCL1IDX);
|
||||
void clearDomo();
|
||||
|
||||
bool isDomoChanged();
|
||||
void ackDomoChange();
|
||||
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
int configVersion = 0;
|
||||
ConfigObject config {
|
||||
0, // Board type
|
||||
"", // SSID
|
||||
"", // PSK
|
||||
"", // IP
|
||||
"", // GW
|
||||
"", // Subnet
|
||||
"", // DNS 1
|
||||
"", // DNS 2
|
||||
"", // Hostname
|
||||
"", // MQTT host
|
||||
1883, // Port
|
||||
"", // Client ID
|
||||
"", // Publish topic
|
||||
"", // Subscribe topic
|
||||
"", // Username
|
||||
"", // Password
|
||||
0, // Format
|
||||
false, // SSL
|
||||
0, // Web security
|
||||
"", // Username
|
||||
"", // Password
|
||||
0, // Meter type
|
||||
0, // Distribution system
|
||||
0, // Main fuse
|
||||
0, // Production capacity
|
||||
false, // Substitute
|
||||
false, // Send unknown
|
||||
false, // Debug telnet
|
||||
false, // Debug serial
|
||||
5, // Debug level
|
||||
0x03, // HAN pin
|
||||
0xFF, // AP pin
|
||||
0x02, // LED pin
|
||||
true, // Inverted
|
||||
0xFF, // Red
|
||||
0xFF, // Green
|
||||
0xFF, // Blue
|
||||
true, // Inverted
|
||||
0xFF, // Temp sensor
|
||||
0xFF, // Vcc
|
||||
100, // Multiplier
|
||||
0, // Boot limit
|
||||
//Domoticz
|
||||
0, // ELIDX
|
||||
0, // VL1IDX
|
||||
0, // VL2IDX
|
||||
0, // VL3IDX
|
||||
0 // CL1IDX
|
||||
// 786 bytes
|
||||
};
|
||||
bool wifiChanged, mqttChanged, domoChanged;
|
||||
|
||||
String wifiSsid;
|
||||
String wifiPassword;
|
||||
String wifiIp;
|
||||
String wifiGw;
|
||||
String wifiSubnet;
|
||||
String wifiDns1;
|
||||
String wifiDns2;
|
||||
String wifiHostname;
|
||||
bool wifiChanged = false;
|
||||
|
||||
String mqttHost;
|
||||
int mqttPort = 1883;
|
||||
String mqttClientId;
|
||||
String mqttPublishTopic;
|
||||
String mqttSubscribeTopic;
|
||||
String mqttUser;
|
||||
String mqttPassword;
|
||||
int mqttPayloadFormat = 0;
|
||||
bool mqttChanged = false;
|
||||
|
||||
byte authSecurity;
|
||||
String authUser;
|
||||
String authPassword;
|
||||
|
||||
int meterType = 0, distributionSystem = 0, mainFuse = 0, productionCapacity = 0;
|
||||
|
||||
bool debugTelnet = false, debugSerial = false;
|
||||
int debugLevel = 3;
|
||||
|
||||
const int EEPROM_SIZE = 512;
|
||||
const int EEPROM_CHECK_SUM = 81; // Used to check if config is stored. Change if structure changes
|
||||
const int EEPROM_SIZE = 790; // Config size + 4 bytes for config version
|
||||
const int EEPROM_CHECK_SUM = 82; // Used to check if config is stored. Change if structure changes
|
||||
const int EEPROM_CONFIG_ADDRESS = 0;
|
||||
|
||||
bool loadConfig72(int address);
|
||||
bool loadConfig75(int address);
|
||||
bool loadConfig80(int address);
|
||||
bool loadConfig81(int address);
|
||||
|
||||
int saveString(int pAddress, const char* pString);
|
||||
int readString(int pAddress, char* pString[]);
|
||||
int saveInt(int pAddress, int pValue);
|
||||
int readInt(int pAddress, int *pValue);
|
||||
int saveBool(int pAddress, bool pValue);
|
||||
int readBool(int pAddress, bool *pValue);
|
||||
int saveByte(int pAddress, byte pValue);
|
||||
int readByte(int pAddress, byte *pValue);
|
||||
|
||||
template <class T> int writeAnything(int ee, const T& value);
|
||||
template <class T> int readAnything(int ee, T& value);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
AmsData::AmsData() {}
|
||||
|
||||
AmsData::AmsData(int meterType, HanReader& hanReader) {
|
||||
AmsData::AmsData(int meterType, bool substituteMissing, HanReader& hanReader) {
|
||||
lastUpdateMillis = millis();
|
||||
packageTimestamp = hanReader.getPackageTime();
|
||||
|
||||
@@ -15,10 +15,10 @@ AmsData::AmsData(int meterType, HanReader& hanReader) {
|
||||
extractFromKaifa(hanReader, listSize);
|
||||
break;
|
||||
case METER_TYPE_AIDON:
|
||||
extractFromAidon(hanReader, listSize);
|
||||
extractFromAidon(hanReader, listSize, substituteMissing);
|
||||
break;
|
||||
case METER_TYPE_KAMSTRUP:
|
||||
extractFromKamstrup(hanReader, listSize);
|
||||
extractFromKamstrup(hanReader, listSize, substituteMissing);
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -87,7 +87,7 @@ void AmsData::extractFromKaifa(HanReader& hanReader, int listSize) {
|
||||
}
|
||||
}
|
||||
|
||||
void AmsData::extractFromAidon(HanReader& hanReader, int listSize) {
|
||||
void AmsData::extractFromAidon(HanReader& hanReader, int listSize, bool substituteMissing) {
|
||||
switch(listSize) {
|
||||
case (int)Aidon::List1:
|
||||
listType = 1;
|
||||
@@ -168,19 +168,23 @@ void AmsData::extractFromAidon(HanReader& hanReader, int listSize) {
|
||||
l1voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL1)) / 10;
|
||||
l2voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL2)) / 10;
|
||||
l3voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL3)) / 10;
|
||||
//l2current = ((activeImportPower * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage;
|
||||
if(substituteMissing) {
|
||||
l2current = ((activeImportPower * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize) {
|
||||
void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize, bool substituteMissing) {
|
||||
switch(listSize) {
|
||||
case (int)Kamstrup::List3PhaseITShort:
|
||||
case (int)Kamstrup::List3PhaseShort:
|
||||
threePhase = true;
|
||||
case (int)Kamstrup::List1PhaseShort:
|
||||
listType = 2;
|
||||
break;
|
||||
case (int)Kamstrup::List3PhaseITLong:
|
||||
case (int)Kamstrup::List3PhaseLong:
|
||||
threePhase = true;
|
||||
case (int)Kamstrup::List1PhaseLong:
|
||||
@@ -189,6 +193,23 @@ void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize) {
|
||||
}
|
||||
|
||||
switch(listSize) {
|
||||
case (int)Kamstrup::List1PhaseLong:
|
||||
meterTimestamp = hanReader.getTime( (int)Kamstrup_List1Phase::MeterClock);
|
||||
activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveImportEnergy)) / 100;
|
||||
activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveExportEnergy)) / 100;
|
||||
reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveImportEnergy)) / 100;
|
||||
reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveExportEnergy)) / 100;
|
||||
case (int)Kamstrup::List1PhaseShort:
|
||||
listId = hanReader.getString( (int)Kamstrup_List1Phase::ListVersionIdentifier);
|
||||
meterId = hanReader.getString( (int)Kamstrup_List1Phase::MeterID);
|
||||
meterType = hanReader.getString( (int)Kamstrup_List1Phase::MeterType);
|
||||
activeImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveImportPower);
|
||||
reactiveImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveImportPower);
|
||||
activeExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveExportPower);
|
||||
reactiveExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveExportPower);
|
||||
l1current = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CurrentL1)) / 100;
|
||||
l1voltage = hanReader.getInt( (int)Kamstrup_List1Phase::VoltageL1);
|
||||
break;
|
||||
case (int)Kamstrup::List3PhaseLong:
|
||||
meterTimestamp = hanReader.getTime( (int)Kamstrup_List3Phase::MeterClock);
|
||||
activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100;
|
||||
@@ -210,22 +231,29 @@ void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize) {
|
||||
l2voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2);
|
||||
l3voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3);
|
||||
break;
|
||||
case (int)Kamstrup::List1PhaseLong:
|
||||
meterTimestamp = hanReader.getTime( (int)Kamstrup_List1Phase::MeterClock);
|
||||
activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveImportEnergy)) / 100;
|
||||
activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveExportEnergy)) / 100;
|
||||
reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveImportEnergy)) / 100;
|
||||
reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveExportEnergy)) / 100;
|
||||
case (int)Kamstrup::List1PhaseShort:
|
||||
listId = hanReader.getString( (int)Kamstrup_List1Phase::ListVersionIdentifier);
|
||||
meterId = hanReader.getString( (int)Kamstrup_List1Phase::MeterID);
|
||||
meterType = hanReader.getString( (int)Kamstrup_List1Phase::MeterType);
|
||||
activeImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveImportPower);
|
||||
reactiveImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveImportPower);
|
||||
activeExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveExportPower);
|
||||
reactiveExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveExportPower);
|
||||
l1current = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CurrentL1)) / 100;
|
||||
l1voltage = hanReader.getInt( (int)Kamstrup_List1Phase::VoltageL1);
|
||||
case (int)Kamstrup::List3PhaseITLong:
|
||||
meterTimestamp = hanReader.getTime( (int)Kamstrup_List3Phase::MeterClock);
|
||||
activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100;
|
||||
activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100;
|
||||
reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100;
|
||||
reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100;
|
||||
case (int)Kamstrup::List3PhaseITShort:
|
||||
listId = hanReader.getString( (int)Kamstrup_List3Phase::ListVersionIdentifier);
|
||||
meterId = hanReader.getString( (int)Kamstrup_List3Phase::MeterID);
|
||||
meterType = hanReader.getString( (int)Kamstrup_List3Phase::MeterType);
|
||||
activeImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveImportPower);
|
||||
reactiveImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveImportPower);
|
||||
activeExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveExportPower);
|
||||
reactiveExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveExportPower);
|
||||
l1current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL1)) / 100;
|
||||
l2current = 0;
|
||||
l3current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL3)) / 100;
|
||||
l1voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL1);
|
||||
l2voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2);
|
||||
l3voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3);
|
||||
if(substituteMissing) {
|
||||
l2current = ((activeImportPower * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
class AmsData {
|
||||
public:
|
||||
AmsData();
|
||||
AmsData(int meterType, HanReader& hanReader);
|
||||
AmsData(int meterType, bool substituteMissing, HanReader& hanReader);
|
||||
|
||||
void apply(AmsData& other);
|
||||
|
||||
@@ -60,8 +60,8 @@ private:
|
||||
bool threePhase = false;
|
||||
|
||||
void extractFromKaifa(HanReader& hanReader, int listSize);
|
||||
void extractFromAidon(HanReader& hanReader, int listSize);
|
||||
void extractFromKamstrup(HanReader& hanReader, int listSize);
|
||||
void extractFromAidon(HanReader& hanReader, int listSize, bool substituteMissing);
|
||||
void extractFromKamstrup(HanReader& hanReader, int listSize, bool substituteMissing);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
10
src/AmsStorage.h
Normal file
10
src/AmsStorage.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _AMSSTORAGE_H
|
||||
#define _AMSSTORAGE_H
|
||||
|
||||
#define FILE_FIRMWARE "/firmware.bin"
|
||||
|
||||
#define FILE_MQTT_CA "/mqtt-ca.pem"
|
||||
#define FILE_MQTT_CERT "/mqtt-cert.pem"
|
||||
#define FILE_MQTT_KEY "/mqtt-key.pem"
|
||||
|
||||
#endif
|
||||
@@ -5,73 +5,17 @@
|
||||
|
||||
#define INVALID_BUTTON_PIN 0xFFFFFFFF
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#elif defined(ESP32)
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include "SPIFFS.h"
|
||||
#include "Update.h"
|
||||
#endif
|
||||
|
||||
#define RGB_RED 1
|
||||
#define RGB_GREEN 2
|
||||
#define RGB_YELLOW 3
|
||||
#define RGB_ON 1
|
||||
#define RGB_OFF 0
|
||||
|
||||
// Build settings for custom hardware by Roar Fredriksen
|
||||
#if HW_ROARFRED
|
||||
#define LED_PIN 2 // The blue on-board LED of the ESP8266 custom AMS board
|
||||
#define LED_ACTIVE_HIGH 0
|
||||
#define AP_BUTTON_PIN 0
|
||||
|
||||
HardwareSerial *hanSerial = &Serial;
|
||||
|
||||
// Build settings for Wemos Lolin D32
|
||||
#elif defined(ARDUINO_LOLIN_D32)
|
||||
#define LED_PIN 5
|
||||
#define LED_ACTIVE_HIGH 0
|
||||
#define AP_BUTTON_PIN 4
|
||||
|
||||
HardwareSerial *hanSerial = &Serial2;
|
||||
|
||||
// Build settings for Wemos D1 mini
|
||||
#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI)
|
||||
#define LED_PIN D4
|
||||
#define LED_ACTIVE_HIGH 0
|
||||
#define AP_BUTTON_PIN D2
|
||||
|
||||
#define SOFTWARE_SERIAL 1
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial *hanSerial = new SoftwareSerial(D1);
|
||||
|
||||
// Build settings for Adafruit Feather ESP32
|
||||
#elif defined(ARDUINO_FEATHER_ESP32)
|
||||
#define LED_PIN LED_BUILTIN
|
||||
#define LED_ACTIVE_HIGH 1
|
||||
#define AP_BUTTON_PIN INVALID_BUTTON_PIN
|
||||
|
||||
HardwareSerial *hanSerial = &Serial2;
|
||||
|
||||
// Default build for ESP32
|
||||
#elif defined(ESP32)
|
||||
#define LED_PIN INVALID_BUTTON_PIN
|
||||
#define LED_ACTIVE_HIGH 1
|
||||
#define AP_BUTTON_PIN INVALID_BUTTON_PIN
|
||||
|
||||
HardwareSerial *hanSerial = &Serial2;
|
||||
|
||||
// Default build settings
|
||||
#else
|
||||
#define LED_PIN 2
|
||||
#define LED_ACTIVE_HIGH 0
|
||||
#define AP_BUTTON_PIN INVALID_BUTTON_PIN
|
||||
#define SOFTWARE_SERIAL 1
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial *hanSerial = new SoftwareSerial(5);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
#include "HanToJson.h"
|
||||
|
||||
void hanToJson(JsonDocument& json, AmsData& data, HwTools& hw, double temperature) {
|
||||
void hanToJson(JsonDocument& json, AmsData& data, HwTools& hw, double temperature, String name) {
|
||||
json["id"] = WiFi.macAddress();
|
||||
json["name"] = name;
|
||||
json["up"] = millis();
|
||||
json["t"] = data.getPackageTimestamp();
|
||||
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
#include "AmsData.h"
|
||||
#include "HwTools.h"
|
||||
|
||||
void hanToJson(JsonDocument& json, AmsData& data, HwTools& hw, double temperature);
|
||||
void hanToJson(JsonDocument& json, AmsData& data, HwTools& hw, double temperature, String name);
|
||||
|
||||
#endif
|
||||
|
||||
194
src/HwTools.cpp
194
src/HwTools.cpp
@@ -1,44 +1,184 @@
|
||||
#include "HwTools.h"
|
||||
|
||||
void HwTools::setTempSensorPin(int tempSensorPin) {
|
||||
if(tempSensorPin != this->tempSensorPin) {
|
||||
this->tempSensorInit = false;
|
||||
if(tempSensor)
|
||||
delete tempSensor;
|
||||
if(oneWire)
|
||||
delete oneWire;
|
||||
if(tempSensorPin > 0 && tempSensorPin < 40) {
|
||||
this->tempSensorPin = tempSensorPin;
|
||||
pinMode(tempSensorPin, INPUT);
|
||||
} else {
|
||||
this->tempSensorPin = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HwTools::setVccPin(int vccPin) {
|
||||
if(vccPin > 0 && vccPin < 40) {
|
||||
pinMode(vccPin, INPUT);
|
||||
this->vccPin = vccPin;
|
||||
} else {
|
||||
this->vccPin = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void HwTools::setVccMultiplier(double vccMultiplier) {
|
||||
this->vccMultiplier = vccMultiplier;
|
||||
}
|
||||
|
||||
double HwTools::getVcc() {
|
||||
double volts = 0.0;
|
||||
#if defined(ARDUINO_ESP8266_WEMOS_D1MINI)
|
||||
volts = (((double) ESP.getVcc()) / 900.0); // This board has a voltage divider on VCC.
|
||||
#elif defined(ARDUINO_LOLIN_D32)
|
||||
volts = (analogRead(GPIO_NUM_35) / 4095.0) * 3.3 * 2.25; // We are actually reading battery voltage here
|
||||
#elif defined(ESP8266)
|
||||
volts = ((double) ESP.getVcc()) / 1024.0;
|
||||
#endif
|
||||
if(vccPin != 0xFF) {
|
||||
#if defined(ESP8266)
|
||||
volts = (analogRead(vccPin) / 1024.0) * 3.3;
|
||||
#elif defined(ESP32)
|
||||
volts = (analogRead(vccPin) / 4095.0) * 3.3;
|
||||
#endif
|
||||
} else {
|
||||
#if defined(ESP8266)
|
||||
volts = ((double) ESP.getVcc()) / 1024.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ESP_VCC_CALIB_FACTOR)
|
||||
return volts * ESP_VCC_CALIB_FACTOR;
|
||||
#else
|
||||
return volts;
|
||||
#endif
|
||||
return volts > 0.0 ? volts * vccMultiplier : 0.0;
|
||||
}
|
||||
|
||||
double HwTools::getTemperature() {
|
||||
if(tempSensorPin != 0xFF) {
|
||||
if(!tempSensorInit) {
|
||||
oneWire = new OneWire(tempSensorPin);
|
||||
tempSensor = new DallasTemperature(this->oneWire);
|
||||
tempSensor->begin();
|
||||
delay(50);
|
||||
tempSensor->requestTemperatures();
|
||||
hasTempSensor = tempSensor->getTempCByIndex(0) != DEVICE_DISCONNECTED_C;
|
||||
tempSensorInit = true;
|
||||
}
|
||||
|
||||
#if defined TEMP_SENSOR_PIN
|
||||
if(!tempSensorInit) {
|
||||
tempSensor->begin();
|
||||
delay(50);
|
||||
tempSensor->requestTemperatures();
|
||||
hasTempSensor = tempSensor->getTempCByIndex(0) != DEVICE_DISCONNECTED_C;
|
||||
tempSensorInit = true;
|
||||
if(hasTempSensor) {
|
||||
tempSensor->requestTemperatures();
|
||||
return tempSensor->getTempCByIndex(0);
|
||||
} else {
|
||||
return DEVICE_DISCONNECTED_C;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasTempSensor) {
|
||||
tempSensor->requestTemperatures();
|
||||
return tempSensor->getTempCByIndex(0);
|
||||
} else {
|
||||
return DEVICE_DISCONNECTED_C;
|
||||
}
|
||||
#endif
|
||||
return DEVICE_DISCONNECTED_C;
|
||||
}
|
||||
|
||||
int HwTools::getWifiRssi() {
|
||||
int rssi = WiFi.RSSI();
|
||||
return isnan(rssi) ? -100.0 : rssi;
|
||||
}
|
||||
}
|
||||
|
||||
void HwTools::setLed(uint8_t ledPin, bool ledInverted) {
|
||||
if(ledPin > 0 && ledPin < 40) {
|
||||
this->ledPin = ledPin;
|
||||
this->ledInverted = ledInverted;
|
||||
pinMode(ledPin, OUTPUT);
|
||||
ledOff(LED_INTERNAL);
|
||||
} else {
|
||||
this->ledPin = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void HwTools::setLedRgb(uint8_t ledPinRed, uint8_t ledPinGreen, uint8_t ledPinBlue, bool ledRgbInverted) {
|
||||
this->ledRgbInverted = ledRgbInverted;
|
||||
if(ledPinRed > 0 && ledPinRed < 40) {
|
||||
this->ledPinRed = ledPinRed;
|
||||
pinMode(ledPinRed, OUTPUT);
|
||||
ledOff(LED_RED);
|
||||
} else {
|
||||
this->ledPinRed = 0xFF;
|
||||
}
|
||||
if(ledPinGreen > 0 && ledPinGreen < 40) {
|
||||
this->ledPinGreen = ledPinGreen;
|
||||
pinMode(ledPinGreen, OUTPUT);
|
||||
ledOff(LED_GREEN);
|
||||
} else {
|
||||
this->ledPinGreen = 0xFF;
|
||||
}
|
||||
if(ledPinBlue > 0 && ledPinBlue < 40) {
|
||||
this->ledPinBlue = ledPinBlue;
|
||||
pinMode(ledPinBlue, OUTPUT);
|
||||
ledOff(LED_BLUE);
|
||||
} else {
|
||||
this->ledPinBlue = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
bool HwTools::ledOn(uint8_t color) {
|
||||
if(color == LED_INTERNAL) {
|
||||
return writeLedPin(color, ledInverted ? LOW : HIGH);
|
||||
} else {
|
||||
return writeLedPin(color, ledRgbInverted ? LOW : HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
bool HwTools::ledOff(uint8_t color) {
|
||||
if(color == LED_INTERNAL) {
|
||||
return writeLedPin(color, ledInverted ? HIGH : LOW);
|
||||
} else {
|
||||
return writeLedPin(color, ledRgbInverted ? HIGH : LOW);
|
||||
}
|
||||
}
|
||||
|
||||
bool HwTools::ledBlink(uint8_t color, uint8_t blink) {
|
||||
for(int i = 0; i < blink; i++) {
|
||||
if(!ledOn(color)) return false;
|
||||
delay(50);
|
||||
ledOff(color);
|
||||
if(i != blink)
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
bool HwTools::writeLedPin(uint8_t color, uint8_t state) {
|
||||
switch(color) {
|
||||
case LED_INTERNAL:
|
||||
if(ledPin != 0xFF) {
|
||||
digitalWrite(ledPin, state);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case LED_RED:
|
||||
if(ledPinRed != 0xFF) {
|
||||
digitalWrite(ledPinRed, state);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case LED_GREEN:
|
||||
if(ledPinGreen != 0xFF) {
|
||||
digitalWrite(ledPinGreen, state);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case LED_BLUE:
|
||||
if(ledPinBlue != 0xFF) {
|
||||
digitalWrite(ledPinBlue, state);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case LED_YELLOW:
|
||||
if(ledPinRed != 0xFF && ledPinGreen != 0xFF) {
|
||||
digitalWrite(ledPinRed, state);
|
||||
digitalWrite(ledPinGreen, state);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,35 +12,38 @@
|
||||
#include <DallasTemperature.h>
|
||||
#include <OneWire.h>
|
||||
|
||||
#if HW_ROARFRED
|
||||
#define TEMP_SENSOR_PIN 5
|
||||
#elif defined(ARDUINO_LOLIN_D32)
|
||||
#define TEMP_SENSOR_PIN 14
|
||||
#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI)
|
||||
#define TEMP_SENSOR_PIN D5
|
||||
#else
|
||||
#define TEMP_SENSOR_PIN 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
|
||||
#define LED_INTERNAL 0
|
||||
#define LED_RED 1
|
||||
#define LED_GREEN 2
|
||||
#define LED_BLUE 3
|
||||
#define LED_YELLOW 4
|
||||
|
||||
class HwTools {
|
||||
public:
|
||||
void setTempSensorPin(int tempSensorPin);
|
||||
void setVccPin(int vccPin);
|
||||
void setVccMultiplier(double vccMultiplier);
|
||||
double getVcc();
|
||||
double getTemperature();
|
||||
int getWifiRssi();
|
||||
void setLed(uint8_t ledPin, bool ledInverted);
|
||||
void setLedRgb(uint8_t ledPinRed, uint8_t ledPinGreen, uint8_t ledPinBlue, bool ledRgbInverted);
|
||||
bool ledOn(uint8_t color);
|
||||
bool ledOff(uint8_t color);
|
||||
bool ledBlink(uint8_t color, uint8_t blink);
|
||||
|
||||
HwTools() {
|
||||
#if defined(ARDUINO_LOLIN_D32)
|
||||
pinMode(GPIO_NUM_35, INPUT);
|
||||
#endif
|
||||
oneWire = new OneWire(TEMP_SENSOR_PIN);
|
||||
tempSensor = new DallasTemperature(this->oneWire);
|
||||
};
|
||||
HwTools() {};
|
||||
private:
|
||||
uint8_t tempSensorPin = -1;
|
||||
uint8_t vccPin = -1;
|
||||
uint8_t ledPin = -1, ledPinRed = -1, ledPinGreen = -1, ledPinBlue = -1;
|
||||
bool ledInverted, ledRgbInverted;
|
||||
double vccMultiplier = 1.0;
|
||||
bool tempSensorInit, hasTempSensor;
|
||||
OneWire *oneWire;
|
||||
DallasTemperature *tempSensor;
|
||||
|
||||
bool writeLedPin(uint8_t color, uint8_t state);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,9 +20,11 @@
|
||||
#if defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266HTTPClient.h>
|
||||
#elif defined(ESP32) // ARDUINO_ARCH_ESP32
|
||||
#include <WiFi.h>
|
||||
#include <WebServer.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "SPIFFS.h"
|
||||
#include "Update.h"
|
||||
#else
|
||||
@@ -31,7 +33,7 @@
|
||||
|
||||
class AmsWebServer {
|
||||
public:
|
||||
AmsWebServer(RemoteDebug* Debug);
|
||||
AmsWebServer(RemoteDebug* Debug, HwTools* hw);
|
||||
void setup(AmsConfiguration* config, MQTTClient* mqtt);
|
||||
void loop();
|
||||
|
||||
@@ -40,11 +42,12 @@ public:
|
||||
private:
|
||||
RemoteDebug* debugger;
|
||||
int maxPwr = 0;
|
||||
HwTools hw;
|
||||
HwTools* hw;
|
||||
AmsConfiguration* config;
|
||||
AmsData data;
|
||||
MQTTClient* mqtt;
|
||||
File firmwareFile;
|
||||
bool uploading = false;
|
||||
File file;
|
||||
bool performRestart = false;
|
||||
|
||||
#if defined(ESP8266)
|
||||
@@ -56,22 +59,48 @@ private:
|
||||
bool checkSecurity(byte level);
|
||||
|
||||
void indexHtml();
|
||||
void applicationJs();
|
||||
void configMeterHtml();
|
||||
void configWifiHtml();
|
||||
void configMqttHtml();
|
||||
void configWebHtml();
|
||||
void configDomoticzHtml();
|
||||
void bootCss();
|
||||
void gaugemeterJs();
|
||||
void githubSvg();
|
||||
void dataJson();
|
||||
|
||||
void handleSetup();
|
||||
void handleSave();
|
||||
|
||||
void configSystemHtml();
|
||||
void configSystemPost();
|
||||
void configSystemUpload();
|
||||
String getSerialSelectOptions(int selected);
|
||||
void firmwareHtml();
|
||||
void firmwareUpload();
|
||||
void firmwareDownload();
|
||||
void restartWaitHtml();
|
||||
void isAliveCheck();
|
||||
|
||||
void uploadHtml(const char* label, const char* action, const char* menu);
|
||||
void deleteHtml(const char* label, const char* action, const char* menu);
|
||||
void uploadFile(const char* path);
|
||||
void deleteFile(const char* path);
|
||||
void uploadPost();
|
||||
void mqttCa();
|
||||
void mqttCaUpload();
|
||||
void mqttCaDelete();
|
||||
void mqttCert();
|
||||
void mqttCertUpload();
|
||||
void mqttCertDelete();
|
||||
void mqttKey();
|
||||
void mqttKeyUpload();
|
||||
void mqttKeyDelete();
|
||||
|
||||
void factoryResetHtml();
|
||||
void factoryResetPost();
|
||||
|
||||
void notFound();
|
||||
|
||||
void printD(String fmt, ...);
|
||||
void printI(String fmt, ...);
|
||||
void printW(String fmt, ...);
|
||||
|
||||
339
web/application.js
Normal file
339
web/application.js
Normal file
@@ -0,0 +1,339 @@
|
||||
var nextVersion;
|
||||
var im, em;
|
||||
$(function() {
|
||||
im = $("#importMeter");
|
||||
if(im && im.gaugeMeter) {
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
em = $("#exportMeter");
|
||||
if(em && em.gaugeMeter) {
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
var meters = $('.SimpleMeter');
|
||||
|
||||
if(meters.length > 0) {
|
||||
fetch();
|
||||
}
|
||||
|
||||
// For config-mqtt
|
||||
$('#mqttEnable').on('change', function() {
|
||||
var inputs = $('.mqtt-config');
|
||||
inputs.prop('disabled', !$(this).is(':checked'));
|
||||
});
|
||||
|
||||
$('#mqttPayloadFormat').on('change', function() {
|
||||
var val = parseInt($(this).val());
|
||||
if(val == 3) {
|
||||
$('.format-type-domoticz').show();
|
||||
} else {
|
||||
$('.format-type-domoticz').hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#mqttSsl').on('change', function() {
|
||||
var port = $('#mqttPort');
|
||||
if($(this).is(':checked')) {
|
||||
if(port.val() == 1883) {
|
||||
port.val(8883);
|
||||
}
|
||||
} else {
|
||||
if(port.val() == 8883) {
|
||||
port.val(1883);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#mqttEnable').trigger('change');
|
||||
$('#mqttPayloadFormat').trigger('change');
|
||||
|
||||
// For config-meter
|
||||
$('.subtitute-dependent').on('change', function() {
|
||||
console.log("test");
|
||||
if(($('#meterType').val() == 2 || $('#meterType').val() == 3) && $('#distributionSystem').val() == 1) {
|
||||
$('#substitute').show();
|
||||
} else {
|
||||
$('#substitute').hide();
|
||||
}
|
||||
});
|
||||
$('#meterType').trigger('change');
|
||||
|
||||
// For config-wifi
|
||||
$('#wifiIpType').on('change', function() {
|
||||
if($(this).is(':checked')) {
|
||||
$('#staticIp').show();
|
||||
} else {
|
||||
$('#staticIp').hide();
|
||||
}
|
||||
});
|
||||
$('#wifiIpType').trigger('change');
|
||||
|
||||
// For config-web
|
||||
$('#authSecurity').on('change', function() {
|
||||
var inputs = $('.auth-config');
|
||||
inputs.prop('disabled', $(this).val() == 0);
|
||||
});
|
||||
|
||||
$('#authSecurity').trigger('change');
|
||||
|
||||
// For file upload
|
||||
$('#fileUploadField').on('change',function(){
|
||||
var fileName = $(this).val();
|
||||
$(this).next('.custom-file-label').html(fileName);
|
||||
})
|
||||
|
||||
switch(window.location.pathname) {
|
||||
case '/config-meter':
|
||||
$('#config-meter-link').addClass('active');
|
||||
break;
|
||||
case '/config-wifi':
|
||||
$('#config-wifi-link').addClass('active');
|
||||
break;
|
||||
case '/config-mqtt':
|
||||
case '/mqtt-ca':
|
||||
case '/mqtt-cert':
|
||||
case '/mqtt-key':
|
||||
case '/config-domoticz':
|
||||
$('#config-mqtt-link').addClass('active');
|
||||
break;
|
||||
case '/config-web':
|
||||
$('#config-web-link').addClass('active');
|
||||
break;
|
||||
case '/config-system':
|
||||
case '/firmware':
|
||||
case '/reset':
|
||||
$('#config-system-link').addClass('active');
|
||||
break;
|
||||
}
|
||||
|
||||
var swv = $('#swVersion')
|
||||
if(meters.length > 0 && swv.length == 1 && swv.text() != "SNAPSHOT") {
|
||||
var v = swv.text().substring(1).split('.');
|
||||
var v_major = parseInt(v[0]);
|
||||
var v_minor = parseInt(v[1]);
|
||||
var v_patch = parseInt(v[2]);
|
||||
$.ajax({
|
||||
url: swv.data('url'),
|
||||
dataType: 'json'
|
||||
}).done(function(releases) {
|
||||
releases.reverse();
|
||||
var me;
|
||||
var next_patch;
|
||||
var next_minor;
|
||||
var next_major;
|
||||
$.each(releases, function(i, release) {
|
||||
var ver2 = release.tag_name;
|
||||
var v2 = ver2.substring(1).split('.');
|
||||
var v2_major = parseInt(v2[0]);
|
||||
var v2_minor = parseInt(v2[1]);
|
||||
var v2_patch = parseInt(v2[2]);
|
||||
|
||||
if(v2_major == v_major) {
|
||||
if(v2_minor == v_minor) {
|
||||
if(v2_patch > v_patch) {
|
||||
next_patch = release;
|
||||
}
|
||||
} else if(v2_minor == v_minor+1) {
|
||||
next_minor = release;
|
||||
}
|
||||
} else if(v2_major == v_major+1) {
|
||||
if(next_major) {
|
||||
var mv = next_major.tag_name.substring(1).split('.');
|
||||
var mv_major = parseInt(mv[0]);
|
||||
var mv_minor = parseInt(mv[1]);
|
||||
var mv_patch = parseInt(mv[2]);
|
||||
if(v2_minor == mv_minor) {
|
||||
next_major = release;
|
||||
}
|
||||
} else {
|
||||
next_major = release;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(next_minor) {
|
||||
nextVersion = next_minor;
|
||||
} else if(next_major) {
|
||||
nextVersion = next_major;
|
||||
} else if(next_patch) {
|
||||
nextVersion = next_patch;
|
||||
}
|
||||
if(nextVersion) {
|
||||
$('#newVersionTag').text(nextVersion.tag_name);
|
||||
$('#newVersionUrl').prop('href', nextVersion.html_url);
|
||||
$('#newVersion').removeClass('d-none');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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 = 5000;
|
||||
var fetch = function() {
|
||||
$.ajax({
|
||||
url: '/data.json',
|
||||
timeout: 10000,
|
||||
dataType: 'json',
|
||||
}).done(function(json) {
|
||||
if(im && em) {
|
||||
$(".SimpleMeter").hide();
|
||||
im.show();
|
||||
em.show();
|
||||
}
|
||||
|
||||
for(var id in json) {
|
||||
var str = json[id];
|
||||
if(typeof str === "object")
|
||||
continue;
|
||||
if(isNaN(str)) {
|
||||
$('#'+id).html(str);
|
||||
} else {
|
||||
var num = parseFloat(str);
|
||||
$('#'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1));
|
||||
}
|
||||
}
|
||||
|
||||
if(window.moment) {
|
||||
$('#currentMillis').html(moment.duration(parseInt(json.uptime_seconds), 'seconds').humanize());
|
||||
$('#currentMillis').closest('.row').show();
|
||||
}
|
||||
|
||||
if(json.status) {
|
||||
for(var id in json.status) {
|
||||
setStatus(id, json.status[id]);
|
||||
}
|
||||
}
|
||||
|
||||
if(json.mqtt) {
|
||||
$('.mqtt-error').addClass('d-none');
|
||||
$('.mqtt-error'+json.mqtt.lastError).removeClass('d-none');
|
||||
$('#mqtt-lastError').html(json.mqtt.lastError);
|
||||
}
|
||||
|
||||
if(json.wifi) {
|
||||
for(var id in json.wifi) {
|
||||
var str = json.wifi[id];
|
||||
dst = $('#'+id);
|
||||
if(isNaN(str)) {
|
||||
dst.html(str);
|
||||
} else {
|
||||
var num = parseFloat(str);
|
||||
dst.html(num.toFixed(0));
|
||||
$('#'+id+'-row').show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(json.data) {
|
||||
var p = 0;
|
||||
var p_pct = parseInt(json.p_pct);
|
||||
var p_append = "W";
|
||||
if(json.data.P) {
|
||||
p = parseFloat(json.data.P);
|
||||
if(p > 1000) {
|
||||
p = (p/1000).toFixed(1);
|
||||
p_append = "kW";
|
||||
}
|
||||
}
|
||||
if(im && im.gaugeMeter) {
|
||||
im.gaugeMeter({
|
||||
percent: p_pct,
|
||||
text: p,
|
||||
append: p_append
|
||||
});
|
||||
}
|
||||
|
||||
var po = 0;
|
||||
var po_pct = parseInt(json.po_pct);
|
||||
var po_append = "W";
|
||||
if(json.data.PO) {
|
||||
po = parseFloat(json.data.PO);
|
||||
if(po > 1000) {
|
||||
po = (po/1000).toFixed(1);
|
||||
po_append = "kW";
|
||||
}
|
||||
}
|
||||
if(em && em.gaugeMeter) {
|
||||
em.gaugeMeter({
|
||||
percent: po_pct,
|
||||
text: po,
|
||||
append: po_append
|
||||
});
|
||||
}
|
||||
|
||||
for(var id in json.data) {
|
||||
var str = json.data[id];
|
||||
if(isNaN(str)) {
|
||||
$('#'+id).html(str);
|
||||
} else {
|
||||
var num = parseFloat(str);
|
||||
$('#'+id).html(num.toFixed(1));
|
||||
$('#'+id+'-row').show();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(im && im.gaugeMeter) {
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
if(em && em.gaugeMeter) {
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
}
|
||||
setTimeout(fetch, interval);
|
||||
}).fail(function() {
|
||||
setTimeout(fetch, interval*4);
|
||||
|
||||
if(im && im.gaugeMeter) {
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
if(em && em.gaugeMeter) {
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
setStatus("mqtt", "secondary");
|
||||
setStatus("wifi", "secondary");
|
||||
setStatus("han", "secondary");
|
||||
setStatus("esp", "danger");
|
||||
});
|
||||
}
|
||||
|
||||
var upgrade = function() {
|
||||
if(nextVersion) {
|
||||
if(confirm("Are you sure you want to perform upgrade to " + nextVersion.tag_name + "?")) {
|
||||
window.location.href="/upgrade?version=" + nextVersion.tag_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
152
web/boot.css
152
web/boot.css
@@ -56,24 +56,9 @@ body {
|
||||
.bg-purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
.text-white-50 {
|
||||
color: rgba(255,255,255,.5)!important;
|
||||
}
|
||||
.mb-0, .my-0 {
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
.m-2 {
|
||||
margin: .5rem!important;
|
||||
}
|
||||
.mb-2, .my-2 {
|
||||
margin-bottom: .5rem!important;
|
||||
}
|
||||
.mt-2, .my-2 {
|
||||
margin-top: .5rem!important;
|
||||
}
|
||||
.pb-2, .py-2 {
|
||||
padding-bottom: .5rem!important;
|
||||
}
|
||||
.p-3 {
|
||||
padding: 1rem!important;
|
||||
}
|
||||
@@ -89,19 +74,9 @@ body {
|
||||
.shadow {
|
||||
box-shadow: 0 .5rem 1rem rgba(0,0,0,.15)!important;
|
||||
}
|
||||
.align-items-center {
|
||||
-ms-flex-align: center!important;
|
||||
align-items: center!important;
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #dee2e6!important;
|
||||
}
|
||||
.rounded {
|
||||
border-radius: .25rem!important;
|
||||
}
|
||||
div {
|
||||
display: block;
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
padding-right: 15px;
|
||||
@@ -115,15 +90,9 @@ article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
.text-white {
|
||||
color: #fff!important;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right!important;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center!important;
|
||||
}
|
||||
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
|
||||
margin-bottom: .5rem;
|
||||
font-weight: 500;
|
||||
@@ -133,6 +102,9 @@ h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
.h5, h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
.h6, h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
@@ -150,48 +122,14 @@ h1, h2, h3, h4, h5, h6 {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.col-2 {
|
||||
-ms-flex: 0 0 16.666667%;
|
||||
flex: 0 0 16.666667%;
|
||||
max-width: 16.666667%;
|
||||
}
|
||||
.col-3 {
|
||||
-ms-flex: 0 0 25%;
|
||||
flex: 0 0 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
.col-4 {
|
||||
-ms-flex: 0 0 33.333333%;
|
||||
flex: 0 0 33.333333%;
|
||||
max-width: 33.333333%;
|
||||
}
|
||||
.col-5 {
|
||||
-ms-flex: 0 0 41.666667%;
|
||||
flex: 0 0 41.666667%;
|
||||
max-width: 41.666667%;
|
||||
}
|
||||
.col-6 {
|
||||
-ms-flex: 0 0 50%;
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
.col-8 {
|
||||
-ms-flex: 0 0 66.666667%;
|
||||
flex: 0 0 66.666667%;
|
||||
max-width: 66.666667%;
|
||||
}
|
||||
.col-9 {
|
||||
-ms-flex: 0 0 75%;
|
||||
flex: 0 0 75%;
|
||||
max-width: 75%;
|
||||
}
|
||||
.d-none {
|
||||
display: none!important;
|
||||
}
|
||||
.d-flex {
|
||||
display: -ms-flexbox!important;
|
||||
display: flex!important;
|
||||
}
|
||||
.flex-row {
|
||||
-ms-flex-direction: row!important;
|
||||
flex-direction: row!important;
|
||||
@@ -225,9 +163,11 @@ a {
|
||||
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;
|
||||
}
|
||||
.btn-outline-secondary {
|
||||
color: #6c757d;
|
||||
border-color: #6c757d;
|
||||
.btn-group-sm>.btn, .btn-sm {
|
||||
padding: .25rem .5rem;
|
||||
font-size: .875rem;
|
||||
line-height: 1.5;
|
||||
border-radius: .2rem;
|
||||
}
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
@@ -295,46 +235,6 @@ a {
|
||||
.navbar-dark .navbar-nav .active>.nav-link, .navbar-dark .navbar-nav .nav-link.active, .navbar-dark .navbar-nav .nav-link.show, .navbar-dark .navbar-nav .show>.nav-link {
|
||||
color: #fff;
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: .25em .4em;
|
||||
font-size: 75%;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: .25rem;
|
||||
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||
}
|
||||
.badge-secondary {
|
||||
color: #fff;
|
||||
background-color: #6c757d;
|
||||
}
|
||||
.badge-success {
|
||||
color: #fff;
|
||||
background-color: #28a745;
|
||||
}
|
||||
.badge-warning {
|
||||
color: #212529;
|
||||
background-color: #ffc107;
|
||||
}
|
||||
.badge-danger {
|
||||
color: #fff;
|
||||
background-color: #dc3545;
|
||||
}
|
||||
.alert {
|
||||
position: relative;
|
||||
padding: .75rem 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: .25rem;
|
||||
}
|
||||
.alert-warning {
|
||||
color: #856404;
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffeeba;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -386,6 +286,9 @@ input[type="radio"], input[type="checkbox"] {
|
||||
.input-group-append {
|
||||
margin-left: -1px;
|
||||
}
|
||||
.input-group-prepend {
|
||||
margin-right: -1px;
|
||||
}
|
||||
.input-group-append, .input-group-prepend {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
@@ -394,6 +297,14 @@ input[type="radio"], input[type="checkbox"] {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle), .input-group>.input-group-append:last-child>.input-group-text:not(:last-child), .input-group>.input-group-append:not(:last-child)>.btn, .input-group>.input-group-append:not(:last-child)>.input-group-text, .input-group>.input-group-prepend>.btn, .input-group>.input-group-prepend>.input-group-text {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.input-group>.custom-select:not(:first-child), .input-group>.form-control:not(:first-child) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.input-group-text {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
@@ -453,6 +364,11 @@ dl, ol, ul {
|
||||
.container, .container-sm {
|
||||
max-width: 540px;
|
||||
}
|
||||
.col-sm-6 {
|
||||
-ms-flex: 0 0 50%;
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.container, .container-md, .container-sm {
|
||||
@@ -463,11 +379,6 @@ dl, ol, ul {
|
||||
flex: 0 0 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
.col-md-4 {
|
||||
-ms-flex: 0 0 33.333333%;
|
||||
flex: 0 0 33.333333%;
|
||||
max-width: 33.333333%;
|
||||
}
|
||||
.col-md-6 {
|
||||
-ms-flex: 0 0 50%;
|
||||
flex: 0 0 50%;
|
||||
@@ -499,6 +410,21 @@ dl, ol, ul {
|
||||
.container, .container-lg, .container-md, .container-sm, .container-xl {
|
||||
max-width: 1140px;
|
||||
}
|
||||
.col-xl-2 {
|
||||
-ms-flex: 0 0 16.666667%;
|
||||
flex: 0 0 16.666667%;
|
||||
max-width: 16.666667%;
|
||||
}
|
||||
.col-xl-3 {
|
||||
-ms-flex: 0 0 25%;
|
||||
flex: 0 0 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
.col-xl-4 {
|
||||
-ms-flex: 0 0 33.333333%;
|
||||
flex: 0 0 33.333333%;
|
||||
max-width: 33.333333%;
|
||||
}
|
||||
}
|
||||
|
||||
*, ::after, ::before {
|
||||
|
||||
60
web/configdomoticz.html
Normal file
60
web/configdomoticz.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="domoConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<p>Domoticz Configuration. Requires that a Domoticz MQTT-message-broker is setup. HOWTO: https://www.domoticz.com/wiki/MQTT.</p>
|
||||
<p>The following virtual sensors can currently be used:</p>
|
||||
<ul>
|
||||
<li>Electricity (instant and counter)</li>
|
||||
<li>Electricity Current/Ampere 3 Phase</li>
|
||||
<li>Voltage</li>
|
||||
</ul>
|
||||
<p>see: <a href="https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's">https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's</a></p>
|
||||
<p>Create the sensors in Domoticz under Hardware > Dummy > Create virtual sensor, and use the IDX assigned to the sensor as input here.</p>
|
||||
<p>"Electricity (instant and counter)" relies on Total energy import "tPI" and will not start before the first value is read (once an hour).</p>
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="d-flex flex-row flex-wrap">
|
||||
<div class="m-2 input-group input-group-sm" style="width: 200px;">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Electricity IDX</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="domoELIDX" value="${config.domoELIDX}" min="0" max="65535"/>
|
||||
</div>
|
||||
<div class="m-2 input-group input-group-sm" style="width: 240px;">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Current (3 Phase) IDX</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="domoCL1IDX" value="${config.domoCL1IDX}" min="0" max="65535"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-row flex-wrap">
|
||||
<div class="m-2 input-group input-group-sm" style="width: 200px;">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Voltage L1 IDX</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="domoVL1IDX" value="${config.domoVL1IDX}" min="0" max="65535"/>
|
||||
</div>
|
||||
<div class="m-2 input-group input-group-sm" style="width: 200px;">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Voltage L1 IDX</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="domoVL2IDX" value="${config.domoVL2IDX}" min="0" max="65535"/>
|
||||
</div>
|
||||
<div class="m-2 input-group input-group-sm" style="width: 200px;">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Voltage L1 IDX</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="domoVL3IDX" value="${config.domoVL3IDX}" min="0" max="65535"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,106 +1,78 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - Meter configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="meterConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<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}>Autodetect</option>
|
||||
<option value="1" ${config.meterType1}>Kaifa</option>
|
||||
<option value="2" ${config.meterType2}>Aidon</option>
|
||||
<option value="3" ${config.meterType3}>Kamstrup</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Distribution system</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control" name="distributionSystem">
|
||||
<option value="0" ${config.distributionSystem0}></option>
|
||||
<option value="1" ${config.distributionSystem1}>IT (230V)</option>
|
||||
<option value="2" ${config.distributionSystem2}>TN (400V)</option>
|
||||
</select>
|
||||
</div>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="meterConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 col-sm-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Meter type</span>
|
||||
</div>
|
||||
<select id="meterType" class="form-control subtitute-dependent" name="meterType">
|
||||
<option value="0" ${config.meterType0}>Autodetect</option>
|
||||
<option value="1" ${config.meterType1}>Kaifa</option>
|
||||
<option value="2" ${config.meterType2}>Aidon</option>
|
||||
<option value="3" ${config.meterType3}>Kamstrup</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Main fuse</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control" name="mainFuse">
|
||||
<option value="0" ${config.mainFuse0}></option>
|
||||
<option value="25" ${config.mainFuse25}>25A</option>
|
||||
<option value="32" ${config.mainFuse32}>32A</option>
|
||||
<option value="35" ${config.mainFuse32}>35A</option>
|
||||
<option value="40" ${config.mainFuse40}>40A</option>
|
||||
<option value="50" ${config.mainFuse50}>50A</option>
|
||||
<option value="63" ${config.mainFuse63}>63A</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-5 col-sm-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Distribution system</span>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Production capacity</label>
|
||||
<div class="col-6">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="productionCapacity" type="number" min="0" max="50" value="${config.productionCapacity}"/>
|
||||
<div class="input-group-append"><span class="input-group-text">kWp</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<select id="distributionSystem" class="form-control subtitute-dependent" name="distributionSystem">
|
||||
<option value="0" ${config.distributionSystem0}></option>
|
||||
<option value="1" ${config.distributionSystem1}>IT (230V)</option>
|
||||
<option value="2" ${config.distributionSystem2}>TN (400V)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-2 col-md-3 col-sm-5">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Main fuse</span>
|
||||
</div>
|
||||
<select class="form-control" name="mainFuse">
|
||||
<option value="0" ${config.mainFuse0}></option>
|
||||
<option value="25" ${config.mainFuse25}>25A</option>
|
||||
<option value="32" ${config.mainFuse32}>32A</option>
|
||||
<option value="35" ${config.mainFuse32}>35A</option>
|
||||
<option value="40" ${config.mainFuse40}>40A</option>
|
||||
<option value="50" ${config.mainFuse50}>50A</option>
|
||||
<option value="63" ${config.mainFuse63}>63A</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-5 col-sm-7">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Production capacity</span>
|
||||
</div>
|
||||
<input class="form-control" name="productionCapacity" type="number" min="0" max="50" value="${config.productionCapacity}"/>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">kWp</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
<div id="substitute" class="col-lg-3 col-md-4 col-sm-5">
|
||||
<div class="m-2">
|
||||
<label class="small"><input id="substituteMissing" type="checkbox" name="substituteMissing" value="true" ${config.substituteMissing}/> Substitute missing values</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
<div class="col-lg-3 col-md-4 col-sm-5">
|
||||
<div class="m-2">
|
||||
<label class="small"><input type="checkbox" name="sendUnknown" value="true" ${config.sendUnknown}/> Send unknown packets to MQTT</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,103 +1,123 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - WiFi configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="mqttConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<label class="m-2"><input id="mqttEnable" type="checkbox" name="mqtt" value="true" ${config.mqtt}/> Enable</label>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<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 class="col-xl-4 col-lg-5 col-md-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Host</span>
|
||||
</div>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttHost" value="${config.mqttHost}" maxlength="128"/>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Payload</label>
|
||||
<div class="col-8">
|
||||
<select class="form-control mqtt-config" name="mqttPayloadFormat">
|
||||
<option value="0" ${config.mqttPayloadFormat0}>JSON</option>
|
||||
<option value="1" ${config.mqttPayloadFormat1}>Raw</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xl-2 col-lg-3 col-md-3 col-sm-4">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Port</span>
|
||||
</div>
|
||||
<input id="mqttPort" type="number" class="form-control mqtt-config" name="mqttPort" value="${config.mqttPort}" min="1024" max="65535" placeholder="1883"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6 col-sm-8">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Client ID</span>
|
||||
</div>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttClientId" value="${config.mqttClientId}" maxlength="32"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Publish topic</span>
|
||||
</div>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttPublishTopic" value="${config.mqttPublishTopic}" maxlength="64"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6 col-sm-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Username</span>
|
||||
</div>
|
||||
<input type="text" class="form-control mqtt-config" name="mqttUser" value="${config.mqttUser}" maxlength="64"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6 col-sm-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Password</span>
|
||||
</div>
|
||||
<input type="password" class="form-control mqtt-config" name="mqttPassword" value="${config.mqttPassword}" maxlength="64"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-4 col-sm-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Payload</span>
|
||||
</div>
|
||||
<select id="mqttPayloadFormat" class="form-control mqtt-config" name="mqttPayloadFormat">
|
||||
<option value="0" ${config.mqttPayloadFormat0}>JSON</option>
|
||||
<option value="1" ${config.mqttPayloadFormat1}>Raw (minimal)</option>
|
||||
<option value="2" ${config.mqttPayloadFormat2}>Raw (full)</option>
|
||||
<option value="3" ${config.mqttPayloadFormat3}>Domoticz</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 format-type-domoticz">
|
||||
<div class="m-2">
|
||||
<a href="/config-domoticz" class="btn btn-sm btn-outline-secondary">Configuration</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<label class="m-2"><input id="mqttSsl" type="checkbox" name="mqttSsl" value="true" ${config.mqttSsl}/> SSL</label>
|
||||
</div>
|
||||
<div class="col-lg-2 col-md-3">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">CA</span>
|
||||
</div>
|
||||
<div class="input-group-append">
|
||||
<span style="display: ${display.ca.upload};">
|
||||
<a href="/mqtt-ca" class="btn btn-sm btn-outline-secondary">Upload</a>
|
||||
</span>
|
||||
<span style="display: ${display.ca.file};">
|
||||
<a href="/mqtt-ca" class="btn btn-sm btn-danger">Delete</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Hostname</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control mqtt-config" name="mqttHost" value="${config.mqttHost}"/>
|
||||
<div class="col-xl-2 col-md-3">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Certificate</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Port</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control mqtt-config" name="mqttPort" value="${config.mqttPort}"/>
|
||||
<div class="input-group-append">
|
||||
<span style="display: ${display.cert.upload};">
|
||||
<a href="/mqtt-cert" class="btn btn-sm btn-outline-secondary">Upload</a>
|
||||
</span>
|
||||
<span style="display: ${display.cert.file};">
|
||||
<a href="/mqtt-cert" class="btn btn-sm btn-danger">Delete</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Client ID</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control mqtt-config" name="mqttClientId" value="${config.mqttClientId}"/>
|
||||
<div class="col-xl-2 col-md-4">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Private key</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Topic</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control mqtt-config" name="mqttPublishTopic" value="${config.mqttPublishTopic}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Username</label>
|
||||
<div class="col-8">
|
||||
<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 mqtt-config" name="mqttPassword" value="${config.mqttPassword}"/>
|
||||
<div class="input-group-append">
|
||||
<span style="display: ${display.key.upload};">
|
||||
<a href="/mqtt-key" class="btn btn-sm btn-outline-secondary">Upload</a>
|
||||
</span>
|
||||
<span style="display: ${display.key.file};">
|
||||
<a href="/mqtt-key" class="btn btn-sm btn-danger">Delete</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,16 +133,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<script>
|
||||
$('#mqttEnable').on('change', function() {
|
||||
var inputs = $('.mqtt-config');
|
||||
inputs.prop('disabled', !$(this).is(':checked'));
|
||||
});
|
||||
|
||||
$(function() {
|
||||
$('#mqttEnable').trigger('change');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,100 +1,134 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - System configuration</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.min.css"/>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link " href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="sysConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="alert alert-warning">!!WARNING!!<br/>Remote debugging is considered insecure and should not be left enabled when not debugging</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<label><input type="checkbox" name="debugTelnet" value="true" ${config.debugTelnet}/> Telnet debugger</label>
|
||||
<div class="alert alert-warning">!!WARNING!!<br/>Do not change anything here unless you know exactly what you are doing! Changing things here could cause the device to stop responding</div>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="sysConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<h6>GPIO settings</h6>
|
||||
<div class="row">
|
||||
<div class="col-xl-2 col-md-3 col-sm-6 col-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">HAN</span>
|
||||
</div>
|
||||
<select name="hanPin" class="form-control">
|
||||
${options.han}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label><input type="checkbox" name="debugSerial" value="true" ${config.debugSerial}/> Serial debugger</label>
|
||||
</div>
|
||||
<div class="col-xl-2 col-lg-3 col-md-4 col-sm-5 col-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">LED</span>
|
||||
</div>
|
||||
<input name="ledPin" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPin}"/>
|
||||
<div class="input-group-append" title="Inverted">
|
||||
<label class="input-group-text">
|
||||
<input type="checkbox" name="ledInverted" value="true" ${config.ledInverted}/> inv
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Debug level</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control" name="debugLevel">
|
||||
<option value="2" ${config.debugLevel2}>Debug</option>
|
||||
<option value="3" ${config.debugLevel3}>Info</option>
|
||||
<option value="4" ${config.debugLevel4}>Warning</option>
|
||||
<option value="5" ${config.debugLevel5}>Error</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">RGB</span>
|
||||
</div>
|
||||
<input name="ledPinRed" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinRed}"/>
|
||||
<input name="ledPinGreen" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinGreen}"/>
|
||||
<input name="ledPinBlue" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinBlue}"/>
|
||||
<div class="input-group-append" title="Inverted">
|
||||
<label class="input-group-text">
|
||||
<input type="checkbox" name="ledRgbInverted" value="true" ${config.ledRgbInverted}/> inv
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-md-3 col-sm-6 col-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">AP button</span>
|
||||
</div>
|
||||
<input name="apPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.apPin}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Temperature</span>
|
||||
</div>
|
||||
<input name="tempSensorPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.tempSensorPin}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-lg-8">
|
||||
<div class="row p-2">
|
||||
<div class="col-sm-3 col-5">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Vcc</span>
|
||||
</div>
|
||||
<input name="vccPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.vccPin}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-7">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Multiplier</span>
|
||||
</div>
|
||||
<input type="number" min="0.1" max="10" step="0.01" class="form-control" name="vccMultiplier" value="${config.vccMultiplier}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-7">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Boot limit</span>
|
||||
</div>
|
||||
<input type="number" min="2.5" max="3.5" step="0.1" class="form-control" name="vccBootLimit" value="${config.vccBootLimit}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="alert alert-warning">!!WARNING!!<br/>Do not use this unless you know what you are doing. Uploading the wrong image could cause your device to stop working. Use with extreme caution!</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Firmware</label>
|
||||
<div class="col-8">
|
||||
<input type="file" name="file"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<h6>Debugger</h6>
|
||||
<div class="row">
|
||||
<div class="col-xl-2 col-md-3">
|
||||
<label><input type="checkbox" name="debugTelnet" value="true" ${config.debugTelnet}/> Telnet debugger</label>
|
||||
</div>
|
||||
<div class="col-xl-2 col-md-3">
|
||||
<label><input type="checkbox" name="debugSerial" value="true" ${config.debugSerial}/> Serial debugger</label>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Debug level</label>
|
||||
<div class="col-6">
|
||||
<select class="form-control form-control-sm" name="debugLevel">
|
||||
<option value="2" ${config.debugLevel2}>Debug</option>
|
||||
<option value="3" ${config.debugLevel3}>Info</option>
|
||||
<option value="4" ${config.debugLevel4}>Warning</option>
|
||||
<option value="5" ${config.debugLevel5}>Error</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8 text-right">
|
||||
<button class="btn btn-primary">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
<a href="/firmware" class="btn btn-sm btn-outline-secondary">Upload firmware</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<a href="/reset" class="btn btn-sm btn-danger">Factory reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,97 +1,44 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - Meter configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="authConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Security</label>
|
||||
<div class="col-8">
|
||||
<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>
|
||||
</select>
|
||||
</div>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="authConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-lg-4 col-md-7">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Security</span>
|
||||
</div>
|
||||
<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>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Username</label>
|
||||
<div class="col-8">
|
||||
<input type="text" class="form-control auth-config" name="authUser" value="${config.authUser}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Username</span>
|
||||
</div>
|
||||
<input type="text" class="form-control auth-config" name="authUser" value="${config.authUser}" maxlength="64"/>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-4">Password</label>
|
||||
<div class="col-8">
|
||||
<input type="password" class="form-control auth-config" name="authPassword" value="${config.authPassword}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-md-6">
|
||||
<div class="m-2 input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Password</span>
|
||||
</div>
|
||||
<input type="password" class="form-control auth-config" name="authPassword" value="${config.authPassword}" maxlength="64"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<script>
|
||||
$('#authSecurity').on('change', function() {
|
||||
var inputs = $('.auth-config');
|
||||
inputs.prop('disabled', $(this).val() == 0);
|
||||
});
|
||||
|
||||
$(function() {
|
||||
$('#authSecurity').trigger('change');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,132 +1,85 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - WiFi configuration</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="wifiConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-md-6 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">SSID</span>
|
||||
</div>
|
||||
<input type="text" name="wifiSsid" class="form-control" maxlength="32" placeholder="Name of your WiFi" value="${config.wifiSsid}" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">PSK</span>
|
||||
</div>
|
||||
<input type="password" name="wifiPassword" class="form-control" maxlength="63" placeholder="Password for WiFi" value="${config.wifiPassword}" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-md-6 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Hostname</span>
|
||||
</div>
|
||||
<input type="text" name="wifiHostname" class="form-control" maxlength="32" pattern="[a-z0-9_-]+" placeholder="Optional, ex.: ams-reader" value="${config.wifiHostname}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-2 col-md-6 form-group">
|
||||
<label><input id="wifiIpType" type="checkbox" name="wifiIpType" value="1" ${config.wifiStaticIp}/> Static IP</label>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post" action="/save">
|
||||
<input type="hidden" name="wifiConfig" value="true"/>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-3">SSID</label>
|
||||
<div class="col-9">
|
||||
<input type="text" class="form-control" name="wifiSsid" value="${config.wifiSsid}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-3">Password</label>
|
||||
<div class="col-9">
|
||||
<input type="password" class="form-control" name="wifiPassword" value="${config.wifiPassword}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-3">Hostname</label>
|
||||
<div class="col-9">
|
||||
<input type="text" class="form-control" name="wifiHostname" value="${config.wifiHostname}"/>
|
||||
</div>
|
||||
<div class="row" id="staticIp">
|
||||
<div class="col-xl-3 col-lg-4 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">IP</span>
|
||||
</div>
|
||||
<input type="text" name="wifiIp" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex: 192.168.1.200" value="${config.wifiIp}"/>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-6">IP configuration</label>
|
||||
<div class="col-6">
|
||||
<select id="wifiIpType" class="form-control" name="wifiIpType">
|
||||
<option value="0" ${config.wifiIpType0}>DHCP</option>
|
||||
<option value="1" ${config.wifiIpType1}>Static</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">IP</label>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control wifiip-config" name="wifiIp" value="${config.wifiIp}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Subnet</label>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control wifiip-config" name="wifiSubnet" value="${config.wifiSubnet}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Subnet</span>
|
||||
</div>
|
||||
<input type="text" name="wifiSubnet" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 255.255.255.0" value="${config.wifiSubnet}"/>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Gateway</label>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control wifiip-config" name="wifiGw" value="${config.wifiGw}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Gateway</span>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Primary DNS</label>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control wifiip-config" name="wifiDns1" value="${config.wifiDns1}"/>
|
||||
</div>
|
||||
<input type="text" name="wifiGw" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 192.168.1.1" value="${config.wifiGw}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-lg-5 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Primary DNS</span>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label class="col-6">Secondary DNS</label>
|
||||
<div class="col-6">
|
||||
<input type="text" class="form-control wifiip-config" name="wifiDns2" value="${config.wifiDns2}"/>
|
||||
</div>
|
||||
<input type="text" name="wifiDns1" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 192.168.1.1" value="${config.wifiDns1}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-lg-5 form-group">
|
||||
<div class="input-group input-group-sm">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Secondary DNS</span>
|
||||
</div>
|
||||
<input type="text" name="wifiDns2" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 8.8.8.8" value="${config.wifiDns2}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="/" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<script>
|
||||
$('#wifiIpType').on('change', function() {
|
||||
var inputs = $('.wifiip-config');
|
||||
inputs.prop('disabled', $(this).val() != 1);
|
||||
});
|
||||
|
||||
$(function() {
|
||||
$('#wifiIpType').trigger('change');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
14
web/delete.html
Normal file
14
web/delete.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<form method="post">
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="alert alert-warning">Are you sure you want to delete this file?</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="javascript:history.back();" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-danger">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
13
web/foot.html
Normal file
13
web/foot.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<div id="newVersion" class="alert alert-info d-none">New version <span id="newVersionTag"></span>! <a id="newVersionUrl" href="#" target="_blank">view</a></div>
|
||||
</main>
|
||||
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
|
||||
<script src="gaugemeter.js"></script>
|
||||
<script src="application.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -58,7 +58,7 @@
|
||||
"White" === option.theme && (t = "#fff"),
|
||||
"Black" === option.theme && (t = "#000"),
|
||||
t;
|
||||
}
|
||||
};
|
||||
/* The label below gauge. */
|
||||
function createLabel(t, a) {
|
||||
if(t.children("b").length === 0){
|
||||
@@ -67,7 +67,7 @@
|
||||
color: option.label_color
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
/* Prepend and append text, the gauge text or percentage value. */
|
||||
function createSpanTag(t) {
|
||||
var fgcolor = "";
|
||||
@@ -90,7 +90,7 @@
|
||||
"font-size": option.text_size * option.size + "px",
|
||||
color: fgcolor
|
||||
});
|
||||
}
|
||||
};
|
||||
/* Get data attributes as options from div tag. Fall back to defaults when not exists. */
|
||||
function getDataAttr(t) {
|
||||
$.each(dataAttr, function (index, element) {
|
||||
@@ -116,10 +116,10 @@
|
||||
option[element] = parseFloat(option[element]);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
/* Draws the gauge. */
|
||||
function drawGauge(a) {
|
||||
if(M < 0) M = 0;
|
||||
if(M < 0) M = 0;
|
||||
if(M > 100) M = 100;
|
||||
var lw = option.width < 1 || isNaN(option.width) ? option.size / 20 : option.width;
|
||||
g.clearRect(0, 0, b.width, b.height);
|
||||
@@ -141,7 +141,7 @@
|
||||
c > M && (M += z, requestAnimationFrame(function(){
|
||||
drawGauge(Math.min(M, c) / 100);
|
||||
}, p));
|
||||
}
|
||||
};
|
||||
|
||||
$(this).attr("data-id", $(this).attr("id"));
|
||||
var r,
|
||||
|
||||
6
web/github.svg
Normal file
6
web/github.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false">
|
||||
<title>GitHub</title>
|
||||
<path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="#f8f9fa" fill-rule="evenodd"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
86
web/head.html
Normal file
86
web/head.html
Normal file
@@ -0,0 +1,86 @@
|
||||
<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" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
|
||||
<style>
|
||||
.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">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-lg-row rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small id="swVersion" data-url="https://api.github.com/repos/gskjold/AmsToMqttBridge/releases">${version}</small></h6></a>
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a id="config-meter-link" class="nav-link" href="/config-meter">Meter</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a id="config-wifi-link" class="nav-link" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a id="config-mqtt-link" class="nav-link" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a id="config-web-link" class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a id="config-system-link" class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div id="esp" class="d-none m-2">ESP</div>
|
||||
<div id="han" class="d-none m-2">HAN</div>
|
||||
<div id="wifi" class="d-none m-2">WiFi</div>
|
||||
<div id="mqtt" class="d-none m-2">MQTT</div>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-lg-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<img class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" src="github.svg"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
453
web/index.html
453
web/index.html
@@ -1,358 +1,107 @@
|
||||
<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"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
|
||||
<script src="gaugemeter.js"></script>
|
||||
<style>
|
||||
.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">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="flex-row ml-md-auto d-md-flex">
|
||||
<div id="esp" class="d-none m-2">ESP</div>
|
||||
<div id="han" class="d-none m-2">HAN</div>
|
||||
<div id="wifi" class="d-none m-2">WiFi</div>
|
||||
<div id="mqtt" class="d-none m-2">MQTT</div>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.P} W
|
||||
</div>
|
||||
<div id="importMeter" 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-label="${text.import}"
|
||||
></div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.P} W
|
||||
</div>
|
||||
<div id="importMeter" 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-label="${text.import}"
|
||||
></div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div id="U1-row" 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="U2-row" 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="U3-row" 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>
|
||||
<hr/>
|
||||
<div id="tPI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Active in</div>
|
||||
<div class="col-6 text-right"><span id="tPI">${data.tPI}</span> kWh</div>
|
||||
</div>
|
||||
<div id="tPO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Active out</div>
|
||||
<div class="col-6 text-right"><span id="tPO">${data.tPO}</span> kWh</div>
|
||||
</div>
|
||||
<div id="tQI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Reactive in</div>
|
||||
<div class="col-6 text-right"><span id="tQI">${data.tQI}</span> kvarh</div>
|
||||
</div>
|
||||
<div id="tQO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Reactive out</div>
|
||||
<div class="col-6 text-right"><span id="tQO">${data.tQO}</span> kvarh</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="text-center" style="display: ${display.export};">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.PO} W
|
||||
</div>
|
||||
<div id="exportMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="200px"
|
||||
data-text_size="0.11"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="DarkGreen-LightGreen"
|
||||
data-animationstep="0"
|
||||
data-label="Export"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<hr class="d-md-inline"/>
|
||||
<div class="row">
|
||||
<div class="col-6">Vcc</div>
|
||||
<div class="col-6 text-right"><span id="vcc">${vcc}</span> V</div>
|
||||
</div>
|
||||
<div class="row" style="display: ${display.temp};">
|
||||
<div class="col-6">Temperature</div>
|
||||
<div class="col-6 text-right"><span id="temp">${temp}</span> °C</div>
|
||||
</div>
|
||||
<div class="row" style="display: none;">
|
||||
<div class="col-6">Uptime</div>
|
||||
<div class="col-6 text-right"><span id="currentMillis">${currentMillis}</span></div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-6">SSID</div>
|
||||
<div class="col-6 text-right"><span id="ssid">${wifi.ssid}</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">Channel</div>
|
||||
<div class="col-6 text-right"><span id="channel">${wifi.channel}</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">RSSI</div>
|
||||
<div class="col-6 text-right"><span id="rssi">${wifi.rssi}</span> dBm</div>
|
||||
</div>
|
||||
<hr class="d-none mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-3 mqtt-error-4 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-10 mqtt-error-11 mqtt-error-12 mqtt-error-13"/>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-12">MQTT communication error (<span id="mqtt-lastError">-</span>)</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-3">MQTT failed to connect</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-4">MQTT network timeout</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-10">MQTT connection denied</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-11">MQTT failed to subscribe</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-13">MQTT lost connection</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div id="U1-row" class="row" style="display: ${display.P1};">
|
||||
<div class="col-2">L1</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="U2-row" class="row" style="display: ${display.P2};">
|
||||
<div class="col-2">L2</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="U3-row" class="row" style="display: ${display.P3};">
|
||||
<div class="col-2">L3</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>
|
||||
<hr/>
|
||||
<div id="tPI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Active in</div>
|
||||
<div class="col-6 text-right"><span id="tPI">${data.tPI}</span> kWh</div>
|
||||
</div>
|
||||
<div id="tPO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Active out</div>
|
||||
<div class="col-6 text-right"><span id="tPO">${data.tPO}</span> kWh</div>
|
||||
</div>
|
||||
<div id="tQI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Reactive in</div>
|
||||
<div class="col-6 text-right"><span id="tQI">${data.tQI}</span> kvarh</div>
|
||||
</div>
|
||||
<div id="tQO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Reactive out</div>
|
||||
<div class="col-6 text-right"><span id="tQO">${data.tQO}</span> kvarh</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="text-center" style="display: ${display.export};">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.PO} W
|
||||
</div>
|
||||
<div id="exportMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="200px"
|
||||
data-text_size="0.11"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="DarkGreen-LightGreen"
|
||||
data-animationstep="0"
|
||||
data-label="Export"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<hr class="d-md-inline"/>
|
||||
<div class="row">
|
||||
<div class="col-6">Vcc</div>
|
||||
<div class="col-6 text-right"><span id="vcc">${vcc}</span> V</div>
|
||||
</div>
|
||||
<div class="row" style="display: ${display.temp};">
|
||||
<div class="col-6">Temperature</div>
|
||||
<div class="col-6 text-right"><span id="temp">${temp}</span> °C</div>
|
||||
</div>
|
||||
<div class="row" style="display: none;">
|
||||
<div class="col-6">Uptime</div>
|
||||
<div class="col-6 text-right"><span id="currentMillis">${currentMillis}</span></div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-6">SSID</div>
|
||||
<div class="col-6 text-right"><span id="ssid">${wifi.ssid}</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">Channel</div>
|
||||
<div class="col-6 text-right"><span id="channel">${wifi.channel}</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">RSSI</div>
|
||||
<div class="col-6 text-right"><span id="rssi">${wifi.rssi}</span> dBm</div>
|
||||
</div>
|
||||
<hr class="d-none mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-3 mqtt-error-4 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-10 mqtt-error-11 mqtt-error-12 mqtt-error-13"/>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-12">MQTT communication error (<span id="mqtt-lastError">-</span>)</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-3">MQTT failed to connect</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-4">MQTT network timeout</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-10">MQTT connection denied</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-11">MQTT failed to subscribe</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-13">MQTT lost connection</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
var im = $("#importMeter")
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
|
||||
var em = $("#exportMeter")
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
|
||||
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 = 5000;
|
||||
var fetch = function() {
|
||||
$.ajax({
|
||||
url: '/data.json',
|
||||
timeout: 10000,
|
||||
dataType: 'json',
|
||||
}).done(function(json) {
|
||||
$(".SimpleMeter").hide();
|
||||
im.show();
|
||||
em.show();
|
||||
|
||||
for(var id in json) {
|
||||
var str = json[id];
|
||||
if(typeof str === "object")
|
||||
continue;
|
||||
if(isNaN(str)) {
|
||||
$('#'+id).html(str);
|
||||
} else {
|
||||
var num = parseFloat(str);
|
||||
$('#'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1));
|
||||
}
|
||||
}
|
||||
|
||||
if(window.moment) {
|
||||
$('#currentMillis').html(moment.duration(parseInt(json.uptime_seconds), 'seconds').humanize());
|
||||
$('#currentMillis').closest('.row').show();
|
||||
}
|
||||
|
||||
if(json.status) {
|
||||
for(var id in json.status) {
|
||||
setStatus(id, json.status[id]);
|
||||
}
|
||||
}
|
||||
|
||||
if(json.mqtt) {
|
||||
$('.mqtt-error').addClass('d-none');
|
||||
$('.mqtt-error'+json.mqtt.lastError).removeClass('d-none');
|
||||
$('#mqtt-lastError').html(json.mqtt.lastError);
|
||||
}
|
||||
|
||||
if(json.wifi) {
|
||||
for(var id in json.wifi) {
|
||||
var str = json.wifi[id];
|
||||
dst = $('#'+id);
|
||||
if(isNaN(str)) {
|
||||
dst.html(str);
|
||||
} else {
|
||||
var num = parseFloat(str);
|
||||
dst.html(num.toFixed(0));
|
||||
$('#'+id+'-row').show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(json.data) {
|
||||
var p = 0;
|
||||
var p_pct = parseInt(json.p_pct);
|
||||
var p_append = "W";
|
||||
if(json.data.P) {
|
||||
p = parseFloat(json.data.P);
|
||||
if(p > 1000) {
|
||||
p = (p/1000).toFixed(1);
|
||||
p_append = "kW";
|
||||
}
|
||||
}
|
||||
im.gaugeMeter({
|
||||
percent: p_pct,
|
||||
text: p,
|
||||
append: p_append
|
||||
});
|
||||
|
||||
var po = 0;
|
||||
var po_pct = parseInt(json.po_pct);
|
||||
var po_append = "W";
|
||||
if(json.data.PO) {
|
||||
po = parseFloat(json.data.PO);
|
||||
if(po > 1000) {
|
||||
po = (po/1000).toFixed(1);
|
||||
po_append = "kW";
|
||||
}
|
||||
}
|
||||
em.gaugeMeter({
|
||||
percent: po_pct,
|
||||
text: po,
|
||||
append: po_append
|
||||
});
|
||||
|
||||
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));
|
||||
$('#'+id+'-row').show();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
setTimeout(fetch, interval);
|
||||
}).fail(function() {
|
||||
setTimeout(fetch, interval*4);
|
||||
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
|
||||
setStatus("mqtt", "secondary");
|
||||
setStatus("wifi", "secondary");
|
||||
setStatus("han", "secondary");
|
||||
setStatus("esp", "danger");
|
||||
});
|
||||
}
|
||||
fetch();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
|
||||
14
web/reset.html
Normal file
14
web/reset.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<form method="post">
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="alert alert-danger">Are you sure you want reset this device to factory settings? ALL configuration will be erased!</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="javascript:history.back();" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-danger" name="perform" value="true">Perform factory reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -5,35 +5,15 @@
|
||||
<title>AMS reader - Restarting, please wait</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-wifi">WiFi</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-mqtt">MQTT</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-web">Web</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config-system">System</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<svg class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false"><title>GitHub</title><path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||
<img class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" src="github.svg"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -44,7 +24,6 @@
|
||||
</main>
|
||||
<script>
|
||||
var tries = 0;
|
||||
|
||||
var ip = "${ip}";
|
||||
var hostname = "${hostname}";
|
||||
var url;
|
||||
@@ -60,15 +39,22 @@
|
||||
} else {
|
||||
url = "";
|
||||
}
|
||||
if(console) console.log("Trying url " + url)
|
||||
$.ajax({
|
||||
url: url + '/is-alive',
|
||||
timeout: 5000
|
||||
}).done(function(json) {
|
||||
window.location.href = url ? url : "/";
|
||||
}).fail(function() {
|
||||
if(console) console.log("Trying url " + url);
|
||||
|
||||
var retry = function() {
|
||||
setTimeout(fetch, 1000);
|
||||
};
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.timeout = 5000;
|
||||
xhr.addEventListener('abort', retry);
|
||||
xhr.addEventListener('error', retry);
|
||||
xhr.addEventListener('timeout', retry);
|
||||
xhr.addEventListener('load', function(e) {
|
||||
window.location.href = url ? url : "/";
|
||||
});
|
||||
xhr.open("GET", url + "/is-alive", true);
|
||||
xhr.send();
|
||||
};
|
||||
setTimeout(fetch, 10000);
|
||||
</script>
|
||||
|
||||
137
web/setup.html
Normal file
137
web/setup.html
Normal file
@@ -0,0 +1,137 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AMS reader - Setup</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" type="text/css" href="boot.css"/>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-md-row bg-purple rounded mt-2 mb-4">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<img style="width: 2rem; height: 2rem;" src="github.svg"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<form method="post">
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-xl-4 col-md-6">
|
||||
<h5>Hardware</h5>
|
||||
<select name="board" class="form-control">
|
||||
<optgroup label="Custom hardware">
|
||||
<option value="0" ${config.boardType0}>Custom hardware by Roar Fredriksen</option>
|
||||
<option value="1" ${config.boardType1}>Kamstrup module by Egil Opsahl</option>
|
||||
<option value="2" ${config.boardType2}>HAN Reader 2.0 by Max Spencer</option>
|
||||
</optgroup>
|
||||
<optgroup label="ESP8266">
|
||||
<option value="101" ${config.boardType101}>Wemos D1</option>
|
||||
<option value="100" ${config.boardType100}>Generic ESP8266</option>
|
||||
</optgroup>
|
||||
<optgroup label="ESP32">
|
||||
<option value="201" ${config.boardType201}>Wemos LOLIN D32</option>
|
||||
<option value="202" ${config.boardType202}>Adafruit HUZZAH32</option>
|
||||
<option value="203" ${config.boardType203}>DevKitC</option>
|
||||
<option value="200" ${config.boardType200}>Generic ESP32</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xl-2 col-md-3">
|
||||
<h5>Meter</h5>
|
||||
<select name="meterType" class="form-control">
|
||||
<option value="0" ${config.meterType0}>Autodetect</option>
|
||||
<option value="1" ${config.meterType1}>Kaifa</option>
|
||||
<option value="2" ${config.meterType2}>Aidon</option>
|
||||
<option value="3" ${config.meterType3}>Kamstrup</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<h5>WiFi</h5>
|
||||
<div class="row">
|
||||
<div class="col-xl-3 col-md-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">SSID</span>
|
||||
</div>
|
||||
<input type="text" name="wifiSsid" class="form-control" maxlength="32" placeholder="Name of your WiFi" required value="${config.wifiSsid}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">PSK</span>
|
||||
</div>
|
||||
<input type="password" name="wifiPassword" class="form-control" maxlength="63" placeholder="Password for WiFi" required value="${config.wifiPassword}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-4 col-md-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Hostname</span>
|
||||
</div>
|
||||
<input type="text" name="wifiHostname" class="form-control" maxlength="32" pattern="[a-z0-9_-]+" placeholder="Optional, ex.: ams-reader" value="${config.wifiHostname}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-2 col-md-6 form-group">
|
||||
<label><input type="checkbox" name="wifiIpType" value="1" onchange="staticChecked(this);" ${config.wifiStaticIp}/> Static IP</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="staticIp">
|
||||
<div class="col-xl-3 col-lg-4 col-sm-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">IP</span>
|
||||
</div>
|
||||
<input type="text" name="wifiIp" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex: 192.168.1.200" value="${config.wifiIp}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-sm-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Subnet</span>
|
||||
</div>
|
||||
<input type="text" name="wifiSubnet" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 255.255.255.0" value="${config.wifiSubnet}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-sm-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Gateway</span>
|
||||
</div>
|
||||
<input type="text" name="wifiGw" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 192.168.1.1" value="${config.wifiGw}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-lg-4 col-sm-6 form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">DNS</span>
|
||||
</div>
|
||||
<input type="text" name="wifiDns1" class="form-control" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" placeholder="Ex.: 192.168.1.1" value="${config.wifiDns1}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-6"></div>
|
||||
<div class="col-6 text-right">
|
||||
<button type="submit" class="btn btn-primary">Save & reboot</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
<script>
|
||||
document.getElementById('staticIp').style.display = "none";
|
||||
var staticChecked = function(el) {
|
||||
document.getElementById('staticIp').style.display = el.checked ? "" : "none";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
26
web/upload.html
Normal file
26
web/upload.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Upload</span>
|
||||
</div>
|
||||
<div class="custom-file">
|
||||
<input name="file" type="file" class="custom-file-input" id="fileUploadField">
|
||||
<label class="custom-file-label" for="fileUploadField">Choose file</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row form-group">
|
||||
<div class="col-6">
|
||||
<a href="javascript:history.back();" class="btn btn-outline-secondary">Back</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<button class="btn btn-primary">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
Reference in New Issue
Block a user