mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-13 23:45:25 +00:00
Further work on v2.2
This commit is contained in:
parent
6563700df4
commit
ab7128c53a
@ -4,7 +4,7 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#define EEPROM_SIZE 1024*3
|
||||
#define EEPROM_CHECK_SUM 96 // Used to check if config is stored. Change if structure changes
|
||||
#define EEPROM_CHECK_SUM 100 // Used to check if config is stored. Change if structure changes
|
||||
#define EEPROM_CONFIG_ADDRESS 0
|
||||
#define EEPROM_TEMP_CONFIG_ADDRESS 2048
|
||||
|
||||
@ -29,7 +29,11 @@
|
||||
|
||||
struct SystemConfig {
|
||||
uint8_t boardType;
|
||||
}; // 1
|
||||
bool vendorConfigured;
|
||||
bool userConfigured;
|
||||
uint8_t dataCollectionConsent; // 0 = unknown, 1 = accepted, 2 = declined
|
||||
char country[2];
|
||||
}; // 6
|
||||
|
||||
struct WiFiConfig91 {
|
||||
char ssid[32];
|
||||
@ -55,7 +59,8 @@ struct WiFiConfig {
|
||||
bool mdns;
|
||||
uint8_t power;
|
||||
uint8_t sleep;
|
||||
}; // 211
|
||||
uint8_t mode;
|
||||
}; // 212
|
||||
|
||||
struct MqttConfig86 {
|
||||
char host[128];
|
||||
@ -280,14 +285,13 @@ private:
|
||||
uint8_t tempSensorCount = 0;
|
||||
TempSensorConfig** tempSensors = NULL;
|
||||
|
||||
bool relocateConfig86(); // 1.5.0
|
||||
bool relocateConfig87(); // 1.5.4
|
||||
bool relocateConfig90(); // 2.0.0
|
||||
bool relocateConfig91(); // 2.0.2
|
||||
bool relocateConfig92(); // 2.0.3
|
||||
bool relocateConfig93(); // 2.1.0
|
||||
bool relocateConfig94(); // 2.1.4
|
||||
bool relocateConfig95(); // 2.1.13
|
||||
bool relocateConfig94(); // 2.1.0
|
||||
bool relocateConfig95(); // 2.1.4
|
||||
bool relocateConfig96(); // 2.1.14
|
||||
|
||||
void saveToFs();
|
||||
bool loadFromFs(uint8_t version);
|
||||
|
||||
@ -7,6 +7,11 @@ bool AmsConfiguration::getSystemConfig(SystemConfig& config) {
|
||||
EEPROM.end();
|
||||
return true;
|
||||
} else {
|
||||
config.boardType = 0xFF;
|
||||
config.vendorConfigured = false;
|
||||
config.userConfigured = false;
|
||||
config.dataCollectionConsent = 0;
|
||||
strcpy(config.country, "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -619,22 +624,6 @@ bool AmsConfiguration::hasConfig() {
|
||||
}
|
||||
} else {
|
||||
switch(configVersion) {
|
||||
case 86:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig86()) {
|
||||
configVersion = 87;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 87:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig87()) {
|
||||
configVersion = 88;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 90:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig90()) {
|
||||
@ -683,6 +672,14 @@ bool AmsConfiguration::hasConfig() {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 96:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig96()) {
|
||||
configVersion = 100;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case EEPROM_CHECK_SUM:
|
||||
return true;
|
||||
default:
|
||||
@ -735,51 +732,6 @@ void AmsConfiguration::saveTempSensors() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig86() {
|
||||
MqttConfig86 mqtt86;
|
||||
MqttConfig mqtt;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_MQTT_START_86, mqtt86);
|
||||
strcpy(mqtt.host, mqtt86.host);
|
||||
mqtt.port = mqtt86.port;
|
||||
strcpy(mqtt.clientId, mqtt86.clientId);
|
||||
strcpy(mqtt.publishTopic, mqtt86.publishTopic);
|
||||
strcpy(mqtt.subscribeTopic, mqtt86.subscribeTopic);
|
||||
strcpy(mqtt.username, mqtt86.username);
|
||||
strcpy(mqtt.password, mqtt86.password);
|
||||
mqtt.payloadFormat = mqtt86.payloadFormat;
|
||||
mqtt.ssl = mqtt86.ssl;
|
||||
EEPROM.put(CONFIG_MQTT_START, mqtt);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 87);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig87() {
|
||||
MeterConfig87 meter87 = {0,0,0,0,0,0,0};
|
||||
MeterConfig meter;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_METER_START_87, meter87);
|
||||
if(meter87.type < 5) {
|
||||
meter.baud = 2400;
|
||||
meter.parity = meter87.type == 3 || meter87.type == 4 ? 3 : 11;
|
||||
meter.invert = false;
|
||||
} else {
|
||||
meter.baud = 115200;
|
||||
meter.parity = 3;
|
||||
meter.invert = meter87.type == 6;
|
||||
}
|
||||
meter.distributionSystem = meter87.distributionSystem;
|
||||
meter.mainFuse = meter87.mainFuse;
|
||||
meter.productionCapacity = meter87.productionCapacity;
|
||||
EEPROM.put(CONFIG_METER_START, meter);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 88);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig90() {
|
||||
EntsoeConfig entsoe;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@ -877,6 +829,27 @@ bool AmsConfiguration::relocateConfig95() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig96() {
|
||||
SystemConfig sys;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_SYSTEM_START, sys);
|
||||
sys.vendorConfigured = false;
|
||||
sys.userConfigured = false;
|
||||
sys.dataCollectionConsent = 0;
|
||||
strcpy(sys.country, "");
|
||||
EEPROM.put(CONFIG_SYSTEM_START, sys);
|
||||
|
||||
WiFiConfig wifi;
|
||||
EEPROM.get(CONFIG_WIFI_START, wifi);
|
||||
wifi.mode = 1; // WIFI_STA
|
||||
EEPROM.put(CONFIG_WIFI_START, wifi);
|
||||
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 100);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::save() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CHECK_SUM);
|
||||
|
||||
@ -1,15 +1,20 @@
|
||||
<script>
|
||||
import { Router, Route } from "svelte-navigator";
|
||||
|
||||
import { sysinfoStore, dataStore } from './lib/DataStores.js';
|
||||
import { getSysinfo, sysinfoStore, dataStore } from './lib/DataStores.js';
|
||||
import Header from './lib/Header.svelte';
|
||||
import Dashboard from './lib/Dashboard.svelte';
|
||||
import ConfigurationPanel from './lib/ConfigurationPanel.svelte';
|
||||
import StatusPage from './lib/StatusPage.svelte';
|
||||
import VendorModal from './lib/VendorModal.svelte';
|
||||
import SetupModal from './lib/SetupModal.svelte';
|
||||
import Mask from './lib/Mask.svelte';
|
||||
|
||||
let sysinfo = {};
|
||||
sysinfoStore.subscribe(update => {
|
||||
sysinfo = update;
|
||||
});
|
||||
getSysinfo();
|
||||
let data = {};
|
||||
dataStore.subscribe(update => {
|
||||
data = update;
|
||||
@ -25,6 +30,13 @@
|
||||
<Route path="/configuration">
|
||||
<ConfigurationPanel sysinfo={sysinfo}/>
|
||||
</Route>
|
||||
<Route path="/status">
|
||||
<StatusPage sysinfo={sysinfo} data={data}/>
|
||||
</Route>
|
||||
</Router>
|
||||
|
||||
{#if sysinfo.vndcfg === false}
|
||||
<VendorModal sysinfo={sysinfo}/>
|
||||
{:else if sysinfo.usrcfg === false}
|
||||
<SetupModal sysinfo={sysinfo}/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
<span title={title} class="my-auto bg-yellow-500 text-yellow-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
{:else if color === `red`}
|
||||
<span title={title} class="my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
{:else if color === `blue`}
|
||||
<span title={title} class="my-auto bg-blue-500 text-blue-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
{:else if color === `gray`}
|
||||
<span title={title} class="my-auto bg-gray-500 text-gray-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
{/if}
|
||||
48
lib/SvelteUi/app/src/lib/BoardTypeSelectOptions.svelte
Normal file
48
lib/SvelteUi/app/src/lib/BoardTypeSelectOptions.svelte
Normal file
@ -0,0 +1,48 @@
|
||||
<script>
|
||||
import {boardtype} from './Helpers.js'
|
||||
|
||||
export let chip;
|
||||
</script>
|
||||
|
||||
<option value=""></option>
|
||||
{#if chip == 'esp8266'}
|
||||
<optgroup label="amsleser.no">
|
||||
<option value={7}>{boardtype(chip, 7)}</option>
|
||||
<option value={5}>{boardtype(chip, 5)}</option>
|
||||
<option value={4}>{boardtype(chip, 4)}</option>
|
||||
<option value={3}>{boardtype(chip, 3)}</option>
|
||||
</optgroup>
|
||||
<optgroup label="Custom hardware">
|
||||
<option value={2}>{boardtype(chip, 2)}</option>
|
||||
<option value={1}>{boardtype(chip, 1)}</option>
|
||||
<option value={0}>{boardtype(chip, 0)}</option>
|
||||
</optgroup>
|
||||
<optgroup label="Generic hardware">
|
||||
<option value={101}>{boardtype(chip, 101)}</option>
|
||||
<option value={100}>{boardtype(chip, 100)}</option>
|
||||
</optgroup>
|
||||
{/if}
|
||||
{#if chip == 'esp32'}
|
||||
<optgroup label="Generic hardware">
|
||||
<option value={201}>{boardtype(chip, 201)}</option>
|
||||
<option value={202}>{boardtype(chip, 202)}</option>
|
||||
<option value={203}>{boardtype(chip, 203)}</option>
|
||||
<option value={200}>{boardtype(chip, 200)}</option>
|
||||
</optgroup>
|
||||
{/if}
|
||||
{#if chip == 'esp32s2'}
|
||||
<optgroup label="amsleser.no">
|
||||
<option value={7}>{boardtype(chip, 7)}</option>
|
||||
<option value={6}>{boardtype(chip, 6)}</option>
|
||||
<option value={5}>{boardtype(chip, 5)}</option>
|
||||
</optgroup>
|
||||
<optgroup label="Generic hardware">
|
||||
<option value={51}>{boardtype(chip, 51)}</option>
|
||||
<option value={50}>{boardtype(chip, 50)}</option>
|
||||
</optgroup>
|
||||
{/if}
|
||||
{#if chip == 'esp32solo'}
|
||||
<optgroup label="Generic hardware">
|
||||
<option value={200}>{boardtype(chip, 200)}</option>
|
||||
</optgroup>
|
||||
{/if}
|
||||
@ -1,138 +1,52 @@
|
||||
<script>
|
||||
import { getConfiguration, configurationStore } from './ConfigurationStore'
|
||||
import Modal from './Modal.svelte'
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import BoardTypeSelectOptions from './BoardTypeSelectOptions.svelte';
|
||||
import UartSelectOptions from './UartSelectOptions.svelte';
|
||||
import Mask from './Mask.svelte'
|
||||
import { metertype } from './Helpers';
|
||||
import Badge from './Badge.svelte';
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
let loadingOrSaving = true;
|
||||
|
||||
let configuration = {
|
||||
general: {
|
||||
host: '',
|
||||
sec: 0,
|
||||
user: '',
|
||||
pass: ''
|
||||
g: {
|
||||
t: '', h: '', s: 0, u: '', p: ''
|
||||
},
|
||||
meter: {
|
||||
inv: false,
|
||||
dist: 0,
|
||||
fuse: 0,
|
||||
prod: 0,
|
||||
enc: '',
|
||||
auth: ''
|
||||
m: {
|
||||
b: 2400, p: 11, i: false, d: 0, f: 0, r: 0,
|
||||
e: { e: false, k: '', a: '' },
|
||||
m: { e: false, w: false, v: false, a: false, c: false }
|
||||
},
|
||||
wifi: {
|
||||
ssid: '',
|
||||
psk: '',
|
||||
pwr: 0.0
|
||||
w: { s: '', p: '', w: 0.0, z: 255 },
|
||||
n: {
|
||||
m: '', i: '', s: '', g: '', d1: '', d2: '', d: false, n1: '', n2: '', h: false
|
||||
},
|
||||
net: {
|
||||
mode: '',
|
||||
ip: '',
|
||||
gw: '',
|
||||
dns1: '',
|
||||
dns2: '',
|
||||
ntp1: '',
|
||||
ntp2: ''
|
||||
q: {
|
||||
h: '', p: 1883, u: '', a: '', b: '',
|
||||
s: { e: false, c: false, r: true, k: false }
|
||||
},
|
||||
mqtt: {
|
||||
host: '',
|
||||
post: 1883,
|
||||
user: '',
|
||||
pass: '',
|
||||
pub: ''
|
||||
t: {
|
||||
t: [0,0,0,0,0,0,0,0,0,0], h: 1
|
||||
},
|
||||
p: {
|
||||
e: false, t: '', r: '', c: '', m: 1.0
|
||||
},
|
||||
d: {
|
||||
s: false, t: false, l: 5
|
||||
},
|
||||
i: {
|
||||
h: null, a: null,
|
||||
l: { p: null, i: false },
|
||||
r: { r: null, g: null, b: null, i: false },
|
||||
t: { d: null, a: null },
|
||||
v: { p: null, d: { v: null, g: null }, o: null, m: null, b: null }
|
||||
}
|
||||
};
|
||||
let metersources = {};
|
||||
configurationStore.subscribe(update => {
|
||||
if(update.version) {
|
||||
switch(sysinfo.chip) {
|
||||
case "esp8266":
|
||||
metersources = {
|
||||
'UART0' : 3,
|
||||
'UART2' : 113,
|
||||
'GPIO4' : 4,
|
||||
'GPIO5' : 5,
|
||||
'GPIO9' : 9,
|
||||
'GPIO10' : 10,
|
||||
'GPIO12' : 12,
|
||||
'GPIO13' : 13,
|
||||
'GPIO14' : 14,
|
||||
'GPIO15' : 15,
|
||||
'GPIO16' : 16,
|
||||
}
|
||||
break;
|
||||
case "esp32":
|
||||
metersources = {
|
||||
'UART0' : 3,
|
||||
'UART1' : 9,
|
||||
'UART2' : 16,
|
||||
'GPIO4' : 4,
|
||||
'GPIO5' : 5,
|
||||
'GPIO6' : 6,
|
||||
'GPIO7' : 7,
|
||||
'GPIO8' : 8,
|
||||
'GPIO10' : 10,
|
||||
'GPIO11' : 11,
|
||||
'GPIO12' : 12,
|
||||
'GPIO13' : 13,
|
||||
'GPIO14' : 14,
|
||||
'GPIO15' : 15,
|
||||
'GPIO17' : 17,
|
||||
'GPIO18' : 18,
|
||||
'GPIO19' : 19,
|
||||
'GPIO21' : 21,
|
||||
'GPIO22' : 22,
|
||||
'GPIO23' : 23,
|
||||
'GPIO25' : 25,
|
||||
'GPIO32' : 32,
|
||||
'GPIO33' : 33,
|
||||
'GPIO34' : 34,
|
||||
'GPIO35' : 35,
|
||||
'GPIO36' : 36,
|
||||
'GPIO39' : 39,
|
||||
}
|
||||
break;
|
||||
case "esp32s2":
|
||||
metersources = {
|
||||
'UART0' : 3,
|
||||
'UART1' : 18,
|
||||
'GPIO4' : 4,
|
||||
'GPIO5' : 5,
|
||||
'GPIO6' : 6,
|
||||
'GPIO7' : 7,
|
||||
'GPIO8' : 8,
|
||||
'GPIO9' : 9,
|
||||
'GPIO10' : 10,
|
||||
'GPIO11' : 11,
|
||||
'GPIO12' : 12,
|
||||
'GPIO13' : 13,
|
||||
'GPIO14' : 14,
|
||||
'GPIO15' : 15,
|
||||
'GPIO16' : 16,
|
||||
'GPIO17' : 17,
|
||||
'GPIO19' : 19,
|
||||
'GPIO21' : 21,
|
||||
'GPIO22' : 22,
|
||||
'GPIO23' : 23,
|
||||
'GPIO25' : 25,
|
||||
'GPIO32' : 32,
|
||||
'GPIO33' : 33,
|
||||
'GPIO34' : 34,
|
||||
'GPIO35' : 35,
|
||||
'GPIO36' : 36,
|
||||
'GPIO39' : 39,
|
||||
'GPIO40' : 40,
|
||||
'GPIO41' : 41,
|
||||
'GPIO42' : 42,
|
||||
'GPIO43' : 43,
|
||||
'GPIO44' : 44,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
metersources = {};
|
||||
}
|
||||
|
||||
configuration = update;
|
||||
loadingOrSaving = false;
|
||||
}
|
||||
@ -153,6 +67,12 @@
|
||||
body: data
|
||||
});
|
||||
let res = (await response.json())
|
||||
|
||||
sysinfoStore.update(s => {
|
||||
s.booting = res.reboot;
|
||||
return s;
|
||||
});
|
||||
|
||||
loadingOrSaving = false;
|
||||
getConfiguration();
|
||||
}
|
||||
@ -162,41 +82,109 @@
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">General</strong>
|
||||
<input type="hidden" name="general" value="true"/>
|
||||
<div class="my-3">
|
||||
Timezone<br/>
|
||||
<select class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<option value="Europe/Oslo">Europe/Oslo</option>
|
||||
</select>
|
||||
<input type="hidden" name="g" value="true"/>
|
||||
<div class="my-1">
|
||||
<div class="flex">
|
||||
<div>
|
||||
Hostname<br/>
|
||||
<input name="gh" bind:value={configuration.g.h} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div>
|
||||
Timezone<br/>
|
||||
<select name="gt" bind:value={configuration.g.t} class="h-10 rounded-r-md border-l-0 shadow-sm border-gray-300">
|
||||
<option value="UTC">UTC</option>
|
||||
<option value="CET/CEST">CET/CEST</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Hostname<br/>
|
||||
<input name="general_host" bind:value={configuration.general.host} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input type="hidden" name="p" value="true"/>
|
||||
<div class="my-1">
|
||||
<div class="flex">
|
||||
<div>
|
||||
Price region<br/>
|
||||
<select name="pr" bind:value={configuration.p.r} class="h-10 rounded-l-md shadow-sm border-gray-300">
|
||||
<optgroup label="Norway">
|
||||
<option value="10YNO-1--------2">NO1</option>
|
||||
<option value="10YNO-2--------T">NO2</option>
|
||||
<option value="10YNO-3--------J">NO3</option>
|
||||
<option value="10YNO-4--------9">NO4</option>
|
||||
<option value="10Y1001A1001A48H">NO5</option>
|
||||
</optgroup>
|
||||
<optgroup label="Sweden">
|
||||
<option value="10Y1001A1001A44P">SE1</option>
|
||||
<option value="10Y1001A1001A45N">SE2</option>
|
||||
<option value="10Y1001A1001A46L">SE3</option>
|
||||
<option value="10Y1001A1001A47J">SE4</option>
|
||||
</optgroup>
|
||||
<optgroup label="Denmark">
|
||||
<option value="10YDK-1--------W">DK1</option>
|
||||
<option value="10YDK-2--------M">DK2</option>
|
||||
</optgroup>
|
||||
<option value="10YAT-APG------L">Austria</option>
|
||||
<option value="10YBE----------2">Belgium</option>
|
||||
<option value="10YCZ-CEPS-----N">Czech Republic</option>
|
||||
<option value="10Y1001A1001A39I">Estonia</option>
|
||||
<option value="10YFI-1--------U">Finland</option>
|
||||
<option value="10YFR-RTE------C">France</option>
|
||||
<option value="10Y1001A1001A83F">Germany</option>
|
||||
<option value="10YGB----------A">Great Britain</option>
|
||||
<option value="10YLV-1001A00074">Latvia</option>
|
||||
<option value="10YLT-1001A0008Q">Lithuania</option>
|
||||
<option value="10YNL----------L">Netherland</option>
|
||||
<option value="10YPL-AREA-----S">Poland</option>
|
||||
<option value="10YCH-SWISSGRIDZ">Switzerland</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
Currency<br/>
|
||||
<select name="pc" bind:value={configuration.p.c} class="h-10 border-l-0 shadow-sm border-gray-300">
|
||||
<option value="NOK">NOK</option>
|
||||
<option value="SEK">SEK</option>
|
||||
<option value="DKK">DKK</option>
|
||||
<option value="EUR">EUR</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
Multiplier<br/>
|
||||
<input name="pm" bind:value={configuration.p.m} type="number" min="0.001" max="1000" step="0.001" class="h-10 rounded-r-md border-l-0 shadow-sm border-gray-300 w-24 text-right"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
{#if sysinfo.chip != 'esp8266'}
|
||||
<div class="my-1">
|
||||
<label><input type="checkbox" name="pe" bind:checked={configuration.p.e} class="rounded mb-1"/> ENTSO-E token</label>
|
||||
{#if configuration.p.e}
|
||||
<br/><input name="pt" bind:value={configuration.p.t} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
Security<br/>
|
||||
<select name="general_sec" bind:value={configuration.general.sec} class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<select name="gs" bind:value={configuration.g.s} class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<option value={0}>None</option>
|
||||
<option value={1}>Only configuration</option>
|
||||
<option value={2}>Everything</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
{#if configuration.g.s > 0}
|
||||
<div class="my-1">
|
||||
Username<br/>
|
||||
<input name="general_user" bind:value={configuration.general.user} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="gu" bind:value={configuration.g.u} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<div class="my-1">
|
||||
Password<br/>
|
||||
<input name="general_pass" bind:value={configuration.general.pass} type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="gp" bind:value={configuration.g.p} type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Meter</strong>
|
||||
<input type="hidden" name="meter" value="true"/>
|
||||
<div class="my-3">
|
||||
<input type="hidden" name="m" value="true"/>
|
||||
<div class="my-1">
|
||||
<span>Serial configuration</span>
|
||||
<div class="flex">
|
||||
<select name="meter_baud" bind:value={configuration.meter.baud} class="h-10 rounded-l-md shadow-sm border-gray-300">
|
||||
<select name="mb" bind:value={configuration.m.b} class="h-10 rounded-l-md shadow-sm border-gray-300">
|
||||
<option value={2400}>2400</option>
|
||||
<option value={4800}>4800</option>
|
||||
<option value={9600}>9600</option>
|
||||
@ -205,179 +193,369 @@
|
||||
<option value={57600}>57600</option>
|
||||
<option value={115200}>115200</option>
|
||||
</select>
|
||||
<select name="meter_par" bind:value={configuration.meter.par} class="h-10 rounded-r-md shadow-sm border-l-0 border-gray-300">
|
||||
<select name="mp" bind:value={configuration.m.p} class="h-10 rounded-r-md border-l-0 shadow-sm border-gray-300">
|
||||
<option value={2}>7N1</option>
|
||||
<option value={3}>8N1</option>
|
||||
<option value={10}>7E1</option>
|
||||
<option value={11}>8E1</option>
|
||||
</select>
|
||||
<label class="mt-2 ml-3"><input name="mi" value="true" bind:checked={configuration.m.i} type="checkbox" class="rounded mb-1"/> inverted</label>
|
||||
</div>
|
||||
<label><input name="meter_inv" value="true" bind:checked={configuration.meter.inv} type="checkbox" class="rounded"/> inverted</label>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="mb-1.5 col-span-2">
|
||||
<div class="my-1 flex">
|
||||
<div class="w-32">
|
||||
Distribution<br/>
|
||||
<select name="meter_dist" bind:value={configuration.meter.dist} class="h-10 rounded-md shadow-sm border-gray-300 w-full">
|
||||
<select name="md" bind:value={configuration.m.d} class="h-10 rounded-l-md shadow-sm border-gray-300 w-full">
|
||||
<option value={0}></option>
|
||||
<option value={1}>IT or TT (230V)</option>
|
||||
<option value={2}>TN (400V)</option>
|
||||
<option value={1}>IT/TT</option>
|
||||
<option value={2}>TN</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="my-1.5 mr-2">
|
||||
<div>
|
||||
Main fuse<br/>
|
||||
<label class="flex">
|
||||
<input name="meter_fuse" bind:value={configuration.meter.fuse} type="number" min="5" max="255" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
<div class="flex -mr-px">
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-l-0 border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">A</span>
|
||||
</div>
|
||||
<input name="mf" bind:value={configuration.m.f} type="number" min="5" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">A</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="my-1.5">
|
||||
<div>
|
||||
Production<br/>
|
||||
<label class="flex">
|
||||
<input name="meter_prod" bind:value={configuration.meter.prod} type="number" min="0" max="255" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
<div class="flex">
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-l-0 border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWp</span>
|
||||
</div>
|
||||
<input name="mr" bind:value={configuration.m.r} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWp</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-3">
|
||||
Encryption key<br/>
|
||||
<input name="meter_enc" bind:value={configuration.meter.enc} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<div class="my-1">
|
||||
</div>
|
||||
<div class="my-3">
|
||||
|
||||
<div class="my-1">
|
||||
<label><input type="checkbox" name="me" value="true" bind:checked={configuration.m.e.e} class="rounded mb-1"/> Meter uses encryption</label>
|
||||
{#if configuration.m.e.e}
|
||||
<br/><input name="mek" bind:value={configuration.m.e.k} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if configuration.m.e.e}
|
||||
<div class="my-1">
|
||||
Authentication key<br/>
|
||||
<input name="meter_auth" bind:value={configuration.meter.auth} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="mea" bind:value={configuration.m.e.a} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<label><input type="checkbox" name="mm" value="true" bind:checked={configuration.m.m.e} class="rounded mb-1"/> Multipliers</label>
|
||||
{#if configuration.m.m.e}
|
||||
<div class="flex my-1">
|
||||
<div class="w-1/4">
|
||||
Instant<br/>
|
||||
<input name="mmw" bind:value={configuration.m.m.w} type="number" min="0.00" max="655.35" step="0.01" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full text-right"/>
|
||||
</div>
|
||||
<div class="w-1/4">
|
||||
Volt<br/>
|
||||
<input name="mmv" bind:value={configuration.m.m.v} type="number" min="0.00" max="655.35" step="0.01" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
</div>
|
||||
<div class="w-1/4">
|
||||
Amp<br/>
|
||||
<input name="mma" bind:value={configuration.m.m.a} type="number" min="0.00" max="655.35" step="0.01" class="h-10 border-r-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
</div>
|
||||
<div class="w-1/4">
|
||||
Acc.<br/>
|
||||
<input name="mmc" bind:value={configuration.m.m.c} type="number" min="0.00" max="655.35" step="0.01" class="h-10 rounded-r-md shadow-sm border-gray-300 w-full text-right"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">WiFi</strong>
|
||||
<input type="hidden" name="wifi" value="true"/>
|
||||
<div class="my-3">
|
||||
<input type="hidden" name="w" value="true"/>
|
||||
<div class="my-1">
|
||||
SSID<br/>
|
||||
<input name="wifi_ssid" bind:value={configuration.wifi.ssid} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="ws" bind:value={configuration.w.s} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<div class="my-1">
|
||||
PSK<br/>
|
||||
<input name="wifi_psk" bind:value={configuration.wifi.psk} type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="wp" bind:value={configuration.w.p} type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Power<br/>
|
||||
<label class="flex">
|
||||
<input name="wifi_pwr" bind:value={configuration.wifi.pwr} type="number" min="0" max="20.5" step="0.5" class="h-10 rounded-l-md shadow-sm border-gray-300"/>
|
||||
<div class="flex -mr-px">
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-l-0 border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">dBm</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Power saving<br/>
|
||||
<select name="wifi_sleep" bind:value={configuration.wifi.sleep} class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<option value={255}>Default</option>
|
||||
<option value={0}>Off</option>
|
||||
<option value={1}>Minimum</option>
|
||||
<option value={2}>Maximum</option>
|
||||
</select>
|
||||
<div class="my-1 flex">
|
||||
<div>
|
||||
Power saving<br/>
|
||||
<select name="wz" bind:value={configuration.w.z} class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<option value={255}>Default</option>
|
||||
<option value={0}>Off</option>
|
||||
<option value={1}>Minimum</option>
|
||||
<option value={2}>Maximum</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
Power<br/>
|
||||
<label class="flex">
|
||||
<input name="ww" bind:value={configuration.w.w} type="number" min="0" max="20.5" step="0.5" class="h-10 rounded-l-md shadow-sm border-gray-300 text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border-l-0 border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">dBm</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Network</strong>
|
||||
<input type="hidden" name="net" value="true"/>
|
||||
<div class="my-3">
|
||||
<div class="my-1">
|
||||
IP<br/>
|
||||
<div class="flex">
|
||||
<select name="net_mode" bind:value={configuration.net.mode} class="h-10 rounded-l-md shadow-sm border-r-0 border-gray-300">
|
||||
<select name="nm" bind:value={configuration.n.m} class="h-10 rounded-l-md shadow-sm border border-gray-300">
|
||||
<option value="dhcp">DHCP</option>
|
||||
<option value="static">Static</option>
|
||||
</select>
|
||||
<input name="net_ip" bind:value={configuration.net.ip} type="text" class="h-10 shadow-sm border-gray-300 w-full"/>
|
||||
<select class="h-10 rounded-r-md shadow-sm border-l-0 border-gray-300">
|
||||
<option>/24</option>
|
||||
<input name="ni" bind:value={configuration.n.i} type="text" class="h-10 border-x-0 shadow-sm border-gray-300 w-full disabled:bg-gray-200" disabled={configuration.n.m == 'dhcp'}/>
|
||||
<select name="ns" bind:value={configuration.n.s} class="h-10 rounded-r-md shadow-sm border-gray-300 disabled:bg-gray-200" disabled={configuration.n.m == 'dhcp'}>
|
||||
<option value="255.255.255.0">/24</option>
|
||||
<option value="255.255.0.0">/16</option>
|
||||
<option value="255.0.0.0">/8</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
{#if configuration.n.m == 'static'}
|
||||
<div class="my-1">
|
||||
Gateway<br/>
|
||||
<input name="net_gw" bind:value={configuration.net.gw} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="ng" bind:value={configuration.n.g} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full disabled:bg-gray-200"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<div class="my-1">
|
||||
DNS<br/>
|
||||
<div class="flex">
|
||||
<input name="net_dns1" bind:value={configuration.net.dns1} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="net_dns2" bind:value={configuration.net.dns2} type="text" class="h-10 rounded-r-md shadow-sm border-l-0 border-gray-300 w-full"/>
|
||||
<input name="nd1" bind:value={configuration.n.d1} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full disabled:bg-gray-200"/>
|
||||
<input name="nd2" bind:value={configuration.n.d2} type="text" class="h-10 border-l-0 rounded-r-md shadow-sm border-gray-300 w-full disabled:bg-gray-200"/>
|
||||
</div>
|
||||
<label><input name="net_mdns" value="true" bind:checked={configuration.net.mdns} type="checkbox" class="rounded"/> enable mDNS</label>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
NTP<br/>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
<label><input name="nd" value="true" bind:checked={configuration.n.d} type="checkbox" class="rounded mb-1"/> enable mDNS</label>
|
||||
</div>
|
||||
<input type="hidden" name="ntp" value="true"/>
|
||||
<div class="my-1">
|
||||
NTP <label class="ml-4"><input name="ntpd" value="true" bind:checked={configuration.n.h} type="checkbox" class="rounded mb-1"/> obtain from DHCP</label><br/>
|
||||
<div class="flex">
|
||||
<input name="net_ntp1" bind:value={configuration.net.ntp1} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="net_ntp2" bind:value={configuration.net.ntp2} type="text" class="h-10 rounded-r-md shadow-sm border-l-0 border-gray-300 w-full"/>
|
||||
</div>
|
||||
<label><input name="net_ntpdhcp" value="true" bind:checked={configuration.net.ntpdhcp} type="checkbox" class="rounded"/> obtain from DHCP</label>
|
||||
<input name="ntph" bind:value={configuration.n.n1} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">MQTT</strong>
|
||||
<input type="hidden" name="mqtt" value="true"/>
|
||||
<div class="my-3">
|
||||
Server<br/>
|
||||
<input type="hidden" name="q" value="true"/>
|
||||
<div class="my-1">
|
||||
Server
|
||||
<label class="float-right mr-3"><input type="checkbox" name="qs" bind:checked={configuration.q.s.e} class="rounded mb-1"/> SSL</label>
|
||||
<br/>
|
||||
<div class="flex">
|
||||
<input name="mqtt_host" bind:value={configuration.mqtt.host} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="mqtt_port" bind:value={configuration.mqtt.port} type="text" class="h-10 rounded-r-md shadow-sm border-l-0 border-gray-300 w-20"/>
|
||||
<input name="qh" bind:value={configuration.q.h} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="qp" bind:value={configuration.q.p} type="number" min="1024" max="65535" class="h-10 border-l-0 rounded-r-md shadow-sm border-gray-300 w-20 text-right"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
{#if configuration.q.s.e}
|
||||
<div class="my-1">
|
||||
<div>
|
||||
{#if configuration.q.s.c}
|
||||
<Badge color="green" text="CA OK" title="Click here to replace CA"/>
|
||||
{:else}
|
||||
<Badge color="blue" text="Upload CA" title="Click here to upload CA"/>
|
||||
{/if}
|
||||
|
||||
{#if configuration.q.s.r}
|
||||
<Badge color="green" text="Cert OK" title="Click here to replace certificate"/>
|
||||
{:else}
|
||||
<Badge color="blue" text="Upload cert" title="Click here to upload certificate"/>
|
||||
{/if}
|
||||
|
||||
{#if configuration.q.s.k}
|
||||
<Badge color="green" text="Key OK" title="Click here to replace key"/>
|
||||
{:else}
|
||||
<Badge color="blue" text="Upload key" title="Click here to upload key"/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
Username<br/>
|
||||
<input name="mqtt_user" bind:value={configuration.mqtt.user} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="qu" bind:value={configuration.q.u} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<div class="my-1">
|
||||
Password<br/>
|
||||
<input name="mqtt_pass" bind:value={configuration.mqtt.pass} type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="qa" bind:value={configuration.q.a} type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Client ID<br/>
|
||||
<input name="mqtt_clid" bind:value={configuration.mqtt.clid} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<div class="my-1 flex">
|
||||
<div>
|
||||
Client ID<br/>
|
||||
<input name="qc" bind:value={configuration.q.c} type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div>
|
||||
Payload<br/>
|
||||
<select name="qm" bind:value={configuration.q.m} class="h-10 border-l-0 rounded-r-md shadow-sm border-gray-300 w-36">
|
||||
<option value={0}>JSON</option>
|
||||
<option value={1}>Raw (minimal)</option>
|
||||
<option value={2}>Raw (full)</option>
|
||||
<option value={3}>Domoticz</option>
|
||||
<option value={4}>HomeAssistant</option>
|
||||
<option value={255}>Raw bytes</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<div class="my-1">
|
||||
Publish topic<br/>
|
||||
<input name="mqtt_pub" bind:value={configuration.mqtt.pub} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="qb" bind:value={configuration.q.b} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Payload<br/>
|
||||
<select name="mqtt_mode" bind:value={configuration.mqtt.mode} class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<option value={0}>JSON</option>
|
||||
<option value={1}>Raw values (minimal)</option>
|
||||
<option value={2}>Raw values (full)</option>
|
||||
<option value={3}>Domoticz</option>
|
||||
<option value={4}>Home-Assistant</option>
|
||||
<option value={255}>Raw data (bytes)</option>
|
||||
</div>
|
||||
{#if configuration.p.r.startsWith("10YNO") || configuration.p.r == '10Y1001A1001A48H'}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Tariff thresholds</strong>
|
||||
<input type="hidden" name="t" value="true"/>
|
||||
<div class="flex flex-wrap my-1">
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">1</span>
|
||||
<input name="t0" bind:value={configuration.t.t[0]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">2</span>
|
||||
<input name="t1" bind:value={configuration.t.t[1]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">3</span>
|
||||
<input name="t2" bind:value={configuration.t.t[2]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">4</span>
|
||||
<input name="t3" bind:value={configuration.t.t[3]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">5</span>
|
||||
<input name="t4" bind:value={configuration.t.t[4]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">6</span>
|
||||
<input name="t5" bind:value={configuration.t.t[5]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">7</span>
|
||||
<input name="t6" bind:value={configuration.t.t[6]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">8</span>
|
||||
<input name="t7" bind:value={configuration.t.t[7]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">9</span>
|
||||
<input name="t8" bind:value={configuration.t.t[8]} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-full text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">kWh</span>
|
||||
</label>
|
||||
</div>
|
||||
<label class="flex m-1">
|
||||
<span class="flex items-center bg-gray-100 rounded-l-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">Average of</span>
|
||||
<input name="th" bind:value={configuration.t.h} type="number" min="0" max="255" class="h-10 border-x-0 shadow-sm border-gray-300 w-24 text-right"/>
|
||||
<span class="flex items-center bg-gray-100 rounded-r-md border border-gray-300 px-3 whitespace-no-wrap text-grey-dark text-sm">hours</span>
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Cloud</strong>
|
||||
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Hardware</strong>
|
||||
{#if sysinfo.board > 20}
|
||||
<input type="hidden" name="i" value="true"/>
|
||||
<div class="flex flex-wrap">
|
||||
<div>
|
||||
HAN<br/>
|
||||
<select name="ih" bind:value={configuration.i.h} class="h-10 rounded-l-md shadow-sm border-gray-300">
|
||||
<UartSelectOptions chip={sysinfo.chip}/>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
AP button<br/>
|
||||
<input name="ia" bind:value={configuration.i.a} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 border-x-0 shadow-sm border-gray-300 text-right"/>
|
||||
</div>
|
||||
<div>
|
||||
LED<label class="ml-4"><input name="ili" value="true" bind:checked={configuration.i.l.i} type="checkbox" class="rounded mb-1"/> inv</label><br/>
|
||||
<div class="flex">
|
||||
<input name="ilp" bind:value={configuration.i.l.p} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 rounded-r-md shadow-sm border-gray-300 text-right"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
RGB<label class="ml-4"><input name="iri" value="true" bind:checked={configuration.i.r.i} type="checkbox" class="rounded mb-1"/> inverted</label><br/>
|
||||
<div class="flex">
|
||||
<input name="irr" bind:value={configuration.i.r.r} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 rounded-l-md shadow-sm border-gray-300 text-right"/>
|
||||
<input name="irg" bind:value={configuration.i.r.g} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 border-x-0 shadow-sm border-gray-300 text-right"/>
|
||||
<input name="irb" bind:value={configuration.i.r.b} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 rounded-r-md shadow-sm border-gray-300 text-right"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
Temperature<br/>
|
||||
<input name="itd" bind:value={configuration.i.t.d} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 rounded-l-md shadow-sm border-gray-300 text-right"/>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
Analog temp<br/>
|
||||
<input name="ita" bind:value={configuration.i.t.a} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 border-x-0 shadow-sm border-gray-300 text-right"/>
|
||||
</div>
|
||||
{#if sysinfo.chip != 'esp8266'}
|
||||
<div class="my-1">
|
||||
Vcc<br/>
|
||||
<input name="ivp" bind:value={configuration.i.v.p} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="h-10 rounded-r-md shadow-sm border-gray-300 text-right"/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if configuration.i.v.p > 0}
|
||||
<div class="my-1">
|
||||
Voltage divider<br/>
|
||||
<div class="flex">
|
||||
<input name="ivdv" bind:value={configuration.i.v.d.v} type="number" min="0" max="65535" class="h-10 rounded-l-md shadow-sm border-gray-300 text-right" placeholder="VCC"/>
|
||||
<input name="ivdg" bind:value={configuration.i.v.d.g} type="number" min="0" max="65535" class="h-10 border-l-0 rounded-r-md shadow-sm border-gray-300 text-right" placeholder="GND"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if configuration.i.v.p > 0 || sysinfo.chip == 'esp8266'}
|
||||
<div class="my-1 flex flex-wrap">
|
||||
<div>
|
||||
Vcc offset<br/>
|
||||
<input name="ivo" bind:value={configuration.i.v.o} type="number" min="0.0" max="3.5" step="0.01" class="h-10 rounded-l-md shadow-sm border-gray-300 w-24 text-right"/>
|
||||
</div>
|
||||
<div>
|
||||
multiplier<br/>
|
||||
<input name="ivm" bind:value={configuration.i.v.m} type="number" min="0.1" max="10" step="0.01" class="h-10 border-x-0 shadow-sm border-gray-300 w-24 text-right"/>
|
||||
</div>
|
||||
<div>
|
||||
boot limit<br/>
|
||||
<input name="ivb" bind:value={configuration.i.v.b} type="number" min="2.5" max="3.5" step="0.1" class="h-10 rounded-r-md shadow-sm border-gray-300 w-24 text-right"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<input type="hidden" name="d" value="true"/>
|
||||
<div class="mt-3">
|
||||
<label><input type="checkbox" name="ds" value="true" bind:checked={configuration.d.s} class="rounded mb-1"/> Enable debugging</label>
|
||||
</div>
|
||||
{#if configuration.d.s}
|
||||
<div class="my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Debug can cause sudden reboots. Do not leave on!</div>
|
||||
<div class="my-1">
|
||||
<label><input type="checkbox" name="dt" value="true" bind:checked={configuration.d.t} class="rounded mb-1"/> Enable telnet</label>
|
||||
</div>
|
||||
{#if configuration.d.t}
|
||||
<div class="my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Telnet is unsafe and should be off when not in use</div>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
<select name="dl" bind:value={configuration.d.l} class="form-control form-control-sh-10 rounded-md shadow-sm border-gray-300m">
|
||||
<option value={1}>Verbose</option>
|
||||
<option value={2}>Debug</option>
|
||||
<option value={3}>Info</option>
|
||||
<option value={4}>Warning</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
SSL
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Prices</strong>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Webhook</strong>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Debugging</strong>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Vendor menu</strong>
|
||||
Board type<br/>
|
||||
GPIO<br/>
|
||||
Vcc<br/>
|
||||
Favico<br/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="font-bold py-2 px-4 rounded bg-blue-500 text-white">Save</button>
|
||||
<button type="submit" class="font-bold py-2 px-4 rounded bg-blue-500 text-white float-right mr-3">Save</button>
|
||||
</form>
|
||||
<Modal active={loadingOrSaving}/>
|
||||
<Mask active={loadingOrSaving} message="Loading configuration"/>
|
||||
|
||||
@ -3,7 +3,7 @@ import { writable } from 'svelte/store';
|
||||
let configuration = {};
|
||||
export const configurationStore = writable(configuration);
|
||||
|
||||
export async function getConfiguration(){
|
||||
export async function getConfiguration() {
|
||||
const response = await fetch("/configuration.json");
|
||||
configuration = (await response.json())
|
||||
configurationStore.set(configuration);
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
import { readable } from 'svelte/store';
|
||||
import { readable, writable } from 'svelte/store';
|
||||
|
||||
let sysinfo = {};
|
||||
export const sysinfoStore = readable(sysinfo, (set) => {
|
||||
async function getSysinfo(){
|
||||
const response = await fetch("/sysinfo.json");
|
||||
sysinfo = (await response.json())
|
||||
set(sysinfo);
|
||||
}
|
||||
getSysinfo();
|
||||
return function stop() {}
|
||||
});
|
||||
|
||||
let sysinfo = {
|
||||
version: '',
|
||||
chip: '',
|
||||
vndcfg: null,
|
||||
usrcfg: null,
|
||||
fwconsent: null,
|
||||
booting: false
|
||||
};
|
||||
export const sysinfoStore = writable(sysinfo);
|
||||
|
||||
export async function getSysinfo() {
|
||||
const response = await fetch("/sysinfo.json");
|
||||
sysinfo = (await response.json())
|
||||
sysinfoStore.set(sysinfo);
|
||||
};
|
||||
|
||||
let data = {};
|
||||
export const dataStore = readable(data, (set) => {
|
||||
@ -17,6 +23,9 @@ export const dataStore = readable(data, (set) => {
|
||||
const response = await fetch("/data.json");
|
||||
data = (await response.json())
|
||||
set(data);
|
||||
if(sysinfo.booting) {
|
||||
getSysinfo();
|
||||
}
|
||||
}
|
||||
const interval = setInterval(getData, 5000);
|
||||
getData();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script></script>
|
||||
|
||||
<!-- Heroicons -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
|
||||
@ -1,14 +1,34 @@
|
||||
<script>
|
||||
import { Link } from "svelte-navigator";
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import GitHubLogo from './../assets/github.svg';
|
||||
import Uptime from "./Uptime.svelte";
|
||||
import Badge from './Badge.svelte';
|
||||
import Clock from './Clock.svelte';
|
||||
import GearIcon from './GearIcon.svelte';
|
||||
import InfoIcon from "./InfoIcon.svelte";
|
||||
import HelpIcon from "./HelpIcon.svelte";
|
||||
import ReloadIcon from "./ReloadIcon.svelte";
|
||||
|
||||
export let data = {}
|
||||
export let sysinfo = {}
|
||||
let timestamp = new Date(0);
|
||||
|
||||
async function reboot() {
|
||||
const response = await fetch('/reboot', {
|
||||
method: 'POST'
|
||||
});
|
||||
let res = (await response.json())
|
||||
}
|
||||
|
||||
const askReload = function() {
|
||||
if(confirm('Are you sure you want to reboot the device?')) {
|
||||
sysinfoStore.update(s => {
|
||||
s.booting = true;
|
||||
return s;
|
||||
});
|
||||
reboot();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<nav class="bg-violet-600 p-1 rounded-md mx-2">
|
||||
@ -22,10 +42,10 @@
|
||||
<div class="flex-none my-auto">Free mem: {data.m ? (data.m/1000).toFixed(1) : '-'}kb</div>
|
||||
</div>
|
||||
<div class="flex-auto my-auto justify-center p-2">
|
||||
<Badge title="ESP" text={data.v > 0 ? data.v.toFixed(2)+"V" : "ESP"} color={data.em === 1 ? 'green' : data.em === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="HAN" text="HAN" color={data.hm === 1 ? 'green' : data.hm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="WiFi" text={data.r ? data.r.toFixed(0)+"dBm" : "WiFi"} color={data.wm === 1 ? 'green' : data.wm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="MQTT" text="MQTT" color={data.mm === 1 ? 'green' : data.mm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="ESP" text={sysinfo.booting ? 'Booting' : data.v > 0 ? data.v.toFixed(2)+"V" : "ESP"} color={sysinfo.booting ? 'yellow' : data.em === 1 ? 'green' : data.em === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="HAN" text="HAN" color={sysinfo.booting ? 'gray' : data.hm === 1 ? 'green' : data.hm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="WiFi" text={data.r ? data.r.toFixed(0)+"dBm" : "WiFi"} color={sysinfo.booting ? 'gray' : data.wm === 1 ? 'green' : data.wm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="MQTT" text="MQTT" color={sysinfo.booting ? 'gray' : data.mm === 1 ? 'green' : data.mm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
</div>
|
||||
<div class="flex-auto p-2 flex flex-row-reverse">
|
||||
<div class="flex-none">
|
||||
@ -34,9 +54,18 @@
|
||||
<div class="flex-none my-auto px-2">
|
||||
<Clock timestamp={ data.c ? new Date(data.c * 1000) : new Date(0) } />
|
||||
</div>
|
||||
<div class="flex-none px-2 mt-1">
|
||||
<div class="flex-none px-1 mt-1" title="Configuration">
|
||||
<Link to="/configuration"><GearIcon/></Link>
|
||||
</div>
|
||||
<div class="flex-none px-1 mt-1" title="Configuration">
|
||||
<button on:click={askReload} class={sysinfo.booting ? 'text-yellow-300' : ''}><ReloadIcon/></button>
|
||||
</div>
|
||||
<div class="flex-none px-1 mt-1" title="Device information">
|
||||
<Link to="/status"><InfoIcon/></Link>
|
||||
</div>
|
||||
<div class="flex-none px-1 mt-1" title="Device information">
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki" target='_blank' rel="noreferrer"><HelpIcon/></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
6
lib/SvelteUi/app/src/lib/HelpIcon.svelte
Normal file
6
lib/SvelteUi/app/src/lib/HelpIcon.svelte
Normal file
@ -0,0 +1,6 @@
|
||||
<script></script>
|
||||
<!-- Heroicons -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
|
||||
</svg>
|
||||
|
||||
@ -42,3 +42,50 @@ export function zeropad(num) {
|
||||
while (num.length < 2) num = "0" + num;
|
||||
return num;
|
||||
}
|
||||
|
||||
export function boardtype(c, b) {
|
||||
switch(b) {
|
||||
case 5:
|
||||
switch(c) {
|
||||
case 'esp8266':
|
||||
return "Pow-K (GPIO12)";
|
||||
case 'esp32s2':
|
||||
return "Pow-K+";
|
||||
}
|
||||
case 7:
|
||||
switch(c) {
|
||||
case 'esp8266':
|
||||
return "Pow-U (GPIO12)";
|
||||
case 'esp32s2':
|
||||
return "Pow-U+";
|
||||
}
|
||||
case 6:
|
||||
return "Pow-P1";
|
||||
case 51:
|
||||
return "Wemos S2 mini";
|
||||
case 50:
|
||||
return "Generic ESP32-S2";
|
||||
case 201:
|
||||
return "Wemos LOLIN D32";
|
||||
case 202:
|
||||
return "Adafruit HUZZAH32";
|
||||
case 203:
|
||||
return "DevKitC";
|
||||
case 200:
|
||||
return "Generic ESP32";
|
||||
case 2:
|
||||
return "HAN Reader 2.0 by Max Spencer";
|
||||
case 0:
|
||||
return "Custom hardware by Roar Fredriksen";
|
||||
case 1:
|
||||
return "Kamstrup module by Egil Opsahl"
|
||||
case 3:
|
||||
return "Pow-K (UART0)";
|
||||
case 4:
|
||||
return "Pow-U (UART0)";
|
||||
case 101:
|
||||
return "Wemos D1 mini";
|
||||
case 100:
|
||||
return "Generic ESP8266";
|
||||
}
|
||||
}
|
||||
|
||||
6
lib/SvelteUi/app/src/lib/InfoIcon.svelte
Normal file
6
lib/SvelteUi/app/src/lib/InfoIcon.svelte
Normal file
@ -0,0 +1,6 @@
|
||||
<script></script>
|
||||
<!-- Heroicons -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
||||
</svg>
|
||||
|
||||
14
lib/SvelteUi/app/src/lib/Mask.svelte
Normal file
14
lib/SvelteUi/app/src/lib/Mask.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
export let active;
|
||||
export let message;
|
||||
</script>
|
||||
|
||||
{#if active}
|
||||
<div class="z-50" aria-modal="true">
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-50 flex items-center justify-center">
|
||||
{#if message}
|
||||
<div class="bg-white m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700 w-96">{message}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@ -1,10 +0,0 @@
|
||||
<script>
|
||||
export let active;
|
||||
</script>
|
||||
|
||||
{#if active}
|
||||
<div class="z-10" aria-modal="true">
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-50"></div>
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
@ -34,6 +34,6 @@
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<path d="{ describeArc(150, 150, 115, 210, 510) }" stroke="#eee" fill="none" stroke-width="55"/>
|
||||
<path d="{ describeArc(150, 150, 115, 210, 210 + (510*pct/100)) }" stroke={color} fill="none" stroke-width="55"/>
|
||||
<path d="{ describeArc(150, 150, 115, 210, 210 + (300*pct/100)) }" stroke={color} fill="none" stroke-width="55"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
6
lib/SvelteUi/app/src/lib/ReloadIcon.svelte
Normal file
6
lib/SvelteUi/app/src/lib/ReloadIcon.svelte
Normal file
@ -0,0 +1,6 @@
|
||||
<script></script>
|
||||
<!-- Heroicons -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
|
||||
92
lib/SvelteUi/app/src/lib/SetupModal.svelte
Normal file
92
lib/SvelteUi/app/src/lib/SetupModal.svelte
Normal file
@ -0,0 +1,92 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import Mask from './Mask.svelte'
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
let staticIp = false;
|
||||
let ntpDhcp = true;
|
||||
|
||||
let loadingOrSaving = false;
|
||||
async function handleSubmit(e) {
|
||||
loadingOrSaving = true;
|
||||
const formData = new FormData(e.target)
|
||||
const data = new URLSearchParams()
|
||||
for (let field of formData) {
|
||||
const [key, value] = field
|
||||
data.append(key, value)
|
||||
}
|
||||
|
||||
const response = await fetch('/save', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
});
|
||||
let res = (await response.json())
|
||||
loadingOrSaving = false;
|
||||
|
||||
sysinfoStore.update(s => {
|
||||
s.usrcfg = res.success;
|
||||
s.booting = res.reboot;
|
||||
return s;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div class="z-10" aria-modal="true">
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-50 flex items-center justify-center">
|
||||
<div class="bg-white m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700 w-96">
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="s" value="true"/>
|
||||
<strong class="text-sm">Setup</strong>
|
||||
<div class="my-3">
|
||||
SSID<br/>
|
||||
<input name="ss" type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
PSK<br/>
|
||||
<input name="sp" type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div>
|
||||
Hostname:
|
||||
<input name="sh" type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full" maxlength="32" pattern="[a-z0-9_-]+" placeholder="Optional, ex.: ams-reader" value="ams-{sysinfo.chipId}"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label><input type="checkbox" name="sm" value="static" class="rounded mb-1" bind:checked={staticIp} /> Static IP</label>
|
||||
{#if staticIp}
|
||||
<br/>
|
||||
<div class="flex">
|
||||
<input name="si" type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full" required={staticIp}/>
|
||||
<select name="su" class="h-10 rounded-r-md shadow-sm border-l-0 border-gray-300" required={staticIp}>
|
||||
<option value="255.255.255.0">/24</option>
|
||||
<option value="255.255.0.0">/16</option>
|
||||
<option value="255.0.0.0">/8</option>
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if staticIp}
|
||||
<div class="my-3 flex">
|
||||
<div>
|
||||
Gateway<br/>
|
||||
<input name="sg" type="text" class="h-10 rounded-l-md shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
<div>
|
||||
DNS<br/>
|
||||
<input name="sd" type="text" class="h-10 rounded-r-md border-l-0 shadow-sm border-gray-300 w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-3">
|
||||
<label><input type="checkbox" name="sf" value="true" class="rounded mb-1"/> Enable OTA upgrade (implies data collection)</label><br/>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Data-collection-on-OTA-firmware-upgrade" target="_blank" class="text-blue-600 hover:text-blue-800">Read more</a>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<button type="submit" class="font-bold py-1 px-4 rounded bg-blue-500 text-white float-right">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Mask active={loadingOrSaving} message="Saving your configuration to the device"/>
|
||||
55
lib/SvelteUi/app/src/lib/StatusPage.svelte
Normal file
55
lib/SvelteUi/app/src/lib/StatusPage.svelte
Normal file
@ -0,0 +1,55 @@
|
||||
<script>
|
||||
import { metertype, boardtype } from './Helpers.js';
|
||||
import { getSysinfo } from './DataStores.js';
|
||||
|
||||
export let sysinfo = {}
|
||||
export let data = {}
|
||||
|
||||
getSysinfo();
|
||||
</script>
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Device information</strong>
|
||||
<div class="my-3">
|
||||
Chip: {sysinfo.chip}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Device: {boardtype(sysinfo.chip, sysinfo.board)}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Firmware version: {sysinfo.version}
|
||||
</div>
|
||||
</div>
|
||||
{#if sysinfo.meter}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Meter</strong>
|
||||
<div class="my-3">
|
||||
Manufacturer: {metertype(sysinfo.meter.mfg)}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Model: {sysinfo.meter.model}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
ID: {sysinfo.meter.id}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if sysinfo.net}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<strong class="text-sm">Network</strong>
|
||||
<div class="my-3">
|
||||
IP: {sysinfo.net.ip}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Mask: {sysinfo.net.mask}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
Gateway: {sysinfo.net.gw}
|
||||
</div>
|
||||
<div class="my-3">
|
||||
DNS: {sysinfo.net.dns1} {#if sysinfo.net.dns2 != '0.0.0.0'}/ {sysinfo.net.dns2}{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
80
lib/SvelteUi/app/src/lib/UartSelectOptions.svelte
Normal file
80
lib/SvelteUi/app/src/lib/UartSelectOptions.svelte
Normal file
@ -0,0 +1,80 @@
|
||||
<script>
|
||||
export let chip;
|
||||
</script>
|
||||
|
||||
{#if chip == 'esp8266'}
|
||||
<option value={3}>UART0</option>
|
||||
<option value={113}>UART2</option>
|
||||
<option value={4}>GPIO4</option>
|
||||
<option value={5}>GPIO5</option>
|
||||
<option value={9}>GPIO9</option>
|
||||
<option value={10}>GPIO10</option>
|
||||
<option value={12}>GPIO12</option>
|
||||
<option value={13}>GPIO13</option>
|
||||
<option value={14}>GPIO14</option>
|
||||
<option value={15}>GPIO15</option>
|
||||
<option value={16}>GPIO16</option>
|
||||
{/if}
|
||||
{#if chip == 'esp32' || chip == 'esp32solo'}
|
||||
<option value={3}>UART0</option>
|
||||
<option value={9}>UART1</option>
|
||||
<option value={16}>UART2</option>
|
||||
<option value={4}>GPIO4</option>
|
||||
<option value={5}>GPIO5</option>
|
||||
<option value={6}>GPIO6</option>
|
||||
<option value={7}>GPIO7</option>
|
||||
<option value={8}>GPIO8</option>
|
||||
<option value={10}>GPIO10</option>
|
||||
<option value={11}>GPIO11</option>
|
||||
<option value={12}>GPIO12</option>
|
||||
<option value={13}>GPIO13</option>
|
||||
<option value={14}>GPIO14</option>
|
||||
<option value={15}>GPIO15</option>
|
||||
<option value={17}>GPIO17</option>
|
||||
<option value={18}>GPIO18</option>
|
||||
<option value={19}>GPIO19</option>
|
||||
<option value={21}>GPIO21</option>
|
||||
<option value={22}>GPIO22</option>
|
||||
<option value={23}>GPIO23</option>
|
||||
<option value={25}>GPIO25</option>
|
||||
<option value={32}>GPIO32</option>
|
||||
<option value={33}>GPIO33</option>
|
||||
<option value={34}>GPIO34</option>
|
||||
<option value={35}>GPIO35</option>
|
||||
<option value={36}>GPIO36</option>
|
||||
<option value={39}>GPIO39</option>
|
||||
{/if}
|
||||
{#if chip == 'esp32s2'}
|
||||
<option value={3}>UART0</option>
|
||||
<option value={18}>UART1</option>
|
||||
<option value={4}>GPIO4</option>
|
||||
<option value={5}>GPIO5</option>
|
||||
<option value={6}>GPIO6</option>
|
||||
<option value={7}>GPIO7</option>
|
||||
<option value={8}>GPIO8</option>
|
||||
<option value={9}>GPIO9</option>
|
||||
<option value={10}>GPIO10</option>
|
||||
<option value={11}>GPIO11</option>
|
||||
<option value={12}>GPIO12</option>
|
||||
<option value={13}>GPIO13</option>
|
||||
<option value={14}>GPIO14</option>
|
||||
<option value={15}>GPIO15</option>
|
||||
<option value={16}>GPIO16</option>
|
||||
<option value={17}>GPIO17</option>
|
||||
<option value={19}>GPIO19</option>
|
||||
<option value={21}>GPIO21</option>
|
||||
<option value={22}>GPIO22</option>
|
||||
<option value={23}>GPIO23</option>
|
||||
<option value={25}>GPIO25</option>
|
||||
<option value={32}>GPIO32</option>
|
||||
<option value={33}>GPIO33</option>
|
||||
<option value={34}>GPIO34</option>
|
||||
<option value={35}>GPIO35</option>
|
||||
<option value={36}>GPIO36</option>
|
||||
<option value={39}>GPIO39</option>
|
||||
<option value={40}>GPIO40</option>
|
||||
<option value={41}>GPIO41</option>
|
||||
<option value={42}>GPIO42</option>
|
||||
<option value={43}>GPIO43</option>
|
||||
<option value={44}>GPIO44</option>
|
||||
{/if}
|
||||
61
lib/SvelteUi/app/src/lib/VendorModal.svelte
Normal file
61
lib/SvelteUi/app/src/lib/VendorModal.svelte
Normal file
@ -0,0 +1,61 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import BoardTypeSelectOptions from './BoardTypeSelectOptions.svelte';
|
||||
import UartSelectOptions from './UartSelectOptions.svelte';
|
||||
import Mask from './Mask.svelte'
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
let loadingOrSaving = false;
|
||||
async function handleSubmit(e) {
|
||||
loadingOrSaving = true;
|
||||
const formData = new FormData(e.target)
|
||||
const data = new URLSearchParams()
|
||||
for (let field of formData) {
|
||||
const [key, value] = field
|
||||
data.append(key, value)
|
||||
}
|
||||
|
||||
const response = await fetch('/save', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
});
|
||||
let res = (await response.json())
|
||||
loadingOrSaving = false;
|
||||
|
||||
sysinfoStore.update(s => {
|
||||
s.vndcfg = res.success;
|
||||
s.booting = res.reboot;
|
||||
return s;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="z-10" aria-modal="true">
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-50 flex items-center justify-center">
|
||||
<div class="bg-white m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700 w-96">
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="v" value="true"/>
|
||||
<strong class="text-sm">Vendor configuration</strong>
|
||||
<div class="my-3">
|
||||
Board type<br/>
|
||||
<select name="b" class="h-10 rounded-md shadow-sm border-gray-300 p-0 w-full" bind:value={sysinfo.board}>
|
||||
<BoardTypeSelectOptions chip={sysinfo.chip}/>
|
||||
</select>
|
||||
</div>
|
||||
{#if sysinfo.board && sysinfo.board > 20}
|
||||
<div class="my-3">
|
||||
HAN GPIO<br/>
|
||||
<select name="h" class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<UartSelectOptions chip={sysinfo.chip}/>
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-3">
|
||||
<button type="submit" class="font-bold py-1 px-4 rounded bg-blue-500 text-white float-right">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Mask active={loadingOrSaving} message="Saving device configuration" />
|
||||
@ -17,14 +17,15 @@ export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.235",
|
||||
"/data.json": "http://192.168.233.244",
|
||||
"/energyprice.json": "http://192.168.233.235",
|
||||
"/dayplot.json": "http://192.168.233.235",
|
||||
"/monthplot.json": "http://192.168.233.235",
|
||||
"/temperature.json": "http://192.168.233.235",
|
||||
"/sysinfo.json": "http://192.168.233.244",
|
||||
"/configuration.json": "http://192.168.233.244",
|
||||
"/save": "http://192.168.233.244"
|
||||
"/save": "http://192.168.233.244",
|
||||
"/reboot": "http://192.168.233.244"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -82,9 +82,11 @@ private:
|
||||
void monthplotJson();
|
||||
void energyPriceJson();
|
||||
void temperatureJson();
|
||||
void wifiScanJson();
|
||||
|
||||
void configurationJson();
|
||||
void handleSave();
|
||||
void reboot();
|
||||
|
||||
void notFound();
|
||||
};
|
||||
|
||||
@ -35,6 +35,7 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
|
||||
// TODO
|
||||
server.on(F("/"), HTTP_GET, std::bind(&AmsWebServer::indexHtml, this));
|
||||
server.on(F("/configuration"), HTTP_GET, std::bind(&AmsWebServer::indexHtml, this));
|
||||
server.on(F("/status"), HTTP_GET, std::bind(&AmsWebServer::indexHtml, this));
|
||||
server.on(F("/index.css"), HTTP_GET, std::bind(&AmsWebServer::indexCss, this));
|
||||
server.on(F("/index.js"), HTTP_GET, std::bind(&AmsWebServer::indexJs, this));
|
||||
server.on(F("/github.svg"), HTTP_GET, std::bind(&AmsWebServer::githubSvg, this));
|
||||
@ -45,8 +46,11 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
|
||||
server.on(F("/energyprice.json"), HTTP_GET, std::bind(&AmsWebServer::energyPriceJson, this));
|
||||
server.on(F("/temperature.json"), HTTP_GET, std::bind(&AmsWebServer::temperatureJson, this));
|
||||
|
||||
server.on(F("/wifiscan.json"), HTTP_GET, std::bind(&AmsWebServer::wifiScanJson, this));
|
||||
|
||||
server.on(F("/configuration.json"), HTTP_GET, std::bind(&AmsWebServer::configurationJson, this));
|
||||
server.on(F("/save"), HTTP_POST, std::bind(&AmsWebServer::handleSave, this));
|
||||
server.on(F("/reboot"), HTTP_POST, std::bind(&AmsWebServer::reboot, this));
|
||||
|
||||
server.onNotFound(std::bind(&AmsWebServer::notFound, this));
|
||||
|
||||
@ -132,7 +136,7 @@ void AmsWebServer::githubSvg() {
|
||||
void AmsWebServer::sysinfoJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /sysinfo.json over http...\n");
|
||||
|
||||
DynamicJsonDocument doc(256);
|
||||
DynamicJsonDocument doc(512);
|
||||
doc["version"] = VERSION;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
doc["chip"] = "esp32s2";
|
||||
@ -144,6 +148,32 @@ void AmsWebServer::sysinfoJson() {
|
||||
doc["chip"] = "esp8266";
|
||||
#endif
|
||||
|
||||
uint16_t chipId;
|
||||
#if defined(ESP32)
|
||||
chipId = ESP.getEfuseMac();
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
#endif
|
||||
doc["chipId"] = String(chipId, HEX);
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
doc["board"] = sys.boardType;
|
||||
doc["vndcfg"] = sys.vendorConfigured;
|
||||
doc["usrcfg"] = sys.userConfigured;
|
||||
doc["fwconsent"] = sys.dataCollectionConsent;
|
||||
doc["country"] = sys.country;
|
||||
|
||||
doc["net"]["ip"] = WiFi.localIP().toString();
|
||||
doc["net"]["mask"] = WiFi.subnetMask().toString();
|
||||
doc["net"]["gw"] = WiFi.gatewayIP().toString();
|
||||
doc["net"]["dns1"] = WiFi.dnsIP(0).toString();
|
||||
doc["net"]["dns2"] = WiFi.dnsIP(1).toString();
|
||||
|
||||
doc["meter"]["mfg"] = meterState->getMeterType();
|
||||
doc["meter"]["model"] = meterState->getMeterModel();
|
||||
doc["meter"]["id"] = meterState->getMeterId();
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
}
|
||||
@ -578,59 +608,189 @@ void AmsWebServer::configurationJson() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
DynamicJsonDocument doc(2048);
|
||||
doc["version"] = VERSION;
|
||||
|
||||
NtpConfig ntpConfig;
|
||||
config->getNtpConfig(ntpConfig);
|
||||
WiFiConfig wifiConfig;
|
||||
config->getWiFiConfig(wifiConfig);
|
||||
WebConfig webConfig;
|
||||
config->getWebConfig(webConfig);
|
||||
doc["general"]["zone"] = "Europe/Oslo";
|
||||
doc["general"]["host"] = wifiConfig.hostname;
|
||||
doc["general"]["sec"] = webConfig.security;
|
||||
doc["general"]["user"] = webConfig.username;
|
||||
doc["general"]["pass"] = webConfig.password;
|
||||
|
||||
if(ntpConfig.offset == 0 && ntpConfig.summerOffset == 0)
|
||||
doc["g"]["t"] = "UTC";
|
||||
else if(ntpConfig.offset == 360 && ntpConfig.summerOffset == 360)
|
||||
doc["g"]["t"] = "CET/CEST";
|
||||
|
||||
doc["g"]["h"] = wifiConfig.hostname;
|
||||
doc["g"]["s"] = webConfig.security;
|
||||
doc["g"]["u"] = webConfig.username;
|
||||
doc["g"]["p"] = strlen(webConfig.password) > 0 ? "***" : "";
|
||||
|
||||
bool encen = false;
|
||||
for(uint8_t i = 0; i < 16; i++) {
|
||||
if(meterConfig->encryptionKey[i] > 0) {
|
||||
encen = true;
|
||||
}
|
||||
}
|
||||
|
||||
config->getMeterConfig(*meterConfig);
|
||||
doc["meter"]["baud"] = meterConfig->baud;
|
||||
doc["meter"]["par"] = meterConfig->parity;
|
||||
doc["meter"]["inv"] = meterConfig->invert;
|
||||
doc["meter"]["dist"] = meterConfig->distributionSystem;
|
||||
doc["meter"]["fuse"] = meterConfig->mainFuse;
|
||||
doc["meter"]["prod"] = meterConfig->productionCapacity;
|
||||
doc["meter"]["enc"] = toHex(meterConfig->encryptionKey, 16);
|
||||
doc["meter"]["auth"] = toHex(meterConfig->authenticationKey, 16);
|
||||
doc["m"]["b"] = meterConfig->baud;
|
||||
doc["m"]["p"] = meterConfig->parity;
|
||||
doc["m"]["i"] = meterConfig->invert;
|
||||
doc["m"]["d"] = meterConfig->distributionSystem;
|
||||
doc["m"]["f"] = meterConfig->mainFuse;
|
||||
doc["m"]["r"] = meterConfig->productionCapacity;
|
||||
doc["m"]["e"]["e"] = encen;
|
||||
doc["m"]["e"]["k"] = toHex(meterConfig->encryptionKey, 16);
|
||||
doc["m"]["e"]["a"] = toHex(meterConfig->authenticationKey, 16);
|
||||
doc["m"]["m"]["e"] = meterConfig->wattageMultiplier > 1 || meterConfig->voltageMultiplier > 1 || meterConfig->amperageMultiplier > 1 || meterConfig->accumulatedMultiplier > 1;
|
||||
doc["m"]["m"]["w"] = meterConfig->wattageMultiplier / 1000.0;
|
||||
doc["m"]["m"]["v"] = meterConfig->voltageMultiplier / 1000.0;
|
||||
doc["m"]["m"]["a"] = meterConfig->amperageMultiplier / 1000.0;
|
||||
doc["m"]["m"]["c"] = meterConfig->accumulatedMultiplier / 1000.0;
|
||||
|
||||
// TODO: Tariff thresholds
|
||||
// TODO: Multipliers
|
||||
EnergyAccountingConfig eac;
|
||||
config->getEnergyAccountingConfig(eac);
|
||||
doc["t"]["t"][0] = eac.thresholds[0];
|
||||
doc["t"]["t"][1] = eac.thresholds[1];
|
||||
doc["t"]["t"][2] = eac.thresholds[2];
|
||||
doc["t"]["t"][3] = eac.thresholds[3];
|
||||
doc["t"]["t"][4] = eac.thresholds[4];
|
||||
doc["t"]["t"][5] = eac.thresholds[5];
|
||||
doc["t"]["t"][6] = eac.thresholds[6];
|
||||
doc["t"]["t"][7] = eac.thresholds[7];
|
||||
doc["t"]["t"][8] = eac.thresholds[8];
|
||||
doc["t"]["t"][9] = eac.thresholds[9];
|
||||
doc["t"]["h"] = eac.hours;
|
||||
|
||||
doc["wifi"]["ssid"] = wifiConfig.ssid;
|
||||
doc["wifi"]["psk"] = wifiConfig.psk;
|
||||
doc["wifi"]["pwr"] = wifiConfig.power / 10.0;
|
||||
doc["wifi"]["sleep"] = wifiConfig.sleep;
|
||||
doc["w"]["s"] = wifiConfig.ssid;
|
||||
doc["w"]["p"] = strlen(wifiConfig.psk) > 0 ? "***" : "";
|
||||
doc["w"]["w"] = wifiConfig.power / 10.0;
|
||||
doc["w"]["z"] = wifiConfig.sleep;
|
||||
|
||||
NtpConfig ntpConfig;
|
||||
config->getNtpConfig(ntpConfig);
|
||||
doc["net"]["mode"] = strlen(wifiConfig.ip) > 0 ? "static" : "dhcp";
|
||||
doc["net"]["ip"] = wifiConfig.ip;
|
||||
doc["net"]["mask"] = wifiConfig.subnet;
|
||||
doc["net"]["gw"] = wifiConfig.gateway;
|
||||
doc["net"]["dns1"] = wifiConfig.dns1;
|
||||
doc["net"]["dns2"] = wifiConfig.dns2;
|
||||
doc["net"]["mdns"] = wifiConfig.mdns;
|
||||
doc["net"]["ntp1"] = ntpConfig.server;
|
||||
doc["net"]["ntpdhcp"] = ntpConfig.dhcp;
|
||||
doc["n"]["m"] = strlen(wifiConfig.ip) > 0 ? "static" : "dhcp";
|
||||
doc["n"]["i"] = wifiConfig.ip;
|
||||
doc["n"]["s"] = wifiConfig.subnet;
|
||||
doc["n"]["g"] = wifiConfig.gateway;
|
||||
doc["n"]["d1"] = wifiConfig.dns1;
|
||||
doc["n"]["d2"] = wifiConfig.dns2;
|
||||
doc["n"]["d"] = wifiConfig.mdns;
|
||||
doc["n"]["n1"] = ntpConfig.server;
|
||||
doc["n"]["h"] = ntpConfig.dhcp;
|
||||
|
||||
MqttConfig mqttConfig;
|
||||
config->getMqttConfig(mqttConfig);
|
||||
doc["mqtt"]["host"] = mqttConfig.host;
|
||||
doc["mqtt"]["port"] = mqttConfig.port;
|
||||
doc["mqtt"]["user"] = mqttConfig.username;
|
||||
doc["mqtt"]["pass"] = mqttConfig.password;
|
||||
doc["mqtt"]["clid"] = mqttConfig.clientId;
|
||||
doc["mqtt"]["pub"] = mqttConfig.publishTopic;
|
||||
doc["mqtt"]["mode"] = mqttConfig.payloadFormat;
|
||||
doc["mqtt"]["ssl"] = mqttConfig.ssl;
|
||||
doc["q"]["h"] = mqttConfig.host;
|
||||
doc["q"]["p"] = mqttConfig.port;
|
||||
doc["q"]["u"] = mqttConfig.username;
|
||||
doc["q"]["a"] = strlen(mqttConfig.password) > 0 ? "***" : "";
|
||||
doc["q"]["c"] = mqttConfig.clientId;
|
||||
doc["q"]["b"] = mqttConfig.publishTopic;
|
||||
doc["q"]["m"] = mqttConfig.payloadFormat;
|
||||
doc["q"]["s"]["e"] = mqttConfig.ssl;
|
||||
|
||||
if(LittleFS.begin()) {
|
||||
doc["q"]["s"]["c"] = LittleFS.exists(FILE_MQTT_CA);
|
||||
doc["q"]["s"]["r"] = LittleFS.exists(FILE_MQTT_CERT);
|
||||
doc["q"]["s"]["k"] = LittleFS.exists(FILE_MQTT_KEY);
|
||||
LittleFS.end();
|
||||
} else {
|
||||
doc["q"]["s"]["c"] = false;
|
||||
doc["q"]["s"]["r"] = false;
|
||||
doc["q"]["s"]["k"] = false;
|
||||
}
|
||||
|
||||
EntsoeConfig entsoe;
|
||||
config->getEntsoeConfig(entsoe);
|
||||
doc["p"]["e"] = strlen(entsoe.token) > 0;
|
||||
doc["p"]["t"] = entsoe.token;
|
||||
doc["p"]["r"] = entsoe.area;
|
||||
doc["p"]["c"] = entsoe.currency;
|
||||
doc["p"]["m"] = entsoe.multiplier / 1000.0;
|
||||
|
||||
DebugConfig debugConfig;
|
||||
config->getDebugConfig(debugConfig);
|
||||
doc["d"]["s"] = debugConfig.serial;
|
||||
doc["d"]["t"] = debugConfig.telnet;
|
||||
doc["d"]["l"] = debugConfig.level;
|
||||
|
||||
GpioConfig gpioConfig;
|
||||
config->getGpioConfig(gpioConfig);
|
||||
if(gpioConfig.hanPin == 0xff)
|
||||
doc["i"]["h"] = nullptr;
|
||||
else
|
||||
doc["i"]["h"] = gpioConfig.hanPin;
|
||||
|
||||
if(gpioConfig.apPin == 0xff)
|
||||
doc["i"]["a"] = nullptr;
|
||||
else
|
||||
doc["i"]["a"] = gpioConfig.apPin;
|
||||
|
||||
if(gpioConfig.ledPin == 0xff)
|
||||
doc["i"]["l"]["p"] = nullptr;
|
||||
else
|
||||
doc["i"]["l"]["p"] = gpioConfig.ledPin;
|
||||
|
||||
doc["i"]["l"]["i"] = gpioConfig.ledInverted;
|
||||
|
||||
if(gpioConfig.ledPinRed == 0xff)
|
||||
doc["i"]["r"]["r"] = nullptr;
|
||||
else
|
||||
doc["i"]["r"]["r"] = gpioConfig.ledPinRed;
|
||||
|
||||
if(gpioConfig.ledPinGreen == 0xff)
|
||||
doc["i"]["r"]["g"] = nullptr;
|
||||
else
|
||||
doc["i"]["r"]["g"] = gpioConfig.ledPinGreen;
|
||||
|
||||
if(gpioConfig.ledPinBlue == 0xff)
|
||||
doc["i"]["r"]["b"] = nullptr;
|
||||
else
|
||||
doc["i"]["r"]["b"] = gpioConfig.ledPinBlue;
|
||||
|
||||
doc["i"]["r"]["i"] = gpioConfig.ledRgbInverted;
|
||||
|
||||
if(gpioConfig.tempSensorPin == 0xff)
|
||||
doc["i"]["t"]["d"] = nullptr;
|
||||
else
|
||||
doc["i"]["t"]["d"] = gpioConfig.tempSensorPin;
|
||||
|
||||
if(gpioConfig.tempAnalogSensorPin == 0xff)
|
||||
doc["i"]["t"]["a"] = nullptr;
|
||||
else
|
||||
doc["i"]["t"]["a"] = gpioConfig.tempAnalogSensorPin;
|
||||
|
||||
if(gpioConfig.vccPin == 0xff)
|
||||
doc["i"]["v"]["p"] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["p"] = gpioConfig.vccPin;
|
||||
|
||||
if(gpioConfig.vccOffset == 0)
|
||||
doc["i"]["v"]["o"] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["o"] = gpioConfig.vccOffset / 100.0;
|
||||
|
||||
if(gpioConfig.vccMultiplier == 0)
|
||||
doc["i"]["v"]["m"] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["m"] = gpioConfig.vccMultiplier / 1000.0;
|
||||
|
||||
if(gpioConfig.vccResistorVcc == 0)
|
||||
doc["i"]["v"]["d"]["v"] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["d"]["v"] = gpioConfig.vccResistorVcc;
|
||||
|
||||
if(gpioConfig.vccResistorGnd == 0)
|
||||
doc["i"]["v"]["d"]["g"] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["d"]["g"] = gpioConfig.vccResistorGnd;
|
||||
|
||||
if(gpioConfig.vccBootLimit == 0)
|
||||
doc["i"]["v"]["b"] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["b"] = gpioConfig.vccBootLimit / 10.0;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
@ -640,86 +800,253 @@ void AmsWebServer::handleSave() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
if(server.hasArg(F("meter")) && server.arg(F("meter")) == F("true")) {
|
||||
bool success = true;
|
||||
if(server.hasArg(F("v")) && server.arg(F("v")) == F("true")) {
|
||||
int boardType = server.arg(F("b")).toInt();
|
||||
int hanPin = server.arg(F("h")).toInt();
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
switch(boardType) {
|
||||
case 5: // Pow-K+
|
||||
case 7: // Pow-U+
|
||||
case 6: // Pow-P1
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 16;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPinRed = 13;
|
||||
gpioConfig->ledPinGreen = 14;
|
||||
gpioConfig->ledRgbInverted = true;
|
||||
gpioConfig->vccPin = 10;
|
||||
gpioConfig->vccResistorGnd = 22;
|
||||
gpioConfig->vccResistorVcc = 33;
|
||||
break;
|
||||
case 51: // Wemos S2 mini
|
||||
gpioConfig->ledPin = 15;
|
||||
gpioConfig->ledInverted = false;
|
||||
gpioConfig->apPin = 0;
|
||||
case 50: // Generic ESP32-S2
|
||||
gpioConfig->hanPin = hanPin > 0 ? hanPin : 18;
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
}
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#elif defined(ESP32)
|
||||
switch(boardType) {
|
||||
case 201: // D32
|
||||
gpioConfig->hanPin = hanPin > 0 ? hanPin : 16;
|
||||
gpioConfig->apPin = 4;
|
||||
gpioConfig->ledPin = 5;
|
||||
gpioConfig->ledInverted = true;
|
||||
break;
|
||||
case 202: // Feather
|
||||
case 203: // DevKitC
|
||||
case 200: // ESP32
|
||||
gpioConfig->hanPin = hanPin > 0 ? hanPin : 16;
|
||||
gpioConfig->ledPin = 2;
|
||||
gpioConfig->ledInverted = false;
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
}
|
||||
#elif defined(ESP8266)
|
||||
switch(boardType) {
|
||||
case 2: // spenceme
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->vccBootLimit = 33;
|
||||
case 0: // roarfred
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
gpioConfig->ledInverted = true;
|
||||
gpioConfig->tempSensorPin = 5;
|
||||
break;
|
||||
case 1: // Arnio Kamstrup
|
||||
case 3: // Pow-K UART0
|
||||
case 4: // Pow-U UART0
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
gpioConfig->ledInverted = true;
|
||||
gpioConfig->ledPinRed = 13;
|
||||
gpioConfig->ledPinGreen = 14;
|
||||
gpioConfig->ledRgbInverted = true;
|
||||
break;
|
||||
case 5: // Pow-K GPIO12
|
||||
case 7: // Pow-U GPIO12
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 12;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
gpioConfig->ledInverted = true;
|
||||
gpioConfig->ledPinRed = 13;
|
||||
gpioConfig->ledPinGreen = 14;
|
||||
gpioConfig->ledRgbInverted = true;
|
||||
break;
|
||||
case 101: // D1
|
||||
gpioConfig->hanPin = hanPin > 0 ? hanPin : 5;
|
||||
gpioConfig->apPin = 4;
|
||||
gpioConfig->ledPin = 2;
|
||||
gpioConfig->ledInverted = true;
|
||||
gpioConfig->vccMultiplier = 1100;
|
||||
break;
|
||||
case 100: // ESP8266
|
||||
gpioConfig->hanPin = hanPin > 0 ? hanPin : 3;
|
||||
gpioConfig->ledPin = 2;
|
||||
gpioConfig->ledInverted = true;
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
sys.boardType = success ? boardType : 0xFF;
|
||||
sys.vendorConfigured = success;
|
||||
config->setSystemConfig(sys);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("s")) && server.arg(F("s")) == F("true")) {
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
|
||||
config->clear();
|
||||
|
||||
WiFiConfig wifi;
|
||||
config->clearWifi(wifi);
|
||||
|
||||
strcpy(wifi.ssid, server.arg(F("ss")).c_str());
|
||||
|
||||
String psk = server.arg(F("sp"));
|
||||
if(!psk.equals("***")) {
|
||||
strcpy(wifi.psk, psk.c_str());
|
||||
}
|
||||
wifi.mode = 1; // WIFI_STA
|
||||
|
||||
if(server.hasArg(F("sm")) && server.arg(F("sm")) == "static") {
|
||||
strcpy(wifi.ip, server.arg(F("si")).c_str());
|
||||
strcpy(wifi.gateway, server.arg(F("sg")).c_str());
|
||||
strcpy(wifi.subnet, server.arg(F("su")).c_str());
|
||||
strcpy(wifi.dns1, server.arg(F("sd")).c_str());
|
||||
}
|
||||
|
||||
if(server.hasArg(F("sh")) && !server.arg(F("sh")).isEmpty()) {
|
||||
strcpy(wifi.hostname, server.arg(F("sh")).c_str());
|
||||
wifi.mdns = true;
|
||||
} else {
|
||||
wifi.mdns = false;
|
||||
}
|
||||
|
||||
switch(sys.boardType) {
|
||||
case 6: // Pow-P1
|
||||
meterConfig->baud = 115200;
|
||||
meterConfig->parity = 3; // 8N1
|
||||
break;
|
||||
case 3: // Pow-K UART0
|
||||
case 5: // Pow-K+
|
||||
meterConfig->parity = 3; // 8N1
|
||||
case 2: // spenceme
|
||||
case 50: // Generic ESP32-S2
|
||||
case 51: // Wemos S2 mini
|
||||
meterConfig->baud = 2400;
|
||||
wifi.sleep = 1; // Modem sleep
|
||||
break;
|
||||
case 4: // Pow-U UART0
|
||||
case 7: // Pow-U+
|
||||
wifi.sleep = 2; // Light sleep
|
||||
break;
|
||||
}
|
||||
config->setWiFiConfig(wifi);
|
||||
config->setMeterConfig(*meterConfig);
|
||||
|
||||
sys.userConfigured = success;
|
||||
//TODO sys.country
|
||||
sys.dataCollectionConsent = server.hasArg(F("sf")) && server.arg(F("sf")) == F("true") ? 1 : 2;
|
||||
config->setSystemConfig(sys);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("m")) && server.arg(F("m")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received meter config"));
|
||||
config->getMeterConfig(*meterConfig);
|
||||
meterConfig->baud = server.arg(F("meter_baud")).toInt();
|
||||
meterConfig->parity = server.arg(F("meter_par")).toInt();
|
||||
meterConfig->invert = server.hasArg(F("meter_inv")) && server.arg(F("meter_inv")) == F("true");
|
||||
meterConfig->distributionSystem = server.arg(F("meter_dist")).toInt();
|
||||
meterConfig->mainFuse = server.arg(F("meter_fuse")).toInt();
|
||||
meterConfig->productionCapacity = server.arg(F("meter_prod")).toInt();
|
||||
meterConfig->baud = server.arg(F("mb")).toInt();
|
||||
meterConfig->parity = server.arg(F("mp")).toInt();
|
||||
meterConfig->invert = server.hasArg(F("mi")) && server.arg(F("mi")) == F("true");
|
||||
meterConfig->distributionSystem = server.arg(F("md")).toInt();
|
||||
meterConfig->mainFuse = server.arg(F("mf")).toInt();
|
||||
meterConfig->productionCapacity = server.arg(F("mr")).toInt();
|
||||
maxPwr = 0;
|
||||
|
||||
String encryptionKeyHex = server.arg(F("meter_enc"));
|
||||
String encryptionKeyHex = server.arg(F("mek"));
|
||||
if(!encryptionKeyHex.isEmpty()) {
|
||||
encryptionKeyHex.replace(F("0x"), F(""));
|
||||
fromHex(meterConfig->encryptionKey, encryptionKeyHex, 16);
|
||||
}
|
||||
|
||||
String authenticationKeyHex = server.arg(F("meter_auth"));
|
||||
String authenticationKeyHex = server.arg(F("mea"));
|
||||
if(!authenticationKeyHex.isEmpty()) {
|
||||
authenticationKeyHex.replace(F("0x"), F(""));
|
||||
fromHex(meterConfig->authenticationKey, authenticationKeyHex, 16);
|
||||
}
|
||||
|
||||
meterConfig->wattageMultiplier = server.arg(F("mmw")).toDouble() * 1000;
|
||||
meterConfig->voltageMultiplier = server.arg(F("mmv")).toDouble() * 1000;
|
||||
meterConfig->amperageMultiplier = server.arg(F("mma")).toDouble() * 1000;
|
||||
meterConfig->accumulatedMultiplier = server.arg(F("mmc")).toDouble() * 1000;
|
||||
config->setMeterConfig(*meterConfig);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("ma")) && server.arg(F("ma")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received meter advanced config"));
|
||||
config->getMeterConfig(*meterConfig);
|
||||
meterConfig->wattageMultiplier = server.arg(F("wm")).toDouble() * 1000;
|
||||
meterConfig->voltageMultiplier = server.arg(F("vm")).toDouble() * 1000;
|
||||
meterConfig->amperageMultiplier = server.arg(F("am")).toDouble() * 1000;
|
||||
meterConfig->accumulatedMultiplier = server.arg(F("cm")).toDouble() * 1000;
|
||||
config->setMeterConfig(*meterConfig);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("wifi")) && server.arg(F("wifi")) == F("true")) {
|
||||
if(server.hasArg(F("w")) && server.arg(F("w")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received WiFi config"));
|
||||
WiFiConfig wifi;
|
||||
config->getWiFiConfig(wifi);
|
||||
strcpy(wifi.ssid, server.arg(F("wifi_ssid")).c_str());
|
||||
strcpy(wifi.psk, server.arg(F("wifi_psk")).c_str());
|
||||
wifi.power = server.arg(F("wifi_pwr")).toFloat() * 10;
|
||||
wifi.sleep = server.arg(F("wifi_sleep")).toInt();
|
||||
strcpy(wifi.ssid, server.arg(F("ws")).c_str());
|
||||
String psk = server.arg(F("wp"));
|
||||
if(!psk.equals("***")) {
|
||||
strcpy(wifi.psk, psk.c_str());
|
||||
}
|
||||
wifi.power = server.arg(F("ww")).toFloat() * 10;
|
||||
wifi.sleep = server.arg(F("wz")).toInt();
|
||||
config->setWiFiConfig(wifi);
|
||||
|
||||
if(server.hasArg(F("nm")) && server.arg(F("nm")) == "static") {
|
||||
strcpy(wifi.ip, server.arg(F("ni")).c_str());
|
||||
strcpy(wifi.gateway, server.arg(F("ng")).c_str());
|
||||
strcpy(wifi.subnet, server.arg(F("ns")).c_str());
|
||||
strcpy(wifi.dns1, server.arg(F("nd1")).c_str());
|
||||
strcpy(wifi.dns2, server.arg(F("nd2")).c_str());
|
||||
}
|
||||
wifi.mdns = server.hasArg(F("nd")) && server.arg(F("nd")) == F("true");
|
||||
config->setWiFiConfig(wifi);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("net")) && server.arg(F("net")) == F("true")) {
|
||||
WiFiConfig wifi;
|
||||
config->getWiFiConfig(wifi);
|
||||
if(server.hasArg(F("net_mode")) && server.arg(F("net_mode")) == "static") {
|
||||
strcpy(wifi.ip, server.arg(F("net_ip")).c_str());
|
||||
strcpy(wifi.gateway, server.arg(F("net_gw")).c_str());
|
||||
strcpy(wifi.subnet, server.arg(F("net_sn")).c_str());
|
||||
strcpy(wifi.dns1, server.arg(F("net_dns1")).c_str());
|
||||
strcpy(wifi.dns2, server.arg(F("net_dns2")).c_str());
|
||||
}
|
||||
wifi.mdns = server.hasArg(F("net_mdns")) && server.arg(F("net_mdns")) == F("true");
|
||||
config->setWiFiConfig(wifi);
|
||||
|
||||
if(server.hasArg(F("ntp")) && server.arg(F("ntp")) == F("true")) {
|
||||
NtpConfig ntp;
|
||||
config->getNtpConfig(ntp);
|
||||
ntp.dhcp = server.hasArg(F("net_ntpdhcp")) && server.arg(F("net_ntpdhcp")) == F("true");
|
||||
strcpy(ntp.server, server.arg(F("net_ntp1")).c_str());
|
||||
ntp.enable = true;
|
||||
ntp.dhcp = server.hasArg(F("ntpd")) && server.arg(F("ntpd")) == F("true");
|
||||
strcpy(ntp.server, server.arg(F("ntph")).c_str());
|
||||
config->setNtpConfig(ntp);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("mqtt")) && server.arg(F("mqtt")) == F("true")) {
|
||||
if(server.hasArg(F("q")) && server.arg(F("q")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received MQTT config"));
|
||||
MqttConfig mqtt;
|
||||
if(server.hasArg(F("mqtt_host")) && !server.arg(F("mqtt_host")).isEmpty()) {
|
||||
strcpy(mqtt.host, server.arg(F("mqtt_host")).c_str());
|
||||
strcpy(mqtt.clientId, server.arg(F("mqtt_clid")).c_str());
|
||||
strcpy(mqtt.publishTopic, server.arg(F("mqtt_pub")).c_str());
|
||||
strcpy(mqtt.subscribeTopic, server.arg(F("mqtt_sub")).c_str());
|
||||
strcpy(mqtt.username, server.arg(F("mqtt_user")).c_str());
|
||||
strcpy(mqtt.password, server.arg(F("mqtt_pass")).c_str());
|
||||
mqtt.payloadFormat = server.arg(F("mqtt_mode")).toInt();
|
||||
mqtt.ssl = server.arg(F("mqtt_ssl")) == F("true");
|
||||
if(server.hasArg(F("qh")) && !server.arg(F("qh")).isEmpty()) {
|
||||
strcpy(mqtt.host, server.arg(F("qh")).c_str());
|
||||
strcpy(mqtt.clientId, server.arg(F("qc")).c_str());
|
||||
strcpy(mqtt.publishTopic, server.arg(F("qb")).c_str());
|
||||
strcpy(mqtt.subscribeTopic, server.arg(F("qr")).c_str());
|
||||
strcpy(mqtt.username, server.arg(F("qu")).c_str());
|
||||
String pass = server.arg(F("qp"));
|
||||
if(!pass.equals("***")) {
|
||||
strcpy(mqtt.password, pass.c_str());
|
||||
}
|
||||
mqtt.payloadFormat = server.arg(F("qm")).toInt();
|
||||
mqtt.ssl = server.arg(F("qs")) == F("true");
|
||||
|
||||
mqtt.port = server.arg(F("mqtt_port")).toInt();
|
||||
mqtt.port = server.arg(F("qp")).toInt();
|
||||
if(mqtt.port == 0) {
|
||||
mqtt.port = mqtt.ssl ? 8883 : 1883;
|
||||
}
|
||||
@ -742,12 +1069,15 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
|
||||
if(server.hasArg(F("general")) && server.arg(F("general")) == F("true")) {
|
||||
if(server.hasArg(F("g")) && server.arg(F("g")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received web config"));
|
||||
webConfig.security = server.arg(F("general_sec")).toInt();
|
||||
webConfig.security = server.arg(F("gs")).toInt();
|
||||
if(webConfig.security > 0) {
|
||||
strcpy(webConfig.username, server.arg(F("general_user")).c_str());
|
||||
strcpy(webConfig.password, server.arg(F("general_pass")).c_str());
|
||||
strcpy(webConfig.username, server.arg(F("gu")).c_str());
|
||||
String pass = server.arg(F("gp"));
|
||||
if(!pass.equals("***")) {
|
||||
strcpy(webConfig.password, pass.c_str());
|
||||
}
|
||||
debugger->setPassword(webConfig.password);
|
||||
} else {
|
||||
strcpy_P(webConfig.username, PSTR(""));
|
||||
@ -758,42 +1088,54 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
WiFiConfig wifi;
|
||||
config->getWiFiConfig(wifi);
|
||||
if(server.hasArg(F("general_host")) && !server.arg(F("general_host")).isEmpty()) {
|
||||
strcpy(wifi.hostname, server.arg(F("general_host")).c_str());
|
||||
if(server.hasArg(F("gh")) && !server.arg(F("gh")).isEmpty()) {
|
||||
strcpy(wifi.hostname, server.arg(F("gh")).c_str());
|
||||
}
|
||||
config->setWiFiConfig(wifi);
|
||||
|
||||
NtpConfig ntp;
|
||||
config->getNtpConfig(ntp);
|
||||
String tz = server.arg(F("gt"));
|
||||
if(tz.equals("UTC")) {
|
||||
ntp.offset = 0;
|
||||
ntp.summerOffset = 0;
|
||||
} else if(tz.equals("CET/CEST")) {
|
||||
ntp.offset = 360;
|
||||
ntp.summerOffset = 360;
|
||||
}
|
||||
config->setNtpConfig(ntp);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("gc")) && server.arg(F("gc")) == F("true")) {
|
||||
if(server.hasArg(F("i")) && server.arg(F("i")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received GPIO config"));
|
||||
gpioConfig->hanPin = server.hasArg(F("h")) && !server.arg(F("h")).isEmpty() ? server.arg(F("h")).toInt() : 3;
|
||||
gpioConfig->ledPin = server.hasArg(F("l")) && !server.arg(F("l")).isEmpty() ? server.arg(F("l")).toInt() : 0xFF;
|
||||
gpioConfig->ledInverted = server.hasArg(F("i")) && server.arg(F("i")) == F("true");
|
||||
gpioConfig->ledPinRed = server.hasArg(F("r")) && !server.arg(F("r")).isEmpty() ? server.arg(F("r")).toInt() : 0xFF;
|
||||
gpioConfig->ledPinGreen = server.hasArg(F("e")) && !server.arg(F("e")).isEmpty() ? server.arg(F("e")).toInt() : 0xFF;
|
||||
gpioConfig->ledPinBlue = server.hasArg(F("b")) && !server.arg(F("b")).isEmpty() ? server.arg(F("b")).toInt() : 0xFF;
|
||||
gpioConfig->ledRgbInverted = server.hasArg(F("n")) && server.arg(F("n")) == F("true");
|
||||
gpioConfig->apPin = server.hasArg(F("a")) && !server.arg(F("a")).isEmpty() ? server.arg(F("a")).toInt() : 0xFF;
|
||||
gpioConfig->tempSensorPin = server.hasArg(F("t")) && !server.arg(F("t")).isEmpty() ?server.arg(F("t")).toInt() : 0xFF;
|
||||
gpioConfig->tempAnalogSensorPin = server.hasArg(F("m")) && !server.arg(F("m")).isEmpty() ?server.arg(F("m")).toInt() : 0xFF;
|
||||
gpioConfig->vccPin = server.hasArg(F("v")) && !server.arg(F("v")).isEmpty() ? server.arg(F("v")).toInt() : 0xFF;
|
||||
gpioConfig->vccOffset = server.hasArg(F("o")) && !server.arg(F("o")).isEmpty() ? server.arg(F("o")).toFloat() * 100 : 0;
|
||||
gpioConfig->vccMultiplier = server.hasArg(F("u")) && !server.arg(F("u")).isEmpty() ? server.arg(F("u")).toFloat() * 1000 : 1000;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("c")) && !server.arg(F("c")).isEmpty() ? server.arg(F("c")).toFloat() * 10 : 0;
|
||||
gpioConfig->vccResistorGnd = server.hasArg(F("d")) && !server.arg(F("d")).isEmpty() ? server.arg(F("d")).toInt() : 0;
|
||||
gpioConfig->vccResistorVcc = server.hasArg(F("s")) && !server.arg(F("s")).isEmpty() ? server.arg(F("s")).toInt() : 0;
|
||||
gpioConfig->hanPin = server.hasArg(F("ih")) && !server.arg(F("ih")).isEmpty() ? server.arg(F("ih")).toInt() : 3;
|
||||
gpioConfig->ledPin = server.hasArg(F("ilp")) && !server.arg(F("ilp")).isEmpty() ? server.arg(F("ilp")).toInt() : 0xFF;
|
||||
gpioConfig->ledInverted = server.hasArg(F("ili")) && server.arg(F("ili")) == F("true");
|
||||
gpioConfig->ledPinRed = server.hasArg(F("irr")) && !server.arg(F("irr")).isEmpty() ? server.arg(F("irr")).toInt() : 0xFF;
|
||||
gpioConfig->ledPinGreen = server.hasArg(F("irg")) && !server.arg(F("irg")).isEmpty() ? server.arg(F("irg")).toInt() : 0xFF;
|
||||
gpioConfig->ledPinBlue = server.hasArg(F("irb")) && !server.arg(F("irb")).isEmpty() ? server.arg(F("irb")).toInt() : 0xFF;
|
||||
gpioConfig->ledRgbInverted = server.hasArg(F("iri")) && server.arg(F("iri")) == F("true");
|
||||
gpioConfig->apPin = server.hasArg(F("ia")) && !server.arg(F("ia")).isEmpty() ? server.arg(F("ia")).toInt() : 0xFF;
|
||||
gpioConfig->tempSensorPin = server.hasArg(F("itd")) && !server.arg(F("itd")).isEmpty() ?server.arg(F("itd")).toInt() : 0xFF;
|
||||
gpioConfig->tempAnalogSensorPin = server.hasArg(F("ita")) && !server.arg(F("ita")).isEmpty() ?server.arg(F("ita")).toInt() : 0xFF;
|
||||
gpioConfig->vccPin = server.hasArg(F("ivp")) && !server.arg(F("ivp")).isEmpty() ? server.arg(F("ivp")).toInt() : 0xFF;
|
||||
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toFloat() * 100 : 0;
|
||||
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toFloat() * 1000 : 1000;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toFloat() * 10 : 0;
|
||||
gpioConfig->vccResistorGnd = server.hasArg(F("ivdg")) && !server.arg(F("ivdg")).isEmpty() ? server.arg(F("ivdg")).toInt() : 0;
|
||||
gpioConfig->vccResistorVcc = server.hasArg(F("ivdv")) && !server.arg(F("ivdv")).isEmpty() ? server.arg(F("ivdv")).toInt() : 0;
|
||||
config->setGpioConfig(*gpioConfig);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("debugConfig")) && server.arg(F("debugConfig")) == F("true")) {
|
||||
if(server.hasArg(F("d")) && server.arg(F("d")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received Debug config"));
|
||||
DebugConfig debug;
|
||||
config->getDebugConfig(debug);
|
||||
bool active = debug.serial || debug.telnet;
|
||||
|
||||
debug.telnet = server.hasArg(F("debugTelnet")) && server.arg(F("debugTelnet")) == F("true");
|
||||
debug.serial = server.hasArg(F("debugSerial")) && server.arg(F("debugSerial")) == F("true");
|
||||
debug.level = server.arg(F("debugLevel")).toInt();
|
||||
debug.telnet = server.hasArg(F("dt")) && server.arg(F("dt")) == F("true");
|
||||
debug.serial = server.hasArg(F("ds")) && server.arg(F("ds")) == F("true");
|
||||
debug.level = server.arg(F("dl")).toInt();
|
||||
|
||||
if(debug.telnet || debug.serial) {
|
||||
if(webConfig.security > 0) {
|
||||
@ -815,29 +1157,17 @@ void AmsWebServer::handleSave() {
|
||||
config->setDebugConfig(debug);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("nc")) && server.arg(F("nc")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received NTP config"));
|
||||
NtpConfig ntp {
|
||||
server.hasArg(F("n")) && server.arg(F("n")) == F("true"),
|
||||
server.hasArg(F("nd")) && server.arg(F("nd")) == F("true"),
|
||||
static_cast<int16_t>(server.arg(F("o")).toInt() / 10),
|
||||
static_cast<int16_t>(server.arg(F("so")).toInt() / 10)
|
||||
};
|
||||
strcpy(ntp.server, server.arg(F("ns")).c_str());
|
||||
config->setNtpConfig(ntp);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("ec")) && server.arg(F("ec")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received ENTSO-E config"));
|
||||
if(server.hasArg(F("p")) && server.arg(F("p")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received price API config"));
|
||||
EntsoeConfig entsoe;
|
||||
strcpy(entsoe.token, server.arg(F("et")).c_str());
|
||||
strcpy(entsoe.area, server.arg(F("ea")).c_str());
|
||||
strcpy(entsoe.currency, server.arg(F("ecu")).c_str());
|
||||
entsoe.multiplier = server.arg(F("em")).toFloat() * 1000;
|
||||
strcpy(entsoe.token, server.arg(F("pt")).c_str());
|
||||
strcpy(entsoe.area, server.arg(F("pr")).c_str());
|
||||
strcpy(entsoe.currency, server.arg(F("pc")).c_str());
|
||||
entsoe.multiplier = server.arg(F("pm")).toFloat() * 1000;
|
||||
config->setEntsoeConfig(entsoe);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("cc")) && server.arg(F("cc")) == F("true")) {
|
||||
if(server.hasArg(F("t")) && server.arg(F("t")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received energy accounting config"));
|
||||
EnergyAccountingConfig eac;
|
||||
eac.thresholds[0] = server.arg(F("t0")).toInt();
|
||||
@ -849,7 +1179,7 @@ void AmsWebServer::handleSave() {
|
||||
eac.thresholds[6] = server.arg(F("t6")).toInt();
|
||||
eac.thresholds[7] = server.arg(F("t7")).toInt();
|
||||
eac.thresholds[8] = server.arg(F("t8")).toInt();
|
||||
eac.hours = server.arg(F("h")).toInt();
|
||||
eac.hours = server.arg(F("th")).toInt();
|
||||
config->setEnergyAccountingConfig(eac);
|
||||
}
|
||||
|
||||
@ -857,7 +1187,7 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
if (config->save()) {
|
||||
doc["success"] = true;
|
||||
doc["success"] = success;
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Successfully saved."));
|
||||
if(config->isWifiChanged() || performRestart) {
|
||||
performRestart = true;
|
||||
@ -868,11 +1198,13 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
} else {
|
||||
doc["success"] = false;
|
||||
doc["reboot"] = false;
|
||||
}
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
delay(100);
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(performRestart || rebootForUpgrade) {
|
||||
if(ds != NULL) {
|
||||
@ -888,3 +1220,34 @@ void AmsWebServer::handleSave() {
|
||||
performRestart = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::wifiScanJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /wifiscan.json over http...\n");
|
||||
|
||||
DynamicJsonDocument doc(512);
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
}
|
||||
|
||||
void AmsWebServer::reboot() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /reboot over http...\n");
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["reboot"] = true;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Rebooting"));
|
||||
delay(1000);
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
performRestart = false;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user