mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-21 18:25:17 +00:00
Even more v2.2
This commit is contained in:
parent
8e54f23367
commit
902e43979b
@ -5,6 +5,7 @@
|
||||
|
||||
#define EEPROM_SIZE 1024*3
|
||||
#define EEPROM_CHECK_SUM 100 // Used to check if config is stored. Change if structure changes
|
||||
#define EEPROM_CLEARED_INDICATOR 0xFC
|
||||
#define EEPROM_CONFIG_ADDRESS 0
|
||||
#define EEPROM_TEMP_CONFIG_ADDRESS 2048
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
#include "AmsConfiguration.h"
|
||||
|
||||
bool AmsConfiguration::getSystemConfig(SystemConfig& config) {
|
||||
if(hasConfig()) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
uint8_t configVersion = EEPROM.read(EEPROM_CONFIG_ADDRESS);
|
||||
if(configVersion == EEPROM_CHECK_SUM || configVersion == EEPROM_CLEARED_INDICATOR) {
|
||||
EEPROM.get(CONFIG_SYSTEM_START, config);
|
||||
EEPROM.end();
|
||||
return true;
|
||||
@ -573,6 +574,15 @@ void AmsConfiguration::ackEnergyAccountingChange() {
|
||||
|
||||
void AmsConfiguration::clear() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
SystemConfig sys;
|
||||
EEPROM.get(CONFIG_SYSTEM_START, sys);
|
||||
sys.userConfigured = false;
|
||||
sys.dataCollectionConsent = 0;
|
||||
strcpy(sys.country, "");
|
||||
EEPROM.put(CONFIG_SYSTEM_START, sys);
|
||||
|
||||
|
||||
MeterConfig meter;
|
||||
clearMeter(meter);
|
||||
EEPROM.put(CONFIG_METER_START, meter);
|
||||
@ -605,7 +615,7 @@ void AmsConfiguration::clear() {
|
||||
clearEnergyAccountingConfig(eac);
|
||||
EEPROM.put(CONFIG_ENERGYACCOUNTING_START, eac);
|
||||
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, -1);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CLEARED_INDICATOR);
|
||||
EEPROM.commit();
|
||||
EEPROM.end();
|
||||
}
|
||||
@ -833,8 +843,8 @@ bool AmsConfiguration::relocateConfig96() {
|
||||
SystemConfig sys;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_SYSTEM_START, sys);
|
||||
sys.vendorConfigured = false;
|
||||
sys.userConfigured = false;
|
||||
sys.vendorConfigured = true;
|
||||
sys.userConfigured = true;
|
||||
sys.dataCollectionConsent = 0;
|
||||
strcpy(sys.country, "");
|
||||
EEPROM.put(CONFIG_SYSTEM_START, sys);
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
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 VendorPanel from './lib/VendorPanel.svelte';
|
||||
import SetupPanel from './lib/SetupPanel.svelte';
|
||||
import Mask from './lib/Mask.svelte';
|
||||
|
||||
let sysinfo = {};
|
||||
@ -25,7 +25,13 @@
|
||||
<Router>
|
||||
<Header data={data} sysinfo={sysinfo}/>
|
||||
<Route path="/">
|
||||
{#if sysinfo.vndcfg === false}
|
||||
<VendorPanel sysinfo={sysinfo}/>
|
||||
{:else if sysinfo.usrcfg === false}
|
||||
<SetupPanel sysinfo={sysinfo}/>
|
||||
{:else}
|
||||
<Dashboard data={data}/>
|
||||
{/if}
|
||||
</Route>
|
||||
<Route path="/configuration">
|
||||
<ConfigurationPanel sysinfo={sysinfo}/>
|
||||
@ -34,19 +40,10 @@
|
||||
<StatusPage sysinfo={sysinfo} data={data}/>
|
||||
</Route>
|
||||
</Router>
|
||||
|
||||
{#if sysinfo.upgrading}
|
||||
<Mask active=true message="Device is upgrading, please wait"/>
|
||||
{:else if sysinfo.vndcfg === false}
|
||||
{#if sysinfo.booting}
|
||||
{:else if sysinfo.booting}
|
||||
<Mask active=true message="Device is booting, please wait"/>
|
||||
{:else}
|
||||
<VendorModal sysinfo={sysinfo}/>
|
||||
{/if}
|
||||
{:else if sysinfo.usrcfg === false}
|
||||
{#if sysinfo.booting}
|
||||
<Mask active=true message="Device is booting, please wait"/>
|
||||
{:else}
|
||||
<SetupModal sysinfo={sysinfo}/>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -40,8 +40,6 @@
|
||||
});
|
||||
}
|
||||
config = {
|
||||
height: 250,
|
||||
width: 224,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: 0,
|
||||
|
||||
@ -1,30 +1,37 @@
|
||||
<script>
|
||||
export let config;
|
||||
|
||||
let width;
|
||||
let height;
|
||||
let barWidth;
|
||||
let xScale;
|
||||
let yScale;
|
||||
let heightAvailable;
|
||||
|
||||
$: {
|
||||
let innerWidth = config.width - (config.padding.left + config.padding.right);
|
||||
heightAvailable = height-(config.title ? 20 : 0);
|
||||
let innerWidth = width - (config.padding.left + config.padding.right);
|
||||
barWidth = innerWidth / config.points.length;
|
||||
|
||||
let yPerUnit = (config.height-config.padding.top-config.padding.bottom)/(config.y.max-config.y.min);
|
||||
let yPerUnit = (heightAvailable-config.padding.top-config.padding.bottom)/(config.y.max-config.y.min);
|
||||
|
||||
xScale = function(i) {
|
||||
return (i*barWidth)+config.padding.left;
|
||||
};
|
||||
yScale = function(i) {
|
||||
if(!i) return config.height-config.padding.bottom;
|
||||
if(i > config.y.max) return config.height;
|
||||
let ret = config.height-config.padding.bottom-((i-config.y.min)*yPerUnit);
|
||||
return ret > config.height || ret < 0 ? 0 : ret;
|
||||
if(!i) return heightAvailable-config.padding.bottom;
|
||||
if(i > config.y.max) return heightAvailable;
|
||||
let ret = heightAvailable-config.padding.bottom-((i-config.y.min)*yPerUnit);
|
||||
return ret > heightAvailable || ret < 0 ? 0 : ret;
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="chart" bind:clientWidth={config.width} bind:clientHeight={config.height}>
|
||||
<svg height="{config.height}">
|
||||
<div class="chart" bind:clientWidth={width} bind:clientHeight={height}>
|
||||
{#if config.title}
|
||||
<strong class="text-sm">{config.title}</strong>
|
||||
{/if}
|
||||
<svg height="{heightAvailable}">
|
||||
<!-- y axis -->
|
||||
<g class="axis y-axis">
|
||||
{#each config.y.ticks as tick}
|
||||
@ -38,7 +45,7 @@
|
||||
<!-- x axis -->
|
||||
<g class="axis x-axis">
|
||||
{#each config.x.ticks as point, i}
|
||||
<g class="tick" transform="translate({xScale(i)},{config.height})">
|
||||
<g class="tick" transform="translate({xScale(i)},{heightAvailable})">
|
||||
<text x="{barWidth/2}" y="-4">{point.label}</text>
|
||||
</g>
|
||||
{/each}
|
||||
@ -60,7 +67,7 @@
|
||||
dominant-baseline="middle"
|
||||
text-anchor="{barWidth < 25 ? 'left' : 'middle'}"
|
||||
fill="{yScale(point.value) > yScale(0)-15 ? point.color : 'white'}"
|
||||
transform="rotate({barWidth < 25 ? 90 : 0}, {xScale(i) + (barWidth/2)}, {yScale(point.value) > yScale(0)-12 ? yScale(point.value) - 12 : yScale(point.value)+10})"
|
||||
transform="rotate({barWidth < 25 ? 90 : 0}, {xScale(i) + (barWidth/2)}, {yScale(point.value) > yScale(0)-12 ? yScale(point.value) - 12 : yScale(point.value)+9})"
|
||||
>{point.label}</text>
|
||||
{/each}
|
||||
</g>
|
||||
@ -70,6 +77,7 @@
|
||||
<style>
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@ -53,10 +53,24 @@
|
||||
});
|
||||
getConfiguration();
|
||||
|
||||
let isFactoryReset = false;
|
||||
async function factoryReset() {
|
||||
if(confirm("Are you sure you want to factory reset the device?")) {
|
||||
const data = new URLSearchParams();
|
||||
data.append("perform", "true");
|
||||
const response = await fetch('/reset', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
});
|
||||
let res = (await response.json());
|
||||
isFactoryReset = res.success;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit(e) {
|
||||
loadingOrSaving = true;
|
||||
const formData = new FormData(e.target)
|
||||
const data = new URLSearchParams()
|
||||
const formData = new FormData(e.target);
|
||||
const data = new URLSearchParams();
|
||||
for (let field of formData) {
|
||||
const [key, value] = field
|
||||
data.append(key, value)
|
||||
@ -459,10 +473,6 @@
|
||||
</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}
|
||||
@ -557,6 +567,8 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="font-bold py-2 px-4 rounded bg-blue-500 text-white float-right mr-3">Save</button>
|
||||
<button type="button" on:click={factoryReset} class="font-bold py-2 px-4 rounded bg-red-500 text-white ml-2">Factory reset</button>
|
||||
<button type="submit" class="font-bold py-2 px-4 rounded bg-blue-500 text-white float-right mr-2">Save</button>
|
||||
</form>
|
||||
<Mask active={loadingOrSaving} message="Loading configuration"/>
|
||||
<Mask active={isFactoryReset} message="Device have been factory reset and switched to AP mode"/>
|
||||
|
||||
@ -32,16 +32,20 @@
|
||||
|
||||
<div class="grid xl:grid-cols-6 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2">
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
<PowerGauge val={data.i ? data.i : 0} max={data.im} unit="W" label="Import"/>
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="col-span-2">
|
||||
<PowerGauge val={data.i ? data.i : 0} max={data.im} unit="W" label="Import"/>
|
||||
</div>
|
||||
<div>{data.mt ? metertype(data.mt) : '-'}</div>
|
||||
<div class="text-right">{data.ic ? data.ic.toFixed(1) : '-'} kWh</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if data.om}
|
||||
{#if data.om || data.e > 0}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
<PowerGauge val={data.e ? data.e : 0} max={data.om} unit="W" label="Export"/>
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="col-span-2">
|
||||
<PowerGauge val={data.e ? data.e : 0} max={data.om ? data.om : 10000} unit="W" label="Export"/>
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="text-right">{data.ec ? data.ec.toFixed(1) : '-'} kWh</div>
|
||||
</div>
|
||||
@ -60,18 +64,18 @@
|
||||
<AccountingData data={data.ea} currency={prices.currency}/>
|
||||
</div>
|
||||
{#if prices.currency}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-3 md:col-span-3 sm:col-span-2">
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-3 md:col-span-3 sm:col-span-2 h-64">
|
||||
<PricePlot json={prices}/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2">
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<DayPlot json={dayPlot} />
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2">
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<MonthPlot json={monthPlot} />
|
||||
</div>
|
||||
{#if data.t && data.t != -127 && temperatures.c > 1}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2">
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<TemperaturePlot json={temperatures} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -70,6 +70,7 @@
|
||||
}
|
||||
|
||||
config = {
|
||||
title: "Energy use last 24 hours (kWh)",
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
@ -86,7 +87,5 @@
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Energy use last 24 hours (kWh)</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
|
||||
<BarChart config={config} />
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
<nav class="bg-violet-600 p-1 rounded-md mx-2">
|
||||
<div class="flex flex-wrap space-x-4 text-sm text-gray-300">
|
||||
<div class="flex-none text-lg text-gray-100 p-2">
|
||||
<div class="flex text-lg text-gray-100 p-2">
|
||||
<Link to="/">AMS reader <span>{sysinfo.version}</span></Link>
|
||||
</div>
|
||||
<div class="flex-none my-auto p-2 flex space-x-4">
|
||||
@ -66,12 +66,12 @@
|
||||
<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={sysinfo.booting ? 'Booting' : data.v > 1.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="ESP" text={sysinfo.booting ? 'Booting' : data.v > 2.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.hm === 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.wm === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="MQTT" text="MQTT" color={sysinfo.booting ? 'gray' : data.mm === 1 ? 'green' : data.mm === 2 ? 'yellow' : data.mm === 3 ? 'red' : 'gray'}/>
|
||||
</div>
|
||||
<div class="flex-auto p-2 flex flex-row-reverse">
|
||||
<div class="flex-auto p-2 flex flex-row-reverse flex-wrap">
|
||||
<div class="flex-none">
|
||||
<a class="float-right" href='https://github.com/gskjold/AmsToMqttBridge' target='_blank' rel="noreferrer" aria-label="GitHub"><img class="gh-logo" src={GitHubLogo} alt="GitHub repo"/></a>
|
||||
</div>
|
||||
@ -90,8 +90,8 @@
|
||||
<div class="flex-none px-1 mt-1" title="Documentation">
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki" target='_blank' rel="noreferrer"><HelpIcon/></a>
|
||||
</div>
|
||||
{#if sysinfo.fwconsent && nextVersion}
|
||||
<div class="flex-none px-4 mt-1 text-yellow-500" title="New version: {nextVersion.tag_name}">
|
||||
{#if sysinfo.fwconsent === 1 && nextVersion}
|
||||
<div class="flex-none mr-3 text-yellow-500" title="New version: {nextVersion.tag_name}">
|
||||
<button on:click={askUpgrade} class="flex"><DownloadIcon/> <span class="mt-1">{nextVersion.tag_name}</span></button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -71,6 +71,7 @@
|
||||
}
|
||||
|
||||
config = {
|
||||
title: "Energy use last month (kWh)",
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
@ -87,7 +88,5 @@
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Energy use last month (kWh)</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
|
||||
<BarChart config={config} />
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
}
|
||||
.plot-value {
|
||||
font-size: 1.7rem;
|
||||
//cursor: pointer;
|
||||
}
|
||||
.plot-unit {
|
||||
font-size: 1.0rem;
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
<script>
|
||||
export let pct = 0;
|
||||
export let color = "red";
|
||||
let width = 300;
|
||||
let height = 300;
|
||||
|
||||
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
|
||||
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
|
||||
@ -27,13 +25,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="gauge" bind:clientWidth={width} bind:clientHeight={height}>
|
||||
<svg height="100%"
|
||||
width="100%"
|
||||
viewBox="0 0 300 300"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg" height="100%">
|
||||
<path d="{ describeArc(150, 150, 115, 210, 510) }" stroke="#eee" 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>
|
||||
</svg>
|
||||
|
||||
@ -63,8 +63,7 @@
|
||||
}
|
||||
|
||||
config = {
|
||||
height: 226,
|
||||
width: 1520,
|
||||
title: "Future energy price (" + json.currency + ")",
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
@ -79,7 +78,5 @@
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Future energy price ({json.currency})</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
|
||||
<BarChart config={config} />
|
||||
|
||||
@ -1,124 +0,0 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import Mask from './Mask.svelte'
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
let staticIp = false;
|
||||
let loadingOrSaving = false;
|
||||
|
||||
let tries = 0;
|
||||
function scanForDevice() {
|
||||
var url = "";
|
||||
tries++;
|
||||
|
||||
if(sysinfo.net.ip && tries%3 == 0) {
|
||||
url = "http://" + sysinfo.net.ip;
|
||||
} else if(sysinfo.hostname && tries%3 == 1) {
|
||||
url = "http://" + sysinfo.hostname;
|
||||
} else if(sysinfo.hostname && tries%3 == 2) {
|
||||
url = "http://" + sysinfo.hostname + ".local";
|
||||
} else {
|
||||
url = "";
|
||||
}
|
||||
if(console) console.log("Trying url " + url);
|
||||
|
||||
var retry = function() {
|
||||
setTimeout(scanForDevice, 1000);
|
||||
};
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.timeout = 5000;
|
||||
xhr.addEventListener('abort', retry);
|
||||
xhr.addEventListener('error', retry);
|
||||
xhr.addEventListener('timeout', retry);
|
||||
xhr.addEventListener('load', function(e) {
|
||||
window.location.href = url ? url : "/";
|
||||
});
|
||||
xhr.open("GET", url + "/is-alive", true);
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
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;
|
||||
setTimeout(scanForDevice, 5000);
|
||||
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" bind:value={sysinfo.hostname} 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"/>
|
||||
</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"/>
|
||||
122
lib/SvelteUi/app/src/lib/SetupPanel.svelte
Normal file
122
lib/SvelteUi/app/src/lib/SetupPanel.svelte
Normal file
@ -0,0 +1,122 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import Mask from './Mask.svelte'
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
let staticIp = false;
|
||||
let loadingOrSaving = false;
|
||||
|
||||
let tries = 0;
|
||||
function scanForDevice() {
|
||||
var url = "";
|
||||
tries++;
|
||||
|
||||
if(sysinfo.net.ip && tries%3 == 0) {
|
||||
url = "http://" + sysinfo.net.ip;
|
||||
} else if(sysinfo.hostname && tries%3 == 1) {
|
||||
url = "http://" + sysinfo.hostname;
|
||||
} else if(sysinfo.hostname && tries%3 == 2) {
|
||||
url = "http://" + sysinfo.hostname + ".local";
|
||||
} else {
|
||||
url = "";
|
||||
}
|
||||
if(console) console.log("Trying url " + url);
|
||||
|
||||
var retry = function() {
|
||||
setTimeout(scanForDevice, 1000);
|
||||
};
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.timeout = 5000;
|
||||
xhr.addEventListener('abort', retry);
|
||||
xhr.addEventListener('error', retry);
|
||||
xhr.addEventListener('timeout', retry);
|
||||
xhr.addEventListener('load', function(e) {
|
||||
window.location.href = url ? url : "/";
|
||||
});
|
||||
xhr.open("GET", url + "/is-alive", true);
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
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;
|
||||
setTimeout(scanForDevice, 5000);
|
||||
return s;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div class="bg-white m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<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" bind:value={sysinfo.hostname} 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"/>
|
||||
</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>
|
||||
|
||||
<Mask active={loadingOrSaving} message="Saving your configuration to the device"/>
|
||||
@ -81,13 +81,18 @@
|
||||
</div>
|
||||
<div class="my-2 flex">
|
||||
Latest version:
|
||||
{#if sysinfo.fwconsent && nextVersion && nextVersion.tag_name}
|
||||
<a href={nextVersion.html_url} class="ml-2 text-blue-600 hover:text-blue-800" target='_blank' rel="noreferrer">{nextVersion.tag_name}</a>
|
||||
{#if sysinfo.fwconsent === 1 && nextVersion && nextVersion.tag_name}
|
||||
<div class="flex-none ml-2 text-green-500" title="Install this version">
|
||||
<button on:click={askUpgrade}><DownloadIcon/></button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if sysinfo.fwconsent === 2}
|
||||
<div class="my-2">
|
||||
<div class="my-auto bg-yellow-500 text-yellow-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">You have not consented to OTA firmware upgrade, link to self-upgrade is disabled</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if sysinfo.board == 2 || sysinfo.board == 4 || sysinfo.board == 7 }
|
||||
<div class="my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">
|
||||
{boardtype(sysinfo.chip, sysinfo.board)} must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
}
|
||||
|
||||
config = {
|
||||
title: "Temperature sensors (°C)",
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
@ -66,7 +67,5 @@
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Temperature sensors (°C)</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
|
||||
<BarChart config={config} />
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
<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="vb" bind:value={sysinfo.board} class="h-10 rounded-md shadow-sm border-gray-300 p-0 w-full">
|
||||
<BoardTypeSelectOptions chip={sysinfo.chip}/>
|
||||
</select>
|
||||
</div>
|
||||
{#if sysinfo.board && sysinfo.board > 20}
|
||||
<div class="my-3">
|
||||
HAN GPIO<br/>
|
||||
<select name="vh" 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" />
|
||||
60
lib/SvelteUi/app/src/lib/VendorPanel.svelte
Normal file
60
lib/SvelteUi/app/src/lib/VendorPanel.svelte
Normal file
@ -0,0 +1,60 @@
|
||||
<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="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div class="bg-white m-2 p-3 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<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="vb" bind:value={sysinfo.board} class="h-10 rounded-md shadow-sm border-gray-300 p-0 w-full">
|
||||
<BoardTypeSelectOptions chip={sysinfo.chip}/>
|
||||
</select>
|
||||
</div>
|
||||
{#if sysinfo.board && sysinfo.board > 20}
|
||||
<div class="my-3">
|
||||
HAN GPIO<br/>
|
||||
<select name="vh" 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>
|
||||
<span class="clear-both"> </span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<Mask active={loadingOrSaving} message="Saving device configuration" />
|
||||
@ -39,8 +39,6 @@
|
||||
});
|
||||
}
|
||||
config = {
|
||||
height: 250,
|
||||
width: 224,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
|
||||
@ -17,7 +17,7 @@ export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.229",
|
||||
"/data.json": "http://192.168.233.235",
|
||||
"/energyprice.json": "http://192.168.233.235",
|
||||
"/dayplot.json": "http://192.168.233.235",
|
||||
"/monthplot.json": "http://192.168.233.235",
|
||||
|
||||
@ -94,6 +94,8 @@ private:
|
||||
|
||||
HTTPUpload& uploadFile(const char* path);
|
||||
|
||||
void factoryResetPost();
|
||||
|
||||
void notFound();
|
||||
};
|
||||
|
||||
|
||||
@ -58,6 +58,8 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
|
||||
server.on(F("/upgrade"), HTTP_POST, std::bind(&AmsWebServer::upgrade, this));
|
||||
server.on(F("/firmware"), HTTP_POST, std::bind(&AmsWebServer::firmwarePost, this), std::bind(&AmsWebServer::firmwareUpload, this));
|
||||
server.on(F("/is-alive"), HTTP_GET, std::bind(&AmsWebServer::isAliveCheck, this));
|
||||
|
||||
server.on(F("/reset"), HTTP_POST, std::bind(&AmsWebServer::factoryResetPost, this));
|
||||
|
||||
server.onNotFound(std::bind(&AmsWebServer::notFound, this));
|
||||
|
||||
@ -226,7 +228,7 @@ void AmsWebServer::dataJson() {
|
||||
|
||||
uint8_t espStatus;
|
||||
#if defined(ESP8266)
|
||||
if(vcc == 0) {
|
||||
if(vcc < 2.0) { // Voltage not correct, ESP would not run on this voltage
|
||||
espStatus = 1;
|
||||
} else if(vcc > 3.1 && vcc < 3.5) {
|
||||
espStatus = 1;
|
||||
@ -236,7 +238,7 @@ void AmsWebServer::dataJson() {
|
||||
espStatus = 3;
|
||||
}
|
||||
#elif defined(ESP32)
|
||||
if(vcc == 0) {
|
||||
if(vcc < 2.0) { // Voltage not correct, ESP would not run on this voltage
|
||||
espStatus = 1;
|
||||
} else if(vcc > 2.8 && vcc < 3.5) {
|
||||
espStatus = 1;
|
||||
@ -1010,6 +1012,8 @@ void AmsWebServer::handleSave() {
|
||||
//TODO sys.country
|
||||
sys.dataCollectionConsent = server.hasArg(F("sf")) && server.arg(F("sf")) == F("true") ? 1 : 2;
|
||||
config->setSystemConfig(sys);
|
||||
|
||||
performRestart = true;
|
||||
}
|
||||
|
||||
if(server.hasArg(F("m")) && server.arg(F("m")) == F("true")) {
|
||||
@ -1305,58 +1309,64 @@ void AmsWebServer::reboot() {
|
||||
void AmsWebServer::upgrade() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /upgrade over http...\n");
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["reboot"] = true;
|
||||
doc["success"] = sys.dataCollectionConsent == 1;
|
||||
doc["reboot"] = sys.dataCollectionConsent == 1;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
if(sys.dataCollectionConsent == 1) {
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
String customFirmwareUrl = "";
|
||||
if(server.hasArg(F("url"))) {
|
||||
customFirmwareUrl = server.arg(F("url"));
|
||||
}
|
||||
String customFirmwareUrl = "";
|
||||
if(server.hasArg(F("url"))) {
|
||||
customFirmwareUrl = server.arg(F("url"));
|
||||
}
|
||||
|
||||
String url = customFirmwareUrl.isEmpty() || !customFirmwareUrl.startsWith(F("http")) ? F("http://ams2mqtt.rewiredinvent.no/hub/firmware/update") : customFirmwareUrl;
|
||||
String url = customFirmwareUrl.isEmpty() || !customFirmwareUrl.startsWith(F("http")) ? F("http://ams2mqtt.rewiredinvent.no/hub/firmware/update") : customFirmwareUrl;
|
||||
|
||||
if(server.hasArg(F("version"))) {
|
||||
url += "/" + server.arg(F("version"));
|
||||
}
|
||||
if(server.hasArg(F("version"))) {
|
||||
url += "/" + server.arg(F("version"));
|
||||
}
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate;
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
|
||||
#endif
|
||||
#if defined(ESP8266)
|
||||
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate;
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
|
||||
#endif
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK"));
|
||||
break;
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1457,3 +1467,38 @@ void AmsWebServer::isAliveCheck() {
|
||||
server.sendHeader(F("Access-Control-Allow-Origin"), F("*"));
|
||||
server.send(200);
|
||||
}
|
||||
|
||||
void AmsWebServer::factoryResetPost() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Performing factory reset"));
|
||||
|
||||
bool success = false;
|
||||
if(server.hasArg(F("perform")) && server.arg(F("perform")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Formatting LittleFS"));
|
||||
LittleFS.format();
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Clearing configuration"));
|
||||
config->clear();
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["success"] = success;
|
||||
doc["reboot"] = success;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user