mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-04-25 11:51:43 +00:00
More v2.2
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
||||
<title>AMS reader</title>
|
||||
</head>
|
||||
<body class="bg-gray-100">
|
||||
|
||||
1273
lib/SvelteUi/app/package-lock.json
generated
1273
lib/SvelteUi/app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"@tailwindcss/forms": "^0.5.2",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"http-proxy-middleware": "^2.0.1",
|
||||
"postcss": "^8.4.14",
|
||||
@@ -18,7 +19,9 @@
|
||||
"svelte-navigator": "^3.2.2",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tailwindcss": "^3.1.5",
|
||||
"@tailwindcss/forms": "^0.5.2",
|
||||
"vite": "^3.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"cssnano": "^5.1.14"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const tailwindcss = require("tailwindcss");
|
||||
const autoprefixer = require("autoprefixer");
|
||||
const cssnano = require("cssnano");
|
||||
|
||||
const config = {
|
||||
plugins: [
|
||||
@@ -7,6 +8,7 @@ const config = {
|
||||
tailwindcss(),
|
||||
//But others, like autoprefixer, need to run after,
|
||||
autoprefixer,
|
||||
cssnano()
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import VendorPanel from './lib/VendorPanel.svelte';
|
||||
import SetupPanel from './lib/SetupPanel.svelte';
|
||||
import Mask from './lib/Mask.svelte';
|
||||
import FileUploadComponent from "./lib/FileUploadComponent.svelte";
|
||||
|
||||
let sysinfo = {};
|
||||
sysinfoStore.subscribe(update => {
|
||||
@@ -37,7 +38,16 @@
|
||||
<ConfigurationPanel sysinfo={sysinfo}/>
|
||||
</Route>
|
||||
<Route path="/status">
|
||||
<StatusPage sysinfo={sysinfo} data={data}/>
|
||||
<StatusPage sysinfo={sysinfo}/>
|
||||
</Route>
|
||||
<Route path="/mqtt-ca">
|
||||
<FileUploadComponent title="CA" action="/mqtt-ca"/>
|
||||
</Route>
|
||||
<Route path="/mqtt-cert">
|
||||
<FileUploadComponent title="certificate" action="/mqtt-cert"/>
|
||||
</Route>
|
||||
<Route path="/mqtt-key">
|
||||
<FileUploadComponent title="private key" action="/mqtt-key"/>
|
||||
</Route>
|
||||
</Router>
|
||||
|
||||
|
||||
@@ -5,4 +5,140 @@
|
||||
.gh-logo {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.cnt {
|
||||
@apply bg-white m-2 p-2 rounded shadow-lg
|
||||
}
|
||||
|
||||
.in-pre {
|
||||
@apply flex items-center bg-gray-100 rounded-l-md border border-r-0 border-gray-300 px-3 whitespace-nowrap text-sm
|
||||
}
|
||||
|
||||
.in-post {
|
||||
@apply flex items-center bg-gray-100 rounded-r-md border border-l-0 border-gray-300 px-3 whitespace-nowrap text-sm
|
||||
}
|
||||
|
||||
.in-txt {
|
||||
@apply h-10 shadow-sm border-gray-300 disabled:bg-gray-200
|
||||
}
|
||||
.in-f {
|
||||
@apply in-txt rounded-l-md
|
||||
}
|
||||
.in-m {
|
||||
@apply in-txt border-l-0 w-full
|
||||
}
|
||||
.in-l {
|
||||
@apply in-txt border-l-0 rounded-r-md
|
||||
}
|
||||
.in-s {
|
||||
@apply in-txt rounded-md w-full
|
||||
}
|
||||
.tr {
|
||||
@apply text-right
|
||||
}
|
||||
|
||||
.bd-grn {
|
||||
@apply my-auto bg-green-500 text-green-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-ylo {
|
||||
@apply my-auto bg-yellow-500 text-yellow-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-red {
|
||||
@apply my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-blu {
|
||||
@apply my-auto bg-blue-500 text-blue-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-gry {
|
||||
@apply my-auto bg-gray-500 text-gray-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
|
||||
.btn-pri {
|
||||
@apply py-2 px-4 rounded bg-blue-500 text-white mr-3
|
||||
}
|
||||
|
||||
.pl-root {
|
||||
position: relative;
|
||||
}
|
||||
.pl-ov {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
.pl-val {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
.pl-unt {
|
||||
font-size: 1.0rem;
|
||||
color: grey;
|
||||
}
|
||||
.pl-lab {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tick {
|
||||
font-family: Helvetica, Arial;
|
||||
font-size: 0.85em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.tick line {
|
||||
stroke: #e2e2e2;
|
||||
stroke-dasharray: 2;
|
||||
}
|
||||
|
||||
.tick text {
|
||||
fill: #999;
|
||||
text-anchor: start;
|
||||
}
|
||||
|
||||
.tick.tick-0 line {
|
||||
stroke-dasharray: 0;
|
||||
}
|
||||
|
||||
.tick.tick-green line {
|
||||
stroke: #32d900 !important;
|
||||
}
|
||||
|
||||
.tick.tick-green text {
|
||||
fill: #32d900 !important;
|
||||
}
|
||||
|
||||
.tick.tick-orange line {
|
||||
stroke: #d95600 !important;
|
||||
}
|
||||
|
||||
.tick.tick-orange text {
|
||||
fill: #d95600 !important;
|
||||
}
|
||||
|
||||
.x-axis .tick text {
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.bars rect {
|
||||
stroke: rgb(0,0,0);
|
||||
stroke-opacity: 0.25;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.bars text {
|
||||
font-family: Helvetica, Arial;
|
||||
font-size: 0.85em;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -8,45 +8,47 @@
|
||||
<div class="mx-2 text-sm">
|
||||
<strong>Real time calculation</strong>
|
||||
|
||||
{#if data && data.h !== undefined}
|
||||
<div class="flex">
|
||||
<div>Hour</div>
|
||||
<div class="flex-auto text-right">{data && data.h && data.h.u ? data.h.u.toFixed(2) : '-'} kWh {#if currency && (hasExport)}/ {data && data.h && data.h.c ? data.h.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
<div class="flex-auto text-right">{data.h.u ? data.h.u.toFixed(2) : '-'} kWh {#if currency && (hasExport)}/ {data.h.c ? data.h.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Day</div>
|
||||
<div class="flex-auto text-right">{data && data.d && data.d.u ? data.d.u.toFixed(1) : '-'} kWh {#if currency && (hasExport)}/ {data && data.d && data.d.c ? data.d.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
<div class="flex-auto text-right">{data.d.u ? data.d.u.toFixed(1) : '-'} kWh {#if currency && (hasExport)}/ {data.d.c ? data.d.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Month</div>
|
||||
<div class="flex-auto text-right">{data && data.m && data.m.u ? data.m.u.toFixed(0) : '-'} kWh {#if currency && (hasExport)}/ {data && data.m && data.m.c ? data.m.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
<div class="flex-auto text-right">{data.m.u ? data.m.u.toFixed(0) : '-'} kWh {#if currency && (hasExport)}/ {data.m.c ? data.m.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
{#if hasExport}
|
||||
<div class="flex">
|
||||
<div>Hour</div>
|
||||
<div class="flex-auto text-right">{data && data.h && data.h.p ? data.h.p.toFixed(2) : '-'} kWh {#if currency}/ {data && data.h && data.h.pc ? data.h.pc.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
<div class="flex-auto text-right">{data.h.p ? data.h.p.toFixed(2) : '-'} kWh {#if currency}/ {data.h.pc ? data.h.pc.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Day</div>
|
||||
<div class="flex-auto text-right">{data && data.d && data.d.p ? data.d.p.toFixed(1) : '-'} kWh {#if currency}/ {data && data.d && data.d.pc ? data.d.pc.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
<div class="flex-auto text-right">{data.d.p ? data.d.p.toFixed(1) : '-'} kWh {#if currency}/ {data.d.pc ? data.d.pc.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Month</div>
|
||||
<div class="flex-auto text-right">{data && data.m && data.m.p ? data.m.p.toFixed(0) : '-'} kWh {#if currency}/ {data && data.m && data.m.pc ? data.m.pc.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
<div class="flex-auto text-right">{data.m.p ? data.m.p.toFixed(0) : '-'} kWh {#if currency}/ {data.m.pc ? data.m.pc.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex">
|
||||
<div>Hour</div>
|
||||
<div class="flex-auto text-right">{data && data.h && data.h.c ? data.h.c.toFixed(2) : '-'} {currency}</div>
|
||||
<div class="flex-auto text-right">{data.h.c ? data.h.c.toFixed(2) : '-'} {currency}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Day</div>
|
||||
<div class="flex-auto text-right">{data && data.d && data.d.c ? data.d.c.toFixed(2) : '-'} {currency}</div>
|
||||
<div class="flex-auto text-right">{data.d.c ? data.d.c.toFixed(2) : '-'} {currency}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Month</div>
|
||||
<div class="flex-auto text-right">{data && data.m && data.m.c ? data.m.c.toFixed(2) : '-'} {currency}</div>
|
||||
<div class="flex-auto text-right">{data.m.c ? data.m.c.toFixed(2) : '-'} {currency}</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -4,13 +4,13 @@
|
||||
export let text;
|
||||
</script>
|
||||
{#if color == 'green'}
|
||||
<span title={title} class="my-auto bg-green-500 text-green-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
<span title={title} class="bd-grn">{text}</span>
|
||||
{:else if color === `yellow`}
|
||||
<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>
|
||||
<span title={title} class="bd-ylo">{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>
|
||||
<span title={title} class="bd-red">{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>
|
||||
<span title={title} class="bd-blu">{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>
|
||||
<span title={title} class="bd-gry">{text}</span>
|
||||
{/if}
|
||||
@@ -94,69 +94,3 @@
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tick {
|
||||
font-family: Helvetica, Arial;
|
||||
font-size: .725em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.tick line {
|
||||
stroke: #e2e2e2;
|
||||
stroke-dasharray: 2;
|
||||
}
|
||||
|
||||
.tick text {
|
||||
fill: #999;
|
||||
text-anchor: start;
|
||||
}
|
||||
|
||||
.tick.tick-0 line {
|
||||
stroke-dasharray: 0;
|
||||
}
|
||||
|
||||
.tick.tick-green line {
|
||||
stroke: #32d900 !important;
|
||||
}
|
||||
|
||||
.tick.tick-green text {
|
||||
fill: #32d900 !important;
|
||||
}
|
||||
|
||||
.tick.tick-orange line {
|
||||
stroke: #d95600 !important;
|
||||
}
|
||||
|
||||
.tick.tick-orange text {
|
||||
fill: #d95600 !important;
|
||||
}
|
||||
|
||||
.x-axis .tick text {
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.bars rect {
|
||||
stroke: rgb(0,0,0);
|
||||
stroke-opacity: 0.25;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.bars text {
|
||||
font-family: Helvetica, Arial;
|
||||
font-size: .725em;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import { zeropad, monthnames } from './Helpers.js';
|
||||
|
||||
export let timestamp;
|
||||
let monthnames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
</script>
|
||||
|
||||
{#if Math.abs(new Date().getTime()-timestamp.getTime()) < 300000 }
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
import Mask from './Mask.svelte'
|
||||
import Badge from './Badge.svelte';
|
||||
import HelpIcon from './HelpIcon.svelte';
|
||||
import CountrySelectOptions from './CountrySelectOptions.svelte';
|
||||
import { Link, navigate } from 'svelte-navigator';
|
||||
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
@@ -87,71 +90,95 @@
|
||||
});
|
||||
|
||||
loadingOrSaving = false;
|
||||
getConfiguration();
|
||||
navigate("/");
|
||||
}
|
||||
|
||||
async function reboot() {
|
||||
const response = await fetch('/reboot', {
|
||||
method: 'POST'
|
||||
});
|
||||
let res = (await response.json())
|
||||
}
|
||||
|
||||
const askReboot = function() {
|
||||
if(confirm('Are you sure you want to reboot the device?')) {
|
||||
sysinfoStore.update(s => {
|
||||
s.booting = true;
|
||||
return s;
|
||||
});
|
||||
reboot();
|
||||
}
|
||||
}
|
||||
|
||||
const updateMqttPort = function() {
|
||||
if(configuration.q.s.e) {
|
||||
if(configuration.q.p == 1883) configuration.q.p = 8883;
|
||||
} else {
|
||||
if(configuration.q.p == 8883) configuration.q.p = 1883;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<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">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">General</strong>
|
||||
<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"/>
|
||||
<input name="gh" bind:value={configuration.g.h} type="text" class="in-f 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>
|
||||
Time zone<br/>
|
||||
<select name="gt" bind:value={configuration.g.t} class="in-l">
|
||||
<CountrySelectOptions/>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="p" value="true"/>
|
||||
<div class="my-1">
|
||||
Price region<br/>
|
||||
<select name="pr" bind:value={configuration.p.r} class="in-s">
|
||||
<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 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">
|
||||
<select name="pc" bind:value={configuration.p.c} class="in-f">
|
||||
<option value="NOK">NOK</option>
|
||||
<option value="SEK">SEK</option>
|
||||
<option value="DKK">DKK</option>
|
||||
@@ -160,7 +187,7 @@
|
||||
</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"/>
|
||||
<input name="pm" bind:value={configuration.p.m} type="number" min="0.001" max="1000" step="0.001" class="in-l tr"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,13 +195,13 @@
|
||||
<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"/>
|
||||
<br/><input name="pt" bind:value={configuration.p.t} type="text" class="in-s"/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
Security<br/>
|
||||
<select name="gs" bind:value={configuration.g.s} class="h-10 rounded-md shadow-sm border-gray-300">
|
||||
<select name="gs" bind:value={configuration.g.s} class="in-s">
|
||||
<option value={0}>None</option>
|
||||
<option value={1}>Only configuration</option>
|
||||
<option value={2}>Everything</option>
|
||||
@@ -183,22 +210,22 @@
|
||||
{#if configuration.g.s > 0}
|
||||
<div class="my-1">
|
||||
Username<br/>
|
||||
<input name="gu" bind:value={configuration.g.u} 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="in-s"/>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
Password<br/>
|
||||
<input name="gp" bind:value={configuration.g.p} 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="in-s"/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Meter</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Meter-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="m" value="true"/>
|
||||
<div class="my-1">
|
||||
<span>Serial configuration</span>
|
||||
<div class="flex">
|
||||
<select name="mb" bind:value={configuration.m.b} class="h-10 rounded-l-md shadow-sm border-gray-300">
|
||||
<select name="mb" bind:value={configuration.m.b} class="in-f">
|
||||
<option value={2400}>2400</option>
|
||||
<option value={4800}>4800</option>
|
||||
<option value={9600}>9600</option>
|
||||
@@ -207,37 +234,37 @@
|
||||
<option value={57600}>57600</option>
|
||||
<option value={115200}>115200</option>
|
||||
</select>
|
||||
<select name="mp" bind:value={configuration.m.p} class="h-10 rounded-r-md border-l-0 shadow-sm border-gray-300">
|
||||
<select name="mp" bind:value={configuration.m.p} class="in-l">
|
||||
<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>
|
||||
<label class="mt-2 ml-3 whitespace-nowrap"><input name="mi" value="true" bind:checked={configuration.m.i} type="checkbox" class="rounded mb-1"/> inverted</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-1">
|
||||
Voltage<br/>
|
||||
<select name="md" bind:value={configuration.m.d} class="in-s">
|
||||
<option value={0}></option>
|
||||
<option value={1}>230V (IT/TT)</option>
|
||||
<option value={2}>400V (TN)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="my-1 flex">
|
||||
<div class="w-32">
|
||||
Voltage<br/>
|
||||
<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}>230V</option>
|
||||
<option value={2}>400V</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mx-1">
|
||||
Main fuse<br/>
|
||||
<label class="flex">
|
||||
<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>
|
||||
<input name="mf" bind:value={configuration.m.f} type="number" min="5" max="255" class="in-f tr"/>
|
||||
<span class="in-post">A</span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mx-1">
|
||||
Production<br/>
|
||||
<label class="flex">
|
||||
<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>
|
||||
<input name="mr" bind:value={configuration.m.r} type="number" min="0" max="255" class="in-f tr"/>
|
||||
<span class="in-post">kWp</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -247,13 +274,13 @@
|
||||
<div class="my-1">
|
||||
<label><input type="checkbox" name="me" value="true" bind:checked={configuration.m.e.e} class="rounded mb-1"/> Meter is encrypted</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"/>
|
||||
<br/><input name="mek" bind:value={configuration.m.e.k} type="text" class="in-s"/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if configuration.m.e.e}
|
||||
<div class="my-1">
|
||||
Authentication key<br/>
|
||||
<input name="mea" bind:value={configuration.m.e.a} 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="in-s"/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -262,39 +289,39 @@
|
||||
<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"/>
|
||||
<input name="mmw" bind:value={configuration.m.m.w} type="number" min="0.00" max="655.35" step="0.01" class="in-f tr w-full"/>
|
||||
</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"/>
|
||||
<input name="mmv" bind:value={configuration.m.m.v} type="number" min="0.00" max="655.35" step="0.01" class="in-m tr"/>
|
||||
</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"/>
|
||||
<input name="mma" bind:value={configuration.m.m.a} type="number" min="0.00" max="655.35" step="0.01" class="in-m tr"/>
|
||||
</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"/>
|
||||
<input name="mmc" bind:value={configuration.m.m.c} type="number" min="0.00" max="655.35" step="0.01" class="in-l tr w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">WiFi</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/WiFi-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="w" value="true"/>
|
||||
<div class="my-1">
|
||||
SSID<br/>
|
||||
<input name="ws" bind:value={configuration.w.s} 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="in-s"/>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
Password<br/>
|
||||
<input name="wp" bind:value={configuration.w.p} 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="in-s"/>
|
||||
</div>
|
||||
<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">
|
||||
<select name="wz" bind:value={configuration.w.z} class="in-s">
|
||||
<option value={255}>Default</option>
|
||||
<option value={0}>Off</option>
|
||||
<option value={1}>Minimum</option>
|
||||
@@ -304,24 +331,24 @@
|
||||
<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 w-full"/>
|
||||
<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>
|
||||
<input name="ww" bind:value={configuration.w.w} type="number" min="0" max="20.5" step="0.5" class="in-f tr"/>
|
||||
<span class="in-post">dBm</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Network</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Network-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<div class="my-1">
|
||||
IP<br/>
|
||||
<div class="flex">
|
||||
<select name="nm" bind:value={configuration.n.m} class="h-10 rounded-l-md shadow-sm border border-gray-300">
|
||||
<select name="nm" bind:value={configuration.n.m} class="in-f">
|
||||
<option value="dhcp">DHCP</option>
|
||||
<option value="static">Static</option>
|
||||
</select>
|
||||
<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'}>
|
||||
<input name="ni" bind:value={configuration.n.i} type="text" class="in-m" disabled={configuration.n.m == 'dhcp'}/>
|
||||
<select name="ns" bind:value={configuration.n.s} class="in-l" 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>
|
||||
@@ -331,13 +358,13 @@
|
||||
{#if configuration.n.m == 'static'}
|
||||
<div class="my-1">
|
||||
Gateway<br/>
|
||||
<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"/>
|
||||
<input name="ng" bind:value={configuration.n.g} type="text" class="in-s"/>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
DNS<br/>
|
||||
<div class="flex">
|
||||
<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"/>
|
||||
<input name="nd1" bind:value={configuration.n.d1} type="text" class="in-f w-full"/>
|
||||
<input name="nd2" bind:value={configuration.n.d2} type="text" class="in-l w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -348,62 +375,70 @@
|
||||
<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="ntph" bind:value={configuration.n.n1} type="text" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="ntph" bind:value={configuration.n.n1} type="text" class="in-s"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">MQTT</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/MQTT-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<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>
|
||||
{#if sysinfo.chip != 'esp8266'}
|
||||
<label class="float-right mr-3"><input type="checkbox" name="qs" value="true" bind:checked={configuration.q.s.e} class="rounded mb-1" on:change={updateMqttPort}/> SSL</label>
|
||||
{/if}
|
||||
<br/>
|
||||
<div class="flex">
|
||||
<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"/>
|
||||
<input name="qh" bind:value={configuration.q.h} type="text" class="in-f w-full"/>
|
||||
<input name="qp" bind:value={configuration.q.p} type="number" min="1024" max="65535" class="in-l tr"/>
|
||||
</div>
|
||||
</div>
|
||||
{#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}
|
||||
<Link to="/mqtt-ca">
|
||||
{#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}
|
||||
</Link>
|
||||
|
||||
{#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}
|
||||
<Link to="/mqtt-cert">
|
||||
{#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}
|
||||
</Link>
|
||||
|
||||
{#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}
|
||||
<Link to="/mqtt-key">
|
||||
{#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}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-1">
|
||||
Username<br/>
|
||||
<input name="qu" bind:value={configuration.q.u} 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="in-s"/>
|
||||
</div>
|
||||
<div class="my-1">
|
||||
Password<br/>
|
||||
<input name="qa" bind:value={configuration.q.a} 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="in-s"/>
|
||||
</div>
|
||||
<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"/>
|
||||
<input name="qc" bind:value={configuration.q.c} type="text" class="in-f 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">
|
||||
<select name="qm" bind:value={configuration.q.m} class="in-l">
|
||||
<option value={0}>JSON</option>
|
||||
<option value={1}>Raw (minimal)</option>
|
||||
<option value={2}>Raw (full)</option>
|
||||
@@ -415,70 +450,70 @@
|
||||
</div>
|
||||
<div class="my-1">
|
||||
Publish topic<br/>
|
||||
<input name="qb" bind:value={configuration.q.b} 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="in-s"/>
|
||||
</div>
|
||||
</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">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Tariff thresholds</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Threshold-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<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>
|
||||
<span class="in-pre">1</span>
|
||||
<input name="t0" bind:value={configuration.t.t[0]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">2</span>
|
||||
<input name="t1" bind:value={configuration.t.t[1]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">3</span>
|
||||
<input name="t2" bind:value={configuration.t.t[2]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">4</span>
|
||||
<input name="t3" bind:value={configuration.t.t[3]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">5</span>
|
||||
<input name="t4" bind:value={configuration.t.t[4]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">6</span>
|
||||
<input name="t5" bind:value={configuration.t.t[5]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">7</span>
|
||||
<input name="t6" bind:value={configuration.t.t[6]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">8</span>
|
||||
<input name="t7" bind:value={configuration.t.t[7]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">9</span>
|
||||
<input name="t8" bind:value={configuration.t.t[8]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">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>
|
||||
<span class="in-pre">Average of</span>
|
||||
<input name="th" bind:value={configuration.t.h} type="number" min="0" max="255" class="in-txt tr w-full"/>
|
||||
<span class="in-post">hours</span>
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
{#if sysinfo.board > 20 || sysinfo.chip == 'esp8266'}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Hardware</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/GPIO-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
{#if sysinfo.board > 20}
|
||||
@@ -486,48 +521,48 @@
|
||||
<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">
|
||||
<select name="ih" bind:value={configuration.i.h} class="in-f">
|
||||
<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"/>
|
||||
<input name="ia" bind:value={configuration.i.a} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-m tr"/>
|
||||
</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"/>
|
||||
<input name="ilp" bind:value={configuration.i.l.p} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-l tr"/>
|
||||
</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"/>
|
||||
<input name="irr" bind:value={configuration.i.r.r} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-f tr"/>
|
||||
<input name="irg" bind:value={configuration.i.r.g} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-m tr"/>
|
||||
<input name="irb" bind:value={configuration.i.r.b} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-l tr"/>
|
||||
</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"/>
|
||||
<input name="itd" bind:value={configuration.i.t.d} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-f tr"/>
|
||||
</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"/>
|
||||
<input name="ita" bind:value={configuration.i.t.a} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-l tr"/>
|
||||
</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"/>
|
||||
<input name="ivp" bind:value={configuration.i.v.p} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-s tr"/>
|
||||
</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"/>
|
||||
<input name="ivdv" bind:value={configuration.i.v.d.v} type="number" min="0" max="65535" class="in-f tr w-full" placeholder="VCC"/>
|
||||
<input name="ivdg" bind:value={configuration.i.v.d.g} type="number" min="0" max="65535" class="in-l tr w-full" placeholder="GND"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -538,38 +573,39 @@
|
||||
<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"/>
|
||||
<input name="ivo" bind:value={configuration.i.v.o} type="number" min="0.0" max="3.5" step="0.01" class="in-f tr"/>
|
||||
</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-l-0 rounded-r-md shadow-sm border-gray-300 w-24 text-right"/>
|
||||
Multiplier<br/>
|
||||
<input name="ivm" bind:value={configuration.i.v.m} type="number" min="0.1" max="10" step="0.01" class="in-l tr"/>
|
||||
</div>
|
||||
{#if sysinfo.board == 2 || sysinfo.board == 100}
|
||||
<div class="ml-2">
|
||||
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-md shadow-sm border-gray-300 w-24 text-right"/>
|
||||
<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="in-s tr"/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Debugging</strong>
|
||||
<a href="https://amsleser.no/blog/post/24-telnet-debug" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<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="bd-red">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>
|
||||
<div class="bd-red">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">
|
||||
<select name="dl" bind:value={configuration.d.l} class="in-s">
|
||||
<option value={1}>Verbose</option>
|
||||
<option value={2}>Debug</option>
|
||||
<option value={3}>Info</option>
|
||||
@@ -579,8 +615,17 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<div class="grid grid-cols-3">
|
||||
<div>
|
||||
<button type="button" on:click={factoryReset} class="py-2 px-4 rounded bg-red-500 text-white ml-2">Factory reset</button>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="button" on:click={askReboot} class="py-2 px-4 rounded bg-yellow-500 text-white">Reboot</button>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button type="submit" class="btn-pri">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<Mask active={loadingOrSaving} message="Loading configuration"/>
|
||||
<Mask active={isFactoryReset} message="Device have been factory reset and switched to AP mode"/>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<script>
|
||||
let count = 0
|
||||
const increment = () => {
|
||||
count += 1
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={increment}>
|
||||
count is {count}
|
||||
</button>
|
||||
10
lib/SvelteUi/app/src/lib/CountrySelectOptions.svelte
Normal file
10
lib/SvelteUi/app/src/lib/CountrySelectOptions.svelte
Normal file
@@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let europe = ["Amsterdam","Athens","Belfast","Berlin","Bratislava","Brussels","Bucharest","Budapest","Copenhagen","Dublin",
|
||||
"Helsinki","Lisbon","Ljubljana","London","Luxembourg","Madrid","Malta","Nicosia","Oslo","Paris","Prague","Riga","Rome",
|
||||
"Sofia","Stockholm","Tallinn","Vienna","Vilnius","Warsaw","Zagreb","Zurich"];
|
||||
</script>
|
||||
|
||||
<option>GMT</option>
|
||||
{#each europe as c}
|
||||
<option>Europe/{c}</option>
|
||||
{/each}
|
||||
@@ -32,7 +32,7 @@
|
||||
</script>
|
||||
|
||||
<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">
|
||||
<div class="cnt">
|
||||
<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"/>
|
||||
@@ -42,7 +42,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if data.om || data.e > 0}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
<div class="cnt">
|
||||
<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"/>
|
||||
@@ -52,36 +52,40 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
{#if data.u1 > 100 || data.u2 > 100 || data.u3 > 100}
|
||||
<div class="cnt">
|
||||
<VoltPlot u1={data.u1} u2={data.u2} u3={data.u3} ds={data.ds}/>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
{/if}
|
||||
{#if data.i1 > 0.01 || data.i2 > 0.01 || data.i3 > 0.01}
|
||||
<div class="cnt">
|
||||
<AmpPlot u1={data.u1} u2={data.u2} u3={data.u3} i1={data.i1} i2={data.i2} i3={data.i3} max={data.mf ? data.mf : 32}/>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
{/if}
|
||||
<div class="cnt">
|
||||
<ReactiveData importInstant={data.ri} exportInstant={data.re} importTotal={data.ric} exportTotal={data.rec}/>
|
||||
</div>
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
<div class="cnt">
|
||||
<AccountingData data={data.ea} currency={prices.currency}/>
|
||||
</div>
|
||||
{#if prices.currency == 'NOK'}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg h-64">
|
||||
{#if data && data.ea}
|
||||
<div class="cnt h-64">
|
||||
<TariffPeakChart data={data.ea} />
|
||||
</div>
|
||||
{/if}
|
||||
{#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 h-64">
|
||||
<div class="cnt 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 h-64">
|
||||
<div class="cnt 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 h-64">
|
||||
<div class="cnt 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 h-64">
|
||||
<div class="cnt xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<TemperaturePlot json={temperatures} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -127,6 +127,19 @@ export const temperaturesStore = writable(temperatures, (set) => {
|
||||
return function stop() {}
|
||||
});
|
||||
|
||||
let tariff = {};
|
||||
export async function getTariff() {
|
||||
const response = await fetchWithTimeout("/tariff.json");
|
||||
tariff = (await response.json())
|
||||
tariffStore.set(tariff);
|
||||
let date = new Date();
|
||||
setTimeout(getTariff, (61-date.getMinutes())*60000)
|
||||
}
|
||||
|
||||
export const tariffStore = writable(tariff, (set) => {
|
||||
return function stop() {}
|
||||
});
|
||||
|
||||
let releases = [];
|
||||
export const gitHubReleaseStore = writable(releases);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
let cur = new Date();
|
||||
let offset = -cur.getTimezoneOffset()/60;
|
||||
for(i = cur.getUTCHours(); i<24; i++) {
|
||||
let imp = json["i"+zeropad(i)];
|
||||
let exp = json["e"+zeropad(i)];
|
||||
@@ -21,7 +22,7 @@
|
||||
if(exp === undefined) exp = 0;
|
||||
|
||||
xTicks.push({
|
||||
label: zeropad(i)
|
||||
label: zeropad((i+offset)%24)
|
||||
});
|
||||
points.push({
|
||||
label: imp.toFixed(1),
|
||||
@@ -40,7 +41,7 @@
|
||||
if(exp === undefined) exp = 0;
|
||||
|
||||
xTicks.push({
|
||||
label: zeropad(i)
|
||||
label: zeropad((i+offset)%24)
|
||||
});
|
||||
points.push({
|
||||
label: imp.toFixed(1),
|
||||
@@ -58,13 +59,15 @@
|
||||
max = boundary;
|
||||
min = min == 0 ? 0 : boundary*-1;
|
||||
|
||||
let yTickDistDown = min/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
let val = (yTickDistDown*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: (val/10).toFixed(1)
|
||||
});
|
||||
if(min < 0) {
|
||||
let yTickDistDown = min/4;
|
||||
for(i = 1; i < 5; i++) {
|
||||
let val = (yTickDistDown*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: (val/10).toFixed(1)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let yTickDistUp = max/4;
|
||||
|
||||
18
lib/SvelteUi/app/src/lib/FileUploadComponent.svelte
Normal file
18
lib/SvelteUi/app/src/lib/FileUploadComponent.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script>
|
||||
export let action;
|
||||
export let title;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<strong>Upload {title}</strong>
|
||||
<p class="mb-4">Select a suitable file and click upload</p>
|
||||
<form action="{action}" enctype="multipart/form-data" method="post">
|
||||
<input name="file" type="file">
|
||||
<div class="w-full text-right mt-4">
|
||||
<button type="submit" class="btn-pri">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,7 +10,6 @@
|
||||
import GearIcon from './GearIcon.svelte';
|
||||
import InfoIcon from "./InfoIcon.svelte";
|
||||
import HelpIcon from "./HelpIcon.svelte";
|
||||
import ReloadIcon from "./ReloadIcon.svelte";
|
||||
import DownloadIcon from "./DownloadIcon.svelte";
|
||||
|
||||
export let data = {}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export let monthnames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
|
||||
export function voltcol(pct) {
|
||||
if(pct > 85) return '#d90000';
|
||||
else if(pct > 75) return'#e32100';
|
||||
|
||||
@@ -61,13 +61,15 @@
|
||||
max = boundary;
|
||||
min = min == 0 ? 0 : boundary*-1;
|
||||
|
||||
let yTickDistDown = min/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
let val = (yTickDistDown*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val.toFixed(0)
|
||||
});
|
||||
if(min < 0) {
|
||||
let yTickDistDown = min/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
let val = (yTickDistDown*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val.toFixed(0)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let yTickDistUp = max/4;
|
||||
|
||||
@@ -8,35 +8,12 @@
|
||||
export let label;
|
||||
</script>
|
||||
|
||||
<div class="overlay-plot">
|
||||
<div class="pl-root">
|
||||
<PowerGaugeSvg pct={val/max * 100} color={ampcol(val/max * 100)}/>
|
||||
<span class="plot-overlay">
|
||||
<span class="plot-value">{val}</span>
|
||||
<span class="plot-unit">{unit}</span>
|
||||
<span class="pl-ov">
|
||||
<span class="pl-val">{val}</span>
|
||||
<span class="pl-unt">{unit}</span>
|
||||
<br/>
|
||||
<span class="plot-label">{label}</span>
|
||||
<span class="pl-lab">{label}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.overlay-plot {
|
||||
position: relative;
|
||||
}
|
||||
.plot-overlay {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
.plot-value {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
.plot-unit {
|
||||
font-size: 1.0rem;
|
||||
color: grey;
|
||||
}
|
||||
.plot-label {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -56,13 +56,15 @@
|
||||
max = Math.ceil(max);
|
||||
min = Math.floor(min);
|
||||
|
||||
let yTickDistDown = min/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
let val = (yTickDistDown*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: (val/100).toFixed(2)
|
||||
});
|
||||
if(min < 0) {
|
||||
let yTickDistDown = min/4;
|
||||
for(i = 1; i < 5; i++) {
|
||||
let val = (yTickDistDown*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: (val/100).toFixed(2)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let yTickDistUp = max/4;
|
||||
@@ -74,6 +76,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
console.log(yTicks);
|
||||
|
||||
config = {
|
||||
title: "Future energy price (" + json.currency + ")",
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<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>
|
||||
|
||||
@@ -65,30 +65,30 @@
|
||||
</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">
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<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"/>
|
||||
<input name="ss" type="text" class="in-s"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
PSK<br/>
|
||||
<input name="sp" type="password" class="h-10 rounded-md shadow-sm border-gray-300 w-full"/>
|
||||
<input name="sp" type="password" class="in-s"/>
|
||||
</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"/>
|
||||
<input name="sh" bind:value={sysinfo.hostname} type="text" class="in-s" 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}>
|
||||
<input name="si" type="text" class="in-f w-full" required={staticIp}/>
|
||||
<select name="su" class="in-l" 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>
|
||||
@@ -100,11 +100,11 @@
|
||||
<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"/>
|
||||
<input name="sg" type="text" class="in-f 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"/>
|
||||
<input name="sd" type="text" class="in-l w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -113,7 +113,7 @@
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Data-collection-on-one-click-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>
|
||||
<button type="submit" class="btn-pri">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
import { getSysinfo, gitHubReleaseStore, sysinfoStore } from './DataStores.js';
|
||||
import { upgrade, getNextVersion } from './UpgradeHelper';
|
||||
import DownloadIcon from './DownloadIcon.svelte';
|
||||
import UploadIcon from './UploadIcon.svelte';
|
||||
|
||||
export let sysinfo = {}
|
||||
export let data = {}
|
||||
|
||||
export let sysinfo;
|
||||
|
||||
let nextVersion = {};
|
||||
gitHubReleaseStore.subscribe(releases => {
|
||||
nextVersion = getNextVersion(sysinfo.version, releases);
|
||||
@@ -45,14 +43,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let fileinput;
|
||||
|
||||
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">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Device information</strong>
|
||||
<div class="my-2">
|
||||
Chip: {sysinfo.chip}
|
||||
@@ -68,7 +64,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if sysinfo.meter}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Meter</strong>
|
||||
<div class="my-2">
|
||||
Manufacturer: {metertype(sysinfo.meter.mfg)}
|
||||
@@ -82,7 +78,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if sysinfo.net}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Network</strong>
|
||||
<div class="my-2">
|
||||
IP: {sysinfo.net.ip}
|
||||
@@ -98,7 +94,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg-white m-2 p-2 rounded-md shadow-lg pb-4 text-gray-700">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Firmware</strong>
|
||||
<div class="my-2">
|
||||
Installed version: {sysinfo.version}
|
||||
@@ -115,12 +111,12 @@
|
||||
</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 disabled one-click firmware upgrade, link to self-upgrade is disabled</div>
|
||||
<div class="bd-ylo">You have disabled one-click firmware upgrade, link to self-upgrade is disabled</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/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">
|
||||
<div class="bd-red">
|
||||
{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.
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import { monthnames, zeropad } from './Helpers.js';
|
||||
import BarChart from './BarChart.svelte';
|
||||
import { tariffStore, getTariff } from './DataStores';
|
||||
|
||||
let monthnames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
|
||||
export let data;
|
||||
|
||||
let config = {};
|
||||
let max = 0;
|
||||
let min = 0;
|
||||
|
||||
let thresholds = [5,10,15,20,25,50,75,100,150];
|
||||
let tariffData;
|
||||
tariffStore.subscribe(update => {
|
||||
tariffData = update;
|
||||
});
|
||||
getTariff();
|
||||
|
||||
$: {
|
||||
let i = 0;
|
||||
@@ -23,10 +24,25 @@
|
||||
label: 0
|
||||
});
|
||||
|
||||
if(data && data.x) {
|
||||
for(i = 0; i < thresholds.length; i++) {
|
||||
let val = thresholds[i];
|
||||
if(val >= data.x) break;
|
||||
if(tariffData && tariffData.p) {
|
||||
for(i = 0; i < tariffData.p.length; i++) {
|
||||
let peak = tariffData.p[i];
|
||||
points.push({
|
||||
label: peak.v.toFixed(2),
|
||||
value: peak.v,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
xTicks.push({
|
||||
label: peak.d > 0 ? zeropad(peak.d) + "." + monthnames[new Date().getMonth()] : "-"
|
||||
})
|
||||
max = Math.max(max, peak.v);
|
||||
}
|
||||
}
|
||||
|
||||
if(tariffData && tariffData.t) {
|
||||
for(i = 0; i < tariffData.t.length; i++) {
|
||||
let val = tariffData.t[i];
|
||||
if(val >= max) break;
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val
|
||||
@@ -34,34 +50,20 @@
|
||||
}
|
||||
|
||||
yTicks.push({
|
||||
label: data.x.toFixed(1),
|
||||
label: tariffData.m.toFixed(1),
|
||||
align: 'right',
|
||||
color: 'green',
|
||||
value: data.x,
|
||||
value: tariffData.m,
|
||||
});
|
||||
}
|
||||
|
||||
if(data && data.t) {
|
||||
if(tariffData && tariffData.c) {
|
||||
yTicks.push({
|
||||
label: data.t.toFixed(1),
|
||||
label: tariffData.c.toFixed(1),
|
||||
color: 'orange',
|
||||
value: data.t,
|
||||
value: tariffData.c,
|
||||
});
|
||||
}
|
||||
|
||||
if(data && data.p) {
|
||||
for(i = 0; i < data.p.length; i++) {
|
||||
let val = data.p[i];
|
||||
points.push({
|
||||
label: val.toFixed(2),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
xTicks.push({
|
||||
label: monthnames[new Date().getMonth()]
|
||||
})
|
||||
max = Math.max(max, val);
|
||||
}
|
||||
max = Math.max(max, tariffData.c);
|
||||
}
|
||||
|
||||
max = Math.ceil(max);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import BarChart from './BarChart.svelte';
|
||||
|
||||
export let json;
|
||||
@@ -9,12 +8,8 @@
|
||||
let min = 0;
|
||||
|
||||
$: {
|
||||
let hour = new Date().getUTCHours();
|
||||
let i = 0;
|
||||
let val = 0;
|
||||
let imp = 0;
|
||||
let exp = 0;
|
||||
let h = 0;
|
||||
let yTicks = [];
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
|
||||
@@ -2,36 +2,41 @@
|
||||
export let chip;
|
||||
</script>
|
||||
|
||||
{#if chip == 'esp8266'}
|
||||
<option value={3}>UART0</option>
|
||||
{#if chip == 'esp8266'}
|
||||
<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>
|
||||
{/if}
|
||||
{#if chip == 'esp32s2'}
|
||||
<option value={18}>UART1</option>
|
||||
{/if}
|
||||
<option value={4}>GPIO4</option>
|
||||
<option value={5}>GPIO5</option>
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={6}>GPIO6</option>
|
||||
<option value={7}>GPIO7</option>
|
||||
<option value={8}>GPIO8</option>
|
||||
{/if}
|
||||
{#if chip == 'esp8266'}
|
||||
<option value={9}>GPIO9</option>
|
||||
{/if}
|
||||
<option value={10}>GPIO10</option>
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={11}>GPIO11</option>
|
||||
{/if}
|
||||
<option value={12}>GPIO12</option>
|
||||
<option value={13}>GPIO13</option>
|
||||
<option value={14}>GPIO14</option>
|
||||
<option value={15}>GPIO15</option>
|
||||
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={17}>GPIO17</option>
|
||||
{#if chip != 'esp32s2'}
|
||||
<option value={18}>GPIO18</option>
|
||||
{/if}
|
||||
<option value={19}>GPIO19</option>
|
||||
<option value={21}>GPIO21</option>
|
||||
<option value={22}>GPIO22</option>
|
||||
@@ -45,33 +50,6 @@
|
||||
<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>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
export async function upgrade(version) {
|
||||
const data = new URLSearchParams()
|
||||
data.append('version', version.tag_name);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<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 8.25H7.5a2.25 2.25 0 00-2.25 2.25v9a2.25 2.25 0 002.25 2.25h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25H15m0-3l-3-3m0 0l-3 3m3-3V15" />
|
||||
</svg>
|
||||
|
||||
@@ -31,27 +31,27 @@
|
||||
}
|
||||
</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">
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="v" value="true"/>
|
||||
<strong class="text-sm">Initial 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">
|
||||
<select name="vb" bind:value={sysinfo.board} class="in-s">
|
||||
<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">
|
||||
<select name="vh" class="in-s">
|
||||
<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>
|
||||
<button type="submit" class="btn-pri">Save</button>
|
||||
</div>
|
||||
<span class="clear-both"> </span>
|
||||
</form>
|
||||
|
||||
@@ -17,17 +17,18 @@ export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.229",
|
||||
"/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.229",
|
||||
"/configuration.json": "http://192.168.233.229",
|
||||
"/save": "http://192.168.233.229",
|
||||
"/reboot": "http://192.168.233.229",
|
||||
"/firmware": "http://192.168.233.229",
|
||||
"/upgrade": "http://192.168.233.229"
|
||||
"/data.json": "http://192.168.233.244",
|
||||
"/energyprice.json": "http://192.168.233.244",
|
||||
"/dayplot.json": "http://192.168.233.244",
|
||||
"/monthplot.json": "http://192.168.233.244",
|
||||
"/temperature.json": "http://192.168.233.244",
|
||||
"/sysinfo.json": "http://192.168.233.244",
|
||||
"/configuration.json": "http://192.168.233.244",
|
||||
"/tariff.json": "http://192.168.233.244",
|
||||
"/save": "http://192.168.233.244",
|
||||
"/reboot": "http://192.168.233.244",
|
||||
"/firmware": "http://192.168.233.244",
|
||||
"/upgrade": "http://192.168.233.244"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -84,6 +84,7 @@ private:
|
||||
void energyPriceJson();
|
||||
void temperatureJson();
|
||||
void wifiScanJson();
|
||||
void tariffJson();
|
||||
|
||||
void configurationJson();
|
||||
void handleSave();
|
||||
@@ -93,6 +94,9 @@ private:
|
||||
void firmwareUpload();
|
||||
void isAliveCheck();
|
||||
|
||||
void mqttCaUpload();
|
||||
void mqttCertUpload();
|
||||
void mqttKeyUpload();
|
||||
HTTPUpload& uploadFile(const char* path);
|
||||
|
||||
void factoryResetPost();
|
||||
|
||||
@@ -53,5 +53,6 @@
|
||||
"p" : %.2f
|
||||
}
|
||||
},
|
||||
"pr" : "%s",
|
||||
"c" : %lu
|
||||
}
|
||||
5
lib/SvelteUi/json/response.json
Normal file
5
lib/SvelteUi/json/response.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"success": %s,
|
||||
"message": "%s",
|
||||
"reboot": %s
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "html/monthplot_json.h"
|
||||
#include "html/energyprice_json.h"
|
||||
#include "html/tempsensor_json.h"
|
||||
#include "html/response_json.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
@@ -40,6 +41,10 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
|
||||
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("/mqtt-ca"), HTTP_GET, std::bind(&AmsWebServer::indexHtml, this));
|
||||
server.on(F("/mqtt-cert"), HTTP_GET, std::bind(&AmsWebServer::indexHtml, this));
|
||||
server.on(F("/mqtt-key"), 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));
|
||||
@@ -50,6 +55,7 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
|
||||
server.on(F("/monthplot.json"), HTTP_GET, std::bind(&AmsWebServer::monthplotJson, this));
|
||||
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("/tariff.json"), HTTP_GET, std::bind(&AmsWebServer::tariffJson, this));
|
||||
|
||||
server.on(F("/wifiscan.json"), HTTP_GET, std::bind(&AmsWebServer::wifiScanJson, this));
|
||||
|
||||
@@ -64,6 +70,10 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
|
||||
|
||||
server.on(F("/robots.txt"), HTTP_GET, std::bind(&AmsWebServer::robotstxt, this));
|
||||
|
||||
server.on(F("/mqtt-ca"), HTTP_POST, std::bind(&AmsWebServer::firmwarePost, this), std::bind(&AmsWebServer::mqttCaUpload, this));
|
||||
server.on(F("/mqtt-cert"), HTTP_POST, std::bind(&AmsWebServer::firmwarePost, this), std::bind(&AmsWebServer::mqttCertUpload, this));
|
||||
server.on(F("/mqtt-key"), HTTP_POST, std::bind(&AmsWebServer::firmwarePost, this), std::bind(&AmsWebServer::mqttKeyUpload, this));
|
||||
|
||||
server.onNotFound(std::bind(&AmsWebServer::notFound, this));
|
||||
|
||||
server.begin(); // Web server start
|
||||
@@ -157,55 +167,55 @@ void AmsWebServer::sysinfoJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /sysinfo.json over http...\n");
|
||||
|
||||
DynamicJsonDocument doc(512);
|
||||
doc["version"] = VERSION;
|
||||
doc[PSTR("version")] = VERSION;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
doc["chip"] = "esp32s2";
|
||||
doc[PSTR("chip")] = "esp32s2";
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
doc["chip"] = "esp32c3";
|
||||
doc[PSTR("chip")] = "esp32c3";
|
||||
#elif defined(ESP32)
|
||||
doc["chip"] = "esp32";
|
||||
doc[PSTR("chip")] = "esp32";
|
||||
#elif defined(ESP8266)
|
||||
doc["chip"] = "esp8266";
|
||||
doc[PSTR("chip")] = "esp8266";
|
||||
#endif
|
||||
|
||||
uint16_t chipId;
|
||||
uint32_t chipId;
|
||||
#if defined(ESP32)
|
||||
chipId = ESP.getEfuseMac();
|
||||
chipId = ( ESP.getEfuseMac() >> 32 ) % 0xFFFFFFFF;
|
||||
#else
|
||||
chipId = ESP.getChipId();
|
||||
#endif
|
||||
String chipIdStr = String(chipId, HEX);;
|
||||
doc["chipId"] = chipIdStr;
|
||||
doc["mac"] = WiFi.macAddress();
|
||||
doc[PSTR("chipId")] = chipIdStr;
|
||||
doc[PSTR("mac")] = WiFi.macAddress();
|
||||
|
||||
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[PSTR("board")] = sys.boardType;
|
||||
doc[PSTR("vndcfg")] = sys.vendorConfigured;
|
||||
doc[PSTR("usrcfg")] = sys.userConfigured;
|
||||
doc[PSTR("fwconsent")] = sys.dataCollectionConsent;
|
||||
doc[PSTR("country")] = sys.country;
|
||||
|
||||
if(sys.userConfigured) {
|
||||
WiFiConfig wifiConfig;
|
||||
config->getWiFiConfig(wifiConfig);
|
||||
doc["hostname"] = wifiConfig.hostname;
|
||||
doc[PSTR("hostname")] = wifiConfig.hostname;
|
||||
} else {
|
||||
doc["hostname"] = "ams-"+chipIdStr;
|
||||
doc[PSTR("hostname")] = "ams-"+chipIdStr;
|
||||
}
|
||||
|
||||
doc["booting"] = performRestart;
|
||||
doc["upgrading"] = rebootForUpgrade;
|
||||
doc[PSTR("booting")] = performRestart;
|
||||
doc[PSTR("upgrading")] = rebootForUpgrade;
|
||||
|
||||
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[PSTR("net")][PSTR("ip")] = WiFi.localIP().toString();
|
||||
doc[PSTR("net")][PSTR("mask")] = WiFi.subnetMask().toString();
|
||||
doc[PSTR("net")][PSTR("gw")] = WiFi.gatewayIP().toString();
|
||||
doc[PSTR("net")][PSTR("dns1")] = WiFi.dnsIP(0).toString();
|
||||
doc[PSTR("net")][PSTR("dns2")] = WiFi.dnsIP(1).toString();
|
||||
|
||||
doc["meter"]["mfg"] = meterState->getMeterType();
|
||||
doc["meter"]["model"] = meterState->getMeterModel();
|
||||
doc["meter"]["id"] = meterState->getMeterId();
|
||||
doc[PSTR("meter")][PSTR("mfg")] = meterState->getMeterType();
|
||||
doc[PSTR("meter")][PSTR("model")] = meterState->getMeterModel();
|
||||
doc[PSTR("meter")][PSTR("id")] = meterState->getMeterId();
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
@@ -300,7 +310,7 @@ void AmsWebServer::dataJson() {
|
||||
String peaks = "";
|
||||
for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
|
||||
if(!peaks.isEmpty()) peaks += ",";
|
||||
peaks += String(ea->getPeak(i));
|
||||
peaks += String(ea->getPeak(i).value);
|
||||
}
|
||||
|
||||
snprintf_P(buf, BufferSize, DATA_JSON,
|
||||
@@ -350,6 +360,7 @@ void AmsWebServer::dataJson() {
|
||||
ea->getUseThisMonth(),
|
||||
ea->getCostThisMonth(),
|
||||
ea->getProducedThisMonth(),
|
||||
eapi == NULL ? "" : eapi->getArea(),
|
||||
(uint32_t) time(nullptr)
|
||||
);
|
||||
|
||||
@@ -659,7 +670,7 @@ void AmsWebServer::configurationJson() {
|
||||
return;
|
||||
|
||||
DynamicJsonDocument doc(2048);
|
||||
doc["version"] = VERSION;
|
||||
doc[PSTR("version")] = VERSION;
|
||||
|
||||
NtpConfig ntpConfig;
|
||||
config->getNtpConfig(ntpConfig);
|
||||
@@ -668,15 +679,11 @@ void AmsWebServer::configurationJson() {
|
||||
WebConfig webConfig;
|
||||
config->getWebConfig(webConfig);
|
||||
|
||||
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 ? "***" : "";
|
||||
doc[PSTR("g")][PSTR("t")] = ntpConfig.timezone;
|
||||
doc[PSTR("g")][PSTR("h")] = wifiConfig.hostname;
|
||||
doc[PSTR("g")][PSTR("s")] = webConfig.security;
|
||||
doc[PSTR("g")][PSTR("u")] = webConfig.username;
|
||||
doc[PSTR("g")][PSTR("p")] = strlen(webConfig.password) > 0 ? "***" : "";
|
||||
|
||||
bool encen = false;
|
||||
for(uint8_t i = 0; i < 16; i++) {
|
||||
@@ -686,161 +693,161 @@ void AmsWebServer::configurationJson() {
|
||||
}
|
||||
|
||||
config->getMeterConfig(*meterConfig);
|
||||
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;
|
||||
doc[PSTR("m")][PSTR("b")] = meterConfig->baud;
|
||||
doc[PSTR("m")][PSTR("p")] = meterConfig->parity;
|
||||
doc[PSTR("m")][PSTR("i")] = meterConfig->invert;
|
||||
doc[PSTR("m")][PSTR("d")] = meterConfig->distributionSystem;
|
||||
doc[PSTR("m")][PSTR("f")] = meterConfig->mainFuse;
|
||||
doc[PSTR("m")][PSTR("r")] = meterConfig->productionCapacity;
|
||||
doc[PSTR("m")][PSTR("e")][PSTR("e")] = encen;
|
||||
doc[PSTR("m")][PSTR("e")][PSTR("k")] = toHex(meterConfig->encryptionKey, 16);
|
||||
doc[PSTR("m")][PSTR("e")][PSTR("a")] = toHex(meterConfig->authenticationKey, 16);
|
||||
doc[PSTR("m")][PSTR("m")][PSTR("e")] = meterConfig->wattageMultiplier > 1 || meterConfig->voltageMultiplier > 1 || meterConfig->amperageMultiplier > 1 || meterConfig->accumulatedMultiplier > 1;
|
||||
doc[PSTR("m")][PSTR("m")][PSTR("w")] = meterConfig->wattageMultiplier / 1000.0;
|
||||
doc[PSTR("m")][PSTR("m")][PSTR("v")] = meterConfig->voltageMultiplier / 1000.0;
|
||||
doc[PSTR("m")][PSTR("m")][PSTR("a")] = meterConfig->amperageMultiplier / 1000.0;
|
||||
doc[PSTR("m")][PSTR("m")][PSTR("c")] = meterConfig->accumulatedMultiplier / 1000.0;
|
||||
|
||||
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[PSTR("t")][PSTR("t")][0] = eac.thresholds[0];
|
||||
doc[PSTR("t")][PSTR("t")][1] = eac.thresholds[1];
|
||||
doc[PSTR("t")][PSTR("t")][2] = eac.thresholds[2];
|
||||
doc[PSTR("t")][PSTR("t")][3] = eac.thresholds[3];
|
||||
doc[PSTR("t")][PSTR("t")][4] = eac.thresholds[4];
|
||||
doc[PSTR("t")][PSTR("t")][5] = eac.thresholds[5];
|
||||
doc[PSTR("t")][PSTR("t")][6] = eac.thresholds[6];
|
||||
doc[PSTR("t")][PSTR("t")][7] = eac.thresholds[7];
|
||||
doc[PSTR("t")][PSTR("t")][8] = eac.thresholds[8];
|
||||
doc[PSTR("t")][PSTR("t")][9] = eac.thresholds[9];
|
||||
doc[PSTR("t")][PSTR("h")] = eac.hours;
|
||||
|
||||
doc["w"]["s"] = wifiConfig.ssid;
|
||||
doc["w"]["p"] = strlen(wifiConfig.psk) > 0 ? "***" : "";
|
||||
doc["w"]["w"] = wifiConfig.power / 10.0;
|
||||
doc["w"]["z"] = wifiConfig.sleep;
|
||||
doc[PSTR("w")][PSTR("s")] = wifiConfig.ssid;
|
||||
doc[PSTR("w")][PSTR("p")] = strlen(wifiConfig.psk) > 0 ? "***" : "";
|
||||
doc[PSTR("w")][PSTR("w")] = wifiConfig.power / 10.0;
|
||||
doc[PSTR("w")][PSTR("z")] = wifiConfig.sleep;
|
||||
|
||||
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;
|
||||
doc[PSTR("n")][PSTR("m")] = strlen(wifiConfig.ip) > 0 ? "static" : "dhcp";
|
||||
doc[PSTR("n")][PSTR("i")] = wifiConfig.ip;
|
||||
doc[PSTR("n")][PSTR("s")] = wifiConfig.subnet;
|
||||
doc[PSTR("n")][PSTR("g")] = wifiConfig.gateway;
|
||||
doc[PSTR("n")][PSTR("d1")] = wifiConfig.dns1;
|
||||
doc[PSTR("n")][PSTR("d2")] = wifiConfig.dns2;
|
||||
doc[PSTR("n")][PSTR("d")] = wifiConfig.mdns;
|
||||
doc[PSTR("n")][PSTR("n1")] = ntpConfig.server;
|
||||
doc[PSTR("n")][PSTR("h")] = ntpConfig.dhcp;
|
||||
|
||||
MqttConfig mqttConfig;
|
||||
config->getMqttConfig(mqttConfig);
|
||||
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;
|
||||
doc[PSTR("q")][PSTR("h")] = mqttConfig.host;
|
||||
doc[PSTR("q")][PSTR("p")] = mqttConfig.port;
|
||||
doc[PSTR("q")][PSTR("u")] = mqttConfig.username;
|
||||
doc[PSTR("q")][PSTR("a")] = strlen(mqttConfig.password) > 0 ? "***" : "";
|
||||
doc[PSTR("q")][PSTR("c")] = mqttConfig.clientId;
|
||||
doc[PSTR("q")][PSTR("b")] = mqttConfig.publishTopic;
|
||||
doc[PSTR("q")][PSTR("m")] = mqttConfig.payloadFormat;
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("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);
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("c")] = LittleFS.exists(FILE_MQTT_CA);
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("r")] = LittleFS.exists(FILE_MQTT_CERT);
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("k")] = LittleFS.exists(FILE_MQTT_KEY);
|
||||
LittleFS.end();
|
||||
} else {
|
||||
doc["q"]["s"]["c"] = false;
|
||||
doc["q"]["s"]["r"] = false;
|
||||
doc["q"]["s"]["k"] = false;
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("c")] = false;
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("r")] = false;
|
||||
doc[PSTR("q")][PSTR("s")][PSTR("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;
|
||||
doc[PSTR("p")][PSTR("e")] = strlen(entsoe.token) > 0;
|
||||
doc[PSTR("p")][PSTR("t")] = entsoe.token;
|
||||
doc[PSTR("p")][PSTR("r")] = entsoe.area;
|
||||
doc[PSTR("p")][PSTR("c")] = entsoe.currency;
|
||||
doc[PSTR("p")][PSTR("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;
|
||||
doc[PSTR("d")][PSTR("s")] = debugConfig.serial;
|
||||
doc[PSTR("d")][PSTR("t")] = debugConfig.telnet;
|
||||
doc[PSTR("d")][PSTR("l")] = debugConfig.level;
|
||||
|
||||
GpioConfig gpioConfig;
|
||||
config->getGpioConfig(gpioConfig);
|
||||
if(gpioConfig.hanPin == 0xff)
|
||||
doc["i"]["h"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("h")] = nullptr;
|
||||
else
|
||||
doc["i"]["h"] = gpioConfig.hanPin;
|
||||
doc[PSTR("i")][PSTR("h")] = gpioConfig.hanPin;
|
||||
|
||||
if(gpioConfig.apPin == 0xff)
|
||||
doc["i"]["a"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("a")] = nullptr;
|
||||
else
|
||||
doc["i"]["a"] = gpioConfig.apPin;
|
||||
doc[PSTR("i")][PSTR("a")] = gpioConfig.apPin;
|
||||
|
||||
if(gpioConfig.ledPin == 0xff)
|
||||
doc["i"]["l"]["p"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("l")][PSTR("p")] = nullptr;
|
||||
else
|
||||
doc["i"]["l"]["p"] = gpioConfig.ledPin;
|
||||
doc[PSTR("i")][PSTR("l")][PSTR("p")] = gpioConfig.ledPin;
|
||||
|
||||
doc["i"]["l"]["i"] = gpioConfig.ledInverted;
|
||||
doc[PSTR("i")][PSTR("l")][PSTR("i")] = gpioConfig.ledInverted;
|
||||
|
||||
if(gpioConfig.ledPinRed == 0xff)
|
||||
doc["i"]["r"]["r"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("r")] = nullptr;
|
||||
else
|
||||
doc["i"]["r"]["r"] = gpioConfig.ledPinRed;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("r")] = gpioConfig.ledPinRed;
|
||||
|
||||
if(gpioConfig.ledPinGreen == 0xff)
|
||||
doc["i"]["r"]["g"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("g")] = nullptr;
|
||||
else
|
||||
doc["i"]["r"]["g"] = gpioConfig.ledPinGreen;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("g")] = gpioConfig.ledPinGreen;
|
||||
|
||||
if(gpioConfig.ledPinBlue == 0xff)
|
||||
doc["i"]["r"]["b"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("b")] = nullptr;
|
||||
else
|
||||
doc["i"]["r"]["b"] = gpioConfig.ledPinBlue;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("b")] = gpioConfig.ledPinBlue;
|
||||
|
||||
doc["i"]["r"]["i"] = gpioConfig.ledRgbInverted;
|
||||
doc[PSTR("i")][PSTR("r")][PSTR("i")] = gpioConfig.ledRgbInverted;
|
||||
|
||||
if(gpioConfig.tempSensorPin == 0xff)
|
||||
doc["i"]["t"]["d"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("t")][PSTR("d")] = nullptr;
|
||||
else
|
||||
doc["i"]["t"]["d"] = gpioConfig.tempSensorPin;
|
||||
doc[PSTR("i")][PSTR("t")][PSTR("d")] = gpioConfig.tempSensorPin;
|
||||
|
||||
if(gpioConfig.tempAnalogSensorPin == 0xff)
|
||||
doc["i"]["t"]["a"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("t")][PSTR("a")] = nullptr;
|
||||
else
|
||||
doc["i"]["t"]["a"] = gpioConfig.tempAnalogSensorPin;
|
||||
doc[PSTR("i")][PSTR("t")][PSTR("a")] = gpioConfig.tempAnalogSensorPin;
|
||||
|
||||
if(gpioConfig.vccPin == 0xff)
|
||||
doc["i"]["v"]["p"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("p")] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["p"] = gpioConfig.vccPin;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("p")] = gpioConfig.vccPin;
|
||||
|
||||
if(gpioConfig.vccOffset == 0)
|
||||
doc["i"]["v"]["o"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("o")] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["o"] = gpioConfig.vccOffset / 100.0;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("o")] = gpioConfig.vccOffset / 100.0;
|
||||
|
||||
if(gpioConfig.vccMultiplier == 0)
|
||||
doc["i"]["v"]["m"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("m")] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["m"] = gpioConfig.vccMultiplier / 1000.0;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("m")] = gpioConfig.vccMultiplier / 1000.0;
|
||||
|
||||
if(gpioConfig.vccResistorVcc == 0)
|
||||
doc["i"]["v"]["d"]["v"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("d")][PSTR("v")] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["d"]["v"] = gpioConfig.vccResistorVcc;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("d")][PSTR("v")] = gpioConfig.vccResistorVcc;
|
||||
|
||||
if(gpioConfig.vccResistorGnd == 0)
|
||||
doc["i"]["v"]["d"]["g"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("d")][PSTR("g")] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["d"]["g"] = gpioConfig.vccResistorGnd;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("d")][PSTR("g")] = gpioConfig.vccResistorGnd;
|
||||
|
||||
if(gpioConfig.vccBootLimit == 0)
|
||||
doc["i"]["v"]["b"] = nullptr;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("b")] = nullptr;
|
||||
else
|
||||
doc["i"]["v"]["b"] = gpioConfig.vccBootLimit / 10.0;
|
||||
doc[PSTR("i")][PSTR("v")][PSTR("b")] = gpioConfig.vccBootLimit / 10.0;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
@@ -1094,18 +1101,23 @@ void AmsWebServer::handleSave() {
|
||||
if(server.hasArg(F("q")) && server.arg(F("q")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received MQTT config"));
|
||||
MqttConfig mqtt;
|
||||
config->getMqttConfig(mqtt);
|
||||
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"));
|
||||
String pass = server.arg(F("qa"));
|
||||
if(!pass.equals("***")) {
|
||||
strcpy(mqtt.password, pass.c_str());
|
||||
}
|
||||
mqtt.payloadFormat = server.arg(F("qm")).toInt();
|
||||
#if defined(ESP8266)
|
||||
mqtt.ssl = false;
|
||||
#else
|
||||
mqtt.ssl = server.arg(F("qs")) == F("true");
|
||||
#endif
|
||||
|
||||
mqtt.port = server.arg(F("qp")).toInt();
|
||||
if(mqtt.port == 0) {
|
||||
@@ -1156,14 +1168,7 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
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;
|
||||
}
|
||||
strcpy(ntp.timezone, server.arg(F("gt")).c_str());
|
||||
config->setNtpConfig(ntp);
|
||||
}
|
||||
|
||||
@@ -1251,22 +1256,23 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Saving configuration now..."));
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
if (config->save()) {
|
||||
doc["success"] = success;
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Successfully saved."));
|
||||
if(config->isWifiChanged() || performRestart) {
|
||||
performRestart = true;
|
||||
doc["reboot"] = true;
|
||||
} else {
|
||||
doc["reboot"] = false;
|
||||
hw->setup(gpioConfig, config);
|
||||
}
|
||||
} else {
|
||||
doc["success"] = false;
|
||||
doc["reboot"] = false;
|
||||
success = false;
|
||||
}
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
success ? "true" : "false",
|
||||
"",
|
||||
performRestart ? "true" : "false"
|
||||
);
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
server.handleClient();
|
||||
@@ -1300,7 +1306,7 @@ void AmsWebServer::reboot() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /reboot over http...\n");
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["reboot"] = true;
|
||||
doc[PSTR("reboot")] = true;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
@@ -1321,14 +1327,18 @@ void AmsWebServer::reboot() {
|
||||
void AmsWebServer::upgrade() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /upgrade over http...\n");
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["success"] = sys.dataCollectionConsent == 1;
|
||||
doc["reboot"] = sys.dataCollectionConsent == 1;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
sys.dataCollectionConsent == 1 ? "true" : "false",
|
||||
"",
|
||||
sys.dataCollectionConsent == 1 ? "true" : "false"
|
||||
);
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
if(sys.dataCollectionConsent == 1) {
|
||||
@@ -1460,7 +1470,13 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) {
|
||||
LittleFS.end();
|
||||
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(PSTR("An Error has occurred while writing file"));
|
||||
server.send_P(500, MIME_JSON, PSTR("{ \"success\": false, \"message\": \"Unable to upload\" }"));
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
"false",
|
||||
"Unable to upload",
|
||||
"false"
|
||||
);
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(500, MIME_JSON, buf);
|
||||
}
|
||||
}
|
||||
} else if(upload.status == UPLOAD_FILE_END) {
|
||||
@@ -1469,7 +1485,13 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) {
|
||||
file.close();
|
||||
// LittleFS.end();
|
||||
} else {
|
||||
server.send_P(500, MIME_JSON, PSTR("{ \"success\": false, \"message\": \"Unable to upload\" }"));
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
"false",
|
||||
"Unable to upload",
|
||||
"false"
|
||||
);
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(500, MIME_JSON, buf);
|
||||
}
|
||||
}
|
||||
return upload;
|
||||
@@ -1496,11 +1518,12 @@ void AmsWebServer::factoryResetPost() {
|
||||
success = true;
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["success"] = success;
|
||||
doc["reboot"] = success;
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
success ? "true" : "false",
|
||||
"",
|
||||
"true"
|
||||
);
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
server.handleClient();
|
||||
@@ -1518,3 +1541,85 @@ void AmsWebServer::factoryResetPost() {
|
||||
void AmsWebServer::robotstxt() {
|
||||
server.send_P(200, MIME_HTML, PSTR("User-agent: *\nDisallow: /\n"));
|
||||
}
|
||||
|
||||
void AmsWebServer::mqttCaUpload() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
uploadFile(FILE_MQTT_CA);
|
||||
HTTPUpload& upload = server.upload();
|
||||
if(upload.status == UPLOAD_FILE_END) {
|
||||
server.sendHeader(HEADER_LOCATION,F("/configuration"));
|
||||
server.send(303);
|
||||
|
||||
MqttConfig mqttConfig;
|
||||
if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) {
|
||||
config->setMqttChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::mqttCertUpload() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
uploadFile(FILE_MQTT_CERT);
|
||||
HTTPUpload& upload = server.upload();
|
||||
if(upload.status == UPLOAD_FILE_END) {
|
||||
server.sendHeader(HEADER_LOCATION,F("/configuration"));
|
||||
server.send(303);
|
||||
MqttConfig mqttConfig;
|
||||
if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) {
|
||||
config->setMqttChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::mqttKeyUpload() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
uploadFile(FILE_MQTT_KEY);
|
||||
HTTPUpload& upload = server.upload();
|
||||
if(upload.status == UPLOAD_FILE_END) {
|
||||
server.sendHeader(HEADER_LOCATION,F("/configuration"));
|
||||
server.send(303);
|
||||
MqttConfig mqttConfig;
|
||||
if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) {
|
||||
config->setMqttChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::tariffJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /tariff.json over http...\n");
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
|
||||
server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
EnergyAccountingConfig* eac = ea->getConfig();
|
||||
EnergyAccountingData data = ea->getData();
|
||||
|
||||
DynamicJsonDocument doc(512);
|
||||
JsonArray thresholds = doc.createNestedArray(PSTR("t"));
|
||||
for(uint8_t x = 0;x < 10; x++) {
|
||||
thresholds.add(eac->thresholds[x]);
|
||||
}
|
||||
JsonArray peaks = doc.createNestedArray(PSTR("p"));
|
||||
for(uint8_t x = 0;x < min((uint8_t) 5, eac->hours); x++) {
|
||||
JsonObject p = peaks.createNestedObject();
|
||||
EnergyAccountingPeak peak = ea->getPeak(x);
|
||||
p["d"] = peak.day;
|
||||
p["v"] = peak.value / 100.0;
|
||||
}
|
||||
doc["c"] = ea->getCurrentThreshold();
|
||||
doc["m"] = ea->getMonthMax();
|
||||
|
||||
serializeJson(doc, buf, BufferSize);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user