GUI improvements after testign

This commit is contained in:
Gunnar Skjold
2024-04-02 10:54:40 +02:00
parent 766849d6fc
commit 517869f43d
12 changed files with 152 additions and 56 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -34,17 +34,13 @@
}
if(sysinfo.ui.k === 1) {
console.log("dark");
document.documentElement.classList.add('dark')
} else if (sysinfo.ui.k === 0) {
console.log("light");
document.documentElement.classList.remove('dark')
} else {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
console.log("dark auto");
document.documentElement.classList.add('dark')
} else {
console.log("light auto");
document.documentElement.classList.remove('dark')
}
}

View File

@@ -38,10 +38,11 @@
translations = update;
});
let it,et;
let it,et,threePhase;
$: {
it = formatUnit(data?.ic * 1000, "Wh");
et = formatUnit(data?.ec * 1000, "Wh");
threePhase = data?.l1?.u > 100 && data?.l2?.u > 100 && data?.l3?.u > 100;
}
</script>
@@ -80,7 +81,7 @@
{#if data.l1}
<PerPhasePlot title={translations.common?.amperage ?? "Amp"} unit="A" importColorFn={ampcol} exportColorFn={exportcol}
maxImport={data.mf}
maxExport={data.om ? data.om / 230 : 0}
maxExport={data.om ? threePhase ? data.om / 0.4 / Math.sqrt(3) : data.om / 0.23 : 0}
l1={data.l1 && data.l1.u > 100}
l2={data.l2 && data.l2.u > 100}
l3={data.l3 && data.l3.u > 100}
@@ -88,9 +89,9 @@
l1i={Math.max(data.l1.i,0)}
l2i={Math.max(data.l2.i,0)}
l3i={Math.max(data.l3.i,0)}
l1e={Math.min(data.l1.i*-1,0)}
l2e={Math.min(data.l2.i*-1,0)}
l3e={Math.min(data.l3.i*-1,0)}
l1e={Math.max(data.l1.e,0)}
l2e={Math.max(data.l2.e,0)}
l3e={Math.max(data.l3.e,0)}
/>
{/if}
</div>
@@ -100,15 +101,15 @@
{#if data.l1}
<PerPhasePlot title={translations.dashboard?.phase ?? "Phase"} unit="W" importColorFn={ampcol} exportColorFn={exportcol}
maxImport={(data.mf ? data.mf : 32) * 230}
maxExport={data.om}
maxExport={data.om ? threePhase ? (data.om * 1000) / Math.sqrt(3) : data.om * 1000 : 0}
l1={data.l1 && data.l1.u > 100}
l2={data.l2 && data.l2.u > 100}
l3={data.l3 && data.l3.u > 100}
l1i={data.l1.p}
l1e={data.l1.q}
l2i={data.l2.p}
l2e={data.l2.q}
l3i={data.l3.p}
l1e={data.l1.q}
l2e={data.l2.q}
l3e={data.l3.q}
/>
{/if}

View File

@@ -1,7 +1,10 @@
import { readable, writable } from 'svelte/store';
import { isBusPowered, zeropad, scanForDevice } from './Helpers';
export async function fetchWithTimeout(resource, options = {}) {
let queueMap = {}
let queue = [];
async function fetchWithTimeoutReal(resource, options = {}) {
const { timeout = 8000 } = options;
const controller = new AbortController();
@@ -14,6 +17,38 @@ export async function fetchWithTimeout(resource, options = {}) {
return response;
}
let eatTimeout;
async function eatQueue() {
if(queue.length) {
let item = queue.shift();
delete queueMap[item.resource];
let response = await fetchWithTimeoutReal(item.resource, item.options);
for(let i in item.callbacks) {
item.callbacks[i](response);
}
}
if(eatTimeout) clearTimeout(eatTimeout);
eatTimeout = setTimeout(eatQueue, 100);
};
eatQueue();
export async function fetchWithTimeout(resource, options = {}) {
let item;
if(queueMap[resource]) {
item = queueMap[resource];
} else {
item = {
resource: resource,
options: options,
callbacks: []
};
queueMap[resource] = item;
queue.push(item);
}
let promise = new Promise((cb) => item.callbacks.push(cb));
return promise;
}
let sysinfo = {
version: '',
chip: '',
@@ -231,14 +266,26 @@ export async function getGitHubReleases() {
gitHubReleaseStore.set(releases);
};
let realtime = {};
let realtimeOffset = 0;
let realtime = { data: [] };
export async function getRealtime() {
const response = await fetchWithTimeout("realtime.json");
realtime = (await response.json())
realtimeStore.set(realtime);
const response = await fetchWithTimeout(realtimeOffset < 0 ? "realtime.json" : "realtime.json?offset="+realtimeOffset);
let res = (await response.json())
realtimeStore.update(current => {
for(let i = 0; i < res.size; i++) {
current.data[res.offset+i] = res.data[i];
}
current.size = current.data.length;
return current;
});
if(realtimeOffset >= 0) {
realtimeOffset += res.size;
if(realtimeOffset < res.total) {
setTimeout(getRealtime, 2000);
} else {
realtimeOffset = -1;
}
}
}
export const realtimeStore = writable(realtime, (set) => {
getRealtime();
return function stop() {}
});
export const realtimeStore = writable(realtime);

View File

@@ -0,0 +1,7 @@
<script></script>
<!-- Heroicons -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>

View File

@@ -8,6 +8,9 @@
import Uptime from "./Uptime.svelte";
import Badge from './Badge.svelte';
import Clock from './Clock.svelte';
import GearIcon from './GearIcon.svelte';
import InfoIcon from "./InfoIcon.svelte";
import HelpIcon from "./HelpIcon.svelte";
export let basepath = "/";
export let data = {};
@@ -79,14 +82,14 @@
</div>
{#if sysinfo.vndcfg && sysinfo.usrcfg}
<div class="flex-none px-1 mt-1" style="font-size: 18px;font-weight:bold;" title={translations.header?.config ?? ""}>
<Link to="/configuration">&#9965;</Link>
<Link to="/configuration"><GearIcon/></Link>
</div>
<div class="flex-none px-1 mt-1" style="font-size: 18px;font-weight:bold;" title={translations.header?.status ?? ""}>
<Link to="/status">&#9432;</Link>
<Link to="/status"><InfoIcon/></Link>
</div>
{/if}
<div class="flex-none px-1 mt-1" style="font-size: 18px;font-weight:bold;" title={translations.header?.doc ?? ""}>
<a href={wiki('')} target='_blank' rel="noreferrer">&#128464;</a>
<a href={wiki('')} target='_blank' rel="noreferrer"><HelpIcon/></a>
</div>
{#if sysinfo.fwconsent === 1 && nextVersion}
<div class="flex-none mr-3 text-yellow-500" title={(translations.header?.new_version ?? "New version") + ': ' + nextVersion.tag_name}>

View File

@@ -0,0 +1,6 @@
<script></script>
<!-- Heroicons -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
</svg>

View File

@@ -0,0 +1,6 @@
<script></script>
<!-- Heroicons -->
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
</svg>

View File

@@ -77,7 +77,6 @@
ticks.push({ value: maxImport, label: '100%' });
}
config = {
title: title,
padding: { top: 20, right: 15, bottom: 20, left: 35 },

View File

@@ -1,34 +1,49 @@
<script>
import { dataStore, realtimeStore } from './DataStores.js';
import { dataStore, realtimeStore, getRealtime } from './DataStores.js';
export let title;
let dark = document.documentElement.classList.contains('dark');
let realtime;
realtimeStore.subscribe(update => {
realtime = update;
});
let blankTimeout;
let addTimeout;
let lastUp = 0;
let lastValue = 0;
let lastUpdate = 0;
let realtimeRequested = false;
let realtime = null;
let realtimeTimeout;
realtimeStore.subscribe(update => {
realtime = update;
lastUpdate = lastUp;
if(realtimeTimeout) clearTimeout(realtimeTimeout);
realtimeTimeout = setTimeout(getRealtime, 600000);
});
function addValue() {
if(blankTimeout) clearTimeout(blankTimeout);
blankTimeout = setTimeout(addValue, 10000);
realtime.data.unshift(lastValue);
realtime.data = realtime.data.slice(0,realtime.size);
lastUp += 10;
if(addTimeout) clearTimeout(addTimeout);
if(lastUpdate > lastUp || lastUpdate - lastUp > 300) {
getRealtime();
} else {
while(lastUp > lastUpdate) {
realtime.data.unshift(lastValue);
realtime.data = realtime.data.slice(0,realtime.size);
lastUpdate += 10;
}
addTimeout = setTimeout(addValue, 10000);
}
}
dataStore.subscribe(update => {
if(lastUp == 0) {
if(blankTimeout) clearTimeout(blankTimeout);
blankTimeout = setTimeout(addValue, 10000);
}
lastValue = update.i-update.e;
lastUp = update.u;
if(!realtimeRequested) {
getRealtime();
realtimeRequested = true;
return;
}
if(!realtime?.data?.length) return;
if(!addTimeout) addTimeout = setTimeout(addValue, 10000);
});
let max;
@@ -59,6 +74,7 @@
if(realtime.data) {
for(let p in realtime.data) {
let val = realtime.data[p];
if(isNaN(val)) val = 0;
max = Math.max(Math.ceil(val/1000.0)*1000, max);
min = Math.min(Math.ceil(val/1000.0)*1000, min);
}
@@ -95,6 +111,7 @@
break;
}
let val = realtime.data[p];
if(isNaN(val)) val = 0;
points = xScale(i--)+","+yScale(val)+" "+points;
}
}

View File

@@ -1991,18 +1991,32 @@ void AmsWebServer::realtimeJson() {
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
snprintf_P(buf, BufferSize, PSTR("{\"size\":\"%d\",\"data\":["), rtp->getSize());
server.send(200, MIME_JSON, buf);
uint16_t offset = 0;
if(server.hasArg(F("offset"))) {
offset = server.arg(F("offset")).toInt();
}
uint16_t size = 60;
if(server.hasArg(F("size"))) {
size = server.arg(F("size")).toInt();
}
if(size > rtp->getSize()) {
size = rtp->getSize();
}
if(offset > rtp->getSize()) {
offset = rtp->getSize();
}
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"offset\":%d,\"size\":%d,\"total\":%d,\"data\":["), offset, size, rtp->getSize());
bool first = true;
for(uint16_t i = 0; i < rtp->getSize(); i++) {
snprintf_P(buf, BufferSize, PSTR("%s%d"), first ? "" : ",", rtp->getValue(i));
server.sendContent(buf);
for(uint16_t i = 0; i < size; i++) {
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR("%s%d"), first ? "" : ",", rtp->getValue(offset+i));
first = false;
delay(1);
}
snprintf_P(buf, BufferSize, PSTR("]}"));
server.sendContent(buf);
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR("]}"));
server.send(200, MIME_JSON, buf);
}
void AmsWebServer::setPriceSettings(String region, String currency) {