mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-14 07:49:01 +00:00
Created new UI with Svelte
This commit is contained in:
parent
e232b875fa
commit
8b0d4185d3
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,3 +15,5 @@ platformio-user.ini
|
||||
/sdkconfig
|
||||
/.tmp
|
||||
/*.zip
|
||||
node_modules
|
||||
/gui/dist
|
||||
24
ui/svelte/.gitignore
vendored
Normal file
24
ui/svelte/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
12
ui/svelte/index.html
Normal file
12
ui/svelte/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>AMS reader</title>
|
||||
</head>
|
||||
<body class="bg-gray-100">
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
34
ui/svelte/jsconfig.json
Normal file
34
ui/svelte/jsconfig.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
/**
|
||||
* svelte-preprocess cannot figure out whether you have
|
||||
* a value or a type, so tell TypeScript to enforce using
|
||||
* `import type` instead of `import` for Types.
|
||||
*/
|
||||
"importsNotUsedAsValues": "error",
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
/**
|
||||
* To have warnings / errors of the Svelte compiler at the
|
||||
* correct position, enable source maps by default.
|
||||
*/
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
/**
|
||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable this if you'd like to use dynamic types.
|
||||
*/
|
||||
"checkJs": true
|
||||
},
|
||||
/**
|
||||
* Use global.d.ts instead of compilerOptions.types
|
||||
* to avoid limiting type declarations.
|
||||
*/
|
||||
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
|
||||
}
|
||||
3106
ui/svelte/package-lock.json
generated
Normal file
3106
ui/svelte/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
ui/svelte/package.json
Normal file
22
ui/svelte/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "svelte-gui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"svelte": "^3.49.0",
|
||||
"vite": "^3.0.7",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"tailwindcss": "^3.1.5",
|
||||
"http-proxy-middleware": "^2.0.1"
|
||||
}
|
||||
}
|
||||
13
ui/svelte/postcss.config.cjs
Normal file
13
ui/svelte/postcss.config.cjs
Normal file
@ -0,0 +1,13 @@
|
||||
const tailwindcss = require("tailwindcss");
|
||||
const autoprefixer = require("autoprefixer");
|
||||
|
||||
const config = {
|
||||
plugins: [
|
||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
||||
tailwindcss(),
|
||||
//But others, like autoprefixer, need to run after,
|
||||
autoprefixer,
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
15
ui/svelte/src/App.svelte
Normal file
15
ui/svelte/src/App.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
import { dataStore } from './lib/DataStores.js';
|
||||
import Header from './lib/Header.svelte';
|
||||
import Dashboard from './lib/Dashboard.svelte';
|
||||
|
||||
let data = {};
|
||||
dataStore.subscribe(update => {
|
||||
data = update;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto m-3">
|
||||
<Header data={data}/>
|
||||
<Dashboard data={data}/>
|
||||
</div>
|
||||
8
ui/svelte/src/app.postcss
Normal file
8
ui/svelte/src/app.postcss
Normal file
@ -0,0 +1,8 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.gh-logo {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
6
ui/svelte/src/assets/github.svg
Normal file
6
ui/svelte/src/assets/github.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false">
|
||||
<title>GitHub</title>
|
||||
<path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="#f8f9fa" fill-rule="evenodd"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
33
ui/svelte/src/lib/AccountingData.svelte
Normal file
33
ui/svelte/src/lib/AccountingData.svelte
Normal file
@ -0,0 +1,33 @@
|
||||
<script>
|
||||
export let data;
|
||||
export let currency;
|
||||
</script>
|
||||
|
||||
<div class="mx-2 text-sm">
|
||||
<strong>Real time calculation</strong>
|
||||
|
||||
<div class="grid grid-cols-2 mt-4">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data && data.h && data.h.u ? data.h.u.toFixed(2) : '-'} kWh</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data && data.d && data.d.u ? data.d.u.toFixed(1) : '-'} kWh</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data && data.m && data.m.u ? data.m.u.toFixed(0) : '-'} kWh</div>
|
||||
</div>
|
||||
{#if currency}
|
||||
<div class="grid grid-cols-2 mt-4">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data && data.h && data.h.c ? data.h.c.toFixed(2) : '-'} {currency}</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data && data.d && data.d.c ? data.d.c.toFixed(1) : '-'} {currency}</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data && data.m && data.m.c ? data.m.c.toFixed(0) : '-'} {currency}</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 mt-4">
|
||||
<div>Max</div>
|
||||
<div class="text-right">
|
||||
{data && data.x ? data.x.toFixed(1) : '-'} / {data && data.t ? data.t.toFixed(1) : '-'} kWh
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
64
ui/svelte/src/lib/AmpPlot.svelte
Normal file
64
ui/svelte/src/lib/AmpPlot.svelte
Normal file
@ -0,0 +1,64 @@
|
||||
<script>
|
||||
import BarChart from './BarChart.svelte';
|
||||
import { ampcol } from './Helpers.js';
|
||||
|
||||
export let u1;
|
||||
export let u2;
|
||||
export let u3;
|
||||
export let i1;
|
||||
export let i2;
|
||||
export let i3;
|
||||
export let max;
|
||||
|
||||
let config = {};
|
||||
|
||||
$: {
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
if(u1 > 0) {
|
||||
xTicks.push({ label: 'L1' });
|
||||
points.push({
|
||||
label: i1 ? i1 + 'A' : '-',
|
||||
value: i1 ? i1 : 0,
|
||||
color: ampcol(i1 ? (i1)/(max)*100 : 0)
|
||||
});
|
||||
}
|
||||
if(u2 > 0) {
|
||||
xTicks.push({ label: 'L2' });
|
||||
points.push({
|
||||
label: i2 ? i2 + 'A' : '-',
|
||||
value: i2 ? i2 : 0,
|
||||
color: ampcol(i2 ? (i2)/(max)*100 : 0)
|
||||
});
|
||||
}
|
||||
if(u3 > 0) {
|
||||
xTicks.push({ label: 'L3' });
|
||||
points.push({
|
||||
label: i3 ? i3 + 'A' : '-',
|
||||
value: i3 ? i3 : 0,
|
||||
color: ampcol(i3 ? (i3)/(max)*100 : 0)
|
||||
});
|
||||
}
|
||||
config = {
|
||||
height: 250,
|
||||
width: 224,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: 0,
|
||||
max: max,
|
||||
ticks: [
|
||||
{ value: 0, label: '0%' },
|
||||
{ value: max/4, label: '25%' },
|
||||
{ value: max/2, label: '50%' },
|
||||
{ value: (max/4)*3, label: '75%' },
|
||||
{ value: max, label: '100%' }
|
||||
]
|
||||
},
|
||||
x: {
|
||||
ticks: xTicks
|
||||
},
|
||||
points: points
|
||||
};
|
||||
};
|
||||
</script>
|
||||
<BarChart config={config} />
|
||||
14
ui/svelte/src/lib/Badge.svelte
Normal file
14
ui/svelte/src/lib/Badge.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
export let color;
|
||||
export let title;
|
||||
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>
|
||||
{: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>
|
||||
{:else if color === `red`}
|
||||
<span title={title} class="my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
{:else if color === `gray`}
|
||||
<span title={title} class="my-auto bg-gray-500 text-gray-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">{text}</span>
|
||||
{/if}
|
||||
121
ui/svelte/src/lib/BarChart.svelte
Normal file
121
ui/svelte/src/lib/BarChart.svelte
Normal file
@ -0,0 +1,121 @@
|
||||
<script>
|
||||
export let config;
|
||||
|
||||
let barWidth;
|
||||
let xScale;
|
||||
let yScale;
|
||||
|
||||
$: {
|
||||
let innerWidth = config.width - (config.padding.left + config.padding.right);
|
||||
barWidth = innerWidth / config.points.length;
|
||||
|
||||
let yPerUnit = (config.height-config.padding.top-config.padding.bottom)/(config.y.max-config.y.min);
|
||||
|
||||
xScale = function(i) {
|
||||
return (i*barWidth)+config.padding.left;
|
||||
};
|
||||
yScale = function(i) {
|
||||
if(!i) return config.height-config.padding.bottom;
|
||||
if(i > config.y.max) return config.height;
|
||||
let ret = config.height-config.padding.bottom-((i-config.y.min)*yPerUnit);
|
||||
return ret > config.height || ret < 0 ? 0 : ret;
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="chart" bind:clientWidth={config.width} bind:clientHeight={config.height}>
|
||||
<svg height="{config.height}">
|
||||
<!-- y axis -->
|
||||
<g class="axis y-axis">
|
||||
{#each config.y.ticks as tick}
|
||||
<g class="tick tick-{tick.value}" transform="translate(0, {yScale(tick.value)})">
|
||||
<line x2="100%"></line>
|
||||
<text y="-4">{tick.label}</text>
|
||||
</g>
|
||||
{/each}
|
||||
</g>
|
||||
|
||||
<!-- x axis -->
|
||||
<g class="axis x-axis">
|
||||
{#each config.x.ticks as point, i}
|
||||
<g class="tick" transform="translate({xScale(i)},{config.height})">
|
||||
<text x="{barWidth/2}" y="-4">{point.label}</text>
|
||||
</g>
|
||||
{/each}
|
||||
</g>
|
||||
|
||||
<g class='bars'>
|
||||
{#each config.points as point, i}
|
||||
<rect
|
||||
x="{xScale(i) + 2}"
|
||||
y="{yScale(point.value)}"
|
||||
width="{barWidth - 4}"
|
||||
height="{yScale(0) - yScale(point.value)}"
|
||||
fill="{point.color}"
|
||||
/>
|
||||
<text
|
||||
y="{yScale(point.value) > yScale(0)-15 ? yScale(point.value) - 12 : yScale(point.value)+10}"
|
||||
x="{xScale(i) + barWidth/2}"
|
||||
width="{barWidth - 4}"
|
||||
dominant-baseline="middle"
|
||||
text-anchor="{barWidth < 25 ? 'left' : 'middle'}"
|
||||
fill="{yScale(point.value) > yScale(0)-15 ? point.color : 'white'}"
|
||||
transform="rotate({barWidth < 25 ? 90 : 0}, {xScale(i) + (barWidth/2)}, {yScale(point.value) > yScale(0)-12 ? yScale(point.value) - 12 : yScale(point.value)+10})"
|
||||
>{point.label}</text>
|
||||
{/each}
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 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;
|
||||
}
|
||||
|
||||
.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>
|
||||
12
ui/svelte/src/lib/Clock.svelte
Normal file
12
ui/svelte/src/lib/Clock.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import { zeropad } 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 }
|
||||
{`${zeropad(timestamp.getDate())}. ${monthnames[timestamp.getMonth()]} ${zeropad(timestamp.getHours())}:${zeropad(timestamp.getMinutes())}`}
|
||||
{:else}
|
||||
<span class="text-red-500">{`${zeropad(timestamp.getDate())}.${zeropad(timestamp.getMonth())}.${timestamp.getFullYear()} ${zeropad(timestamp.getHours())}:${zeropad(timestamp.getMinutes())}`}</span>
|
||||
{/if}
|
||||
10
ui/svelte/src/lib/Counter.svelte
Normal file
10
ui/svelte/src/lib/Counter.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let count = 0
|
||||
const increment = () => {
|
||||
count += 1
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={increment}>
|
||||
count is {count}
|
||||
</button>
|
||||
78
ui/svelte/src/lib/Dashboard.svelte
Normal file
78
ui/svelte/src/lib/Dashboard.svelte
Normal file
@ -0,0 +1,78 @@
|
||||
<script>
|
||||
import { pricesStore, dayPlotStore, monthPlotStore, temperaturesStore } from './DataStores.js';
|
||||
import { metertype } from './Helpers.js';
|
||||
import PowerGauge from './PowerGauge.svelte';
|
||||
import VoltPlot from './VoltPlot.svelte';
|
||||
import AmpPlot from './AmpPlot.svelte';
|
||||
import ReactiveData from './ReactiveData.svelte';
|
||||
import AccountingData from './AccountingData.svelte';
|
||||
import PricePlot from './PricePlot.svelte';
|
||||
import DayPlot from './DayPlot.svelte';
|
||||
import MonthPlot from './MonthPlot.svelte';
|
||||
import TemperaturePlot from './TemperaturePlot.svelte';
|
||||
|
||||
export let data = {}
|
||||
let prices = {}
|
||||
let dayPlot = {}
|
||||
let monthPlot = {}
|
||||
let temperatures = {};
|
||||
pricesStore.subscribe(update => {
|
||||
prices = update;
|
||||
});
|
||||
dayPlotStore.subscribe(update => {
|
||||
dayPlot = update;
|
||||
});
|
||||
monthPlotStore.subscribe(update => {
|
||||
monthPlot = update;
|
||||
});
|
||||
temperaturesStore.subscribe(update => {
|
||||
temperatures = update;
|
||||
});
|
||||
</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">
|
||||
<PowerGauge val={data.i ? data.i : 0} max={data.im} unit="W" label="Import"/>
|
||||
<div class="grid grid-cols-2">
|
||||
<div>{data.mt ? metertype(data.mt) : '-'}</div>
|
||||
<div class="text-right">{data.ic ? data.ic.toFixed(1) : '-'} kWh</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if data.om}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
<PowerGauge val={data.e ? data.e : 0} max={data.om} unit="W" label="Export"/>
|
||||
<div class="grid grid-cols-2">
|
||||
<div></div>
|
||||
<div class="text-right">{data.ec ? data.ec.toFixed(1) : '-'} kWh</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<AccountingData data={data.ea} currency={prices.currency}/>
|
||||
</div>
|
||||
{#if prices.currency}
|
||||
<div class="bg-white m-2 p-2 rounded shadow-lg xl:col-span-6 lg:col-span-3 md:col-span-3 sm:col-span-2">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<TemperaturePlot json={temperatures} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
72
ui/svelte/src/lib/DataStores.js
Normal file
72
ui/svelte/src/lib/DataStores.js
Normal file
@ -0,0 +1,72 @@
|
||||
import { readable } from 'svelte/store';
|
||||
|
||||
let data = {};
|
||||
export const dataStore = readable(data, (set) => {
|
||||
async function getData(){
|
||||
const response = await fetch("/data.json");
|
||||
data = (await response.json())
|
||||
set(data);
|
||||
}
|
||||
const interval = setInterval(getData, 5000);
|
||||
getData();
|
||||
return function stop() {
|
||||
clearInterval(interval);
|
||||
}
|
||||
});
|
||||
|
||||
let prices = {};
|
||||
export const pricesStore = readable(prices, (set) => {
|
||||
async function getPrices(){
|
||||
const response = await fetch("/energyprice.json");
|
||||
prices = (await response.json())
|
||||
set(prices);
|
||||
}
|
||||
const date = new Date();
|
||||
const timeout = setTimeout(getPrices, (61-date.getMinutes())*60000)
|
||||
getPrices();
|
||||
return function stop() {}
|
||||
});
|
||||
|
||||
let dayPlot = {};
|
||||
export const dayPlotStore = readable(dayPlot, (set) => {
|
||||
async function getDayPlot(){
|
||||
const response = await fetch("/dayplot.json");
|
||||
dayPlot = (await response.json())
|
||||
set(dayPlot);
|
||||
}
|
||||
const date = new Date();
|
||||
const timeout = setTimeout(getDayPlot, (61-date.getMinutes())*60000)
|
||||
getDayPlot();
|
||||
return function stop() {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
});
|
||||
|
||||
let monthPlot = {};
|
||||
export const monthPlotStore = readable(monthPlot, (set) => {
|
||||
async function getmonthPlot(){
|
||||
const response = await fetch("/monthplot.json");
|
||||
monthPlot = (await response.json())
|
||||
set(monthPlot);
|
||||
}
|
||||
const date = new Date();
|
||||
const timeout = setTimeout(getmonthPlot, (24-date.getHours())*3600000)
|
||||
getmonthPlot();
|
||||
return function stop() {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
});
|
||||
|
||||
let temperatures = {};
|
||||
export const temperaturesStore = readable(temperatures, (set) => {
|
||||
async function getTemperatures(){
|
||||
const response = await fetch("/temperature.json");
|
||||
temperatures = (await response.json())
|
||||
set(temperatures);
|
||||
}
|
||||
const interval = setInterval(getTemperatures, 60000);
|
||||
getTemperatures();
|
||||
return function stop() {
|
||||
clearTimeout(interval);
|
||||
}
|
||||
});
|
||||
92
ui/svelte/src/lib/DayPlot.svelte
Normal file
92
ui/svelte/src/lib/DayPlot.svelte
Normal file
@ -0,0 +1,92 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import BarChart from './BarChart.svelte';
|
||||
|
||||
export let json;
|
||||
|
||||
let config = {};
|
||||
let max = 0;
|
||||
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 = [];
|
||||
let cur = new Date();
|
||||
for(i = hour; i<24; i++) {
|
||||
imp = json["i"+zeropad(i)];
|
||||
exp = json["e"+zeropad(i)];
|
||||
val = imp-exp;
|
||||
if(!val) val = 0;
|
||||
|
||||
cur.setUTCHours(i);
|
||||
xTicks.push({
|
||||
label: zeropad(cur.getHours())
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(2),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
};
|
||||
for(i = 0; i < hour; i++) {
|
||||
imp = json["i"+zeropad(i)];
|
||||
exp = json["e"+zeropad(i)];
|
||||
val = imp-exp;
|
||||
if(!val) val = 0;
|
||||
|
||||
cur.setUTCHours(i);
|
||||
xTicks.push({
|
||||
label: zeropad(cur.getHours())
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(2),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
};
|
||||
|
||||
max = Math.ceil(max);
|
||||
min = Math.floor(min);
|
||||
let range = max;
|
||||
if(min < 0) range += Math.abs(min);
|
||||
let yTickDist = range/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
val = min + (yTickDist*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val.toFixed(1)
|
||||
});
|
||||
}
|
||||
|
||||
config = {
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
max: max,
|
||||
ticks: yTicks
|
||||
},
|
||||
x: {
|
||||
ticks: xTicks
|
||||
},
|
||||
points: points
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Energy use last 24 hours (kWh)</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
35
ui/svelte/src/lib/Header.svelte
Normal file
35
ui/svelte/src/lib/Header.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script>
|
||||
import GitHubLogo from './../assets/github.svg';
|
||||
import Badge from './Badge.svelte';
|
||||
import Clock from './Clock.svelte';
|
||||
|
||||
export let data = {}
|
||||
let timestamp = new Date(0);
|
||||
</script>
|
||||
|
||||
<nav class="bg-violet-600 p-1 rounded-md mx-2">
|
||||
<div class="flex flex-wrap space-x-4 text-sm text-gray-300">
|
||||
<div class="flex-none text-lg text-gray-100 p-2">
|
||||
<a href="/">AMS reader <span>v0.0.0</span></a>
|
||||
</div>
|
||||
<div class="flex-none my-auto p-2 flex space-x-4">
|
||||
<div class="flex-none my-auto">Up { data.u ? data.u : '-' }</div>
|
||||
<div class="flex-none my-auto">{ data.t ? data.t.toFixed(1) : '-' }°C</div>
|
||||
<div class="flex-none my-auto">Free mem: {data.m ? (data.m/1000).toFixed(1) : '-'}kb</div>
|
||||
</div>
|
||||
<div class="flex-auto my-auto justify-center p-2">
|
||||
<Badge title="ESP" text={data.v > 0 ? data.v.toFixed(2)+"V" : "ESP"} color={data.em === 1 ? 'green' : data.em === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="HAN" text="HAN" color={data.hm === 1 ? 'green' : data.hm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="WiFi" text={data.r ? data.r.toFixed(0)+"dBm" : "WiFi"} color={data.wm === 1 ? 'green' : data.wm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="MQTT" text="MQTT" color={data.mm === 1 ? 'green' : data.mm === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
</div>
|
||||
<div class="flex-auto p-2 flex flex-row-reverse">
|
||||
<div class="flex-none">
|
||||
<a class="float-right" href='https://github.com/gskjold/AmsToMqttBridge' target='_blank' rel="noreferrer" aria-label="GitHub"><img class="gh-logo" src={GitHubLogo} alt="GitHub repo"/></a>
|
||||
</div>
|
||||
<div class="flex-none my-auto px-2">
|
||||
<Clock timestamp={ data.c ? new Date(data.c * 1000) : new Date(0) } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
44
ui/svelte/src/lib/Helpers.js
Normal file
44
ui/svelte/src/lib/Helpers.js
Normal file
@ -0,0 +1,44 @@
|
||||
export function voltcol(pct) {
|
||||
if(pct > 85) return '#d90000';
|
||||
else if(pct > 75) return'#e32100';
|
||||
else if(pct > 70) return '#ffb800';
|
||||
else if(pct > 65) return '#dcd800';
|
||||
else if(pct > 35) return '#32d900';
|
||||
else if(pct > 25) return '#dcd800';
|
||||
else if(pct > 20) return '#ffb800';
|
||||
else if(pct > 15) return'#e32100';
|
||||
else return '#d90000';
|
||||
};
|
||||
|
||||
export function ampcol(pct) {
|
||||
if(pct > 90) return '#d90000';
|
||||
else if(pct > 85) return'#e32100';
|
||||
else if(pct > 80) return '#ffb800';
|
||||
else if(pct > 75) return '#dcd800';
|
||||
else return '#32d900';
|
||||
};
|
||||
|
||||
export function metertype(mt) {
|
||||
switch(mt) {
|
||||
case 1:
|
||||
return "Aidon";
|
||||
case 2:
|
||||
return "Kaifa";
|
||||
case 3:
|
||||
return "Kamstrup";
|
||||
case 8:
|
||||
return "Iskra";
|
||||
case 9:
|
||||
return "Landis";
|
||||
case 10:
|
||||
return "Sagemcom";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function zeropad(num) {
|
||||
num = num.toString();
|
||||
while (num.length < 2) num = "0" + num;
|
||||
return num;
|
||||
}
|
||||
93
ui/svelte/src/lib/MonthPlot.svelte
Normal file
93
ui/svelte/src/lib/MonthPlot.svelte
Normal file
@ -0,0 +1,93 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import BarChart from './BarChart.svelte';
|
||||
|
||||
export let json;
|
||||
|
||||
let config = {};
|
||||
let max = 0;
|
||||
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 = [];
|
||||
let cur = new Date();
|
||||
let lm = new Date();
|
||||
lm.setDate(0);
|
||||
|
||||
for(i = cur.getDate(); i<=lm.getDate(); i++) {
|
||||
imp = json["i"+zeropad(i)];
|
||||
exp = json["e"+zeropad(i)];
|
||||
val = imp-exp;
|
||||
if(!val) val = 0;
|
||||
|
||||
xTicks.push({
|
||||
label: zeropad(i)
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(0),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
}
|
||||
for(i = 1; i < cur.getDate(); i++) {
|
||||
imp = json["i"+zeropad(i)];
|
||||
exp = json["e"+zeropad(i)];
|
||||
val = imp-exp;
|
||||
if(!val) val = 0;
|
||||
|
||||
xTicks.push({
|
||||
label: zeropad(i)
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(0),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
}
|
||||
|
||||
max = Math.ceil(max/10)*10;
|
||||
min = Math.floor(min/10)*10;
|
||||
let range = max;
|
||||
if(min < 0) range += Math.abs(min);
|
||||
let yTickDist = range/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
val = min + (yTickDist*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val.toFixed(0)
|
||||
});
|
||||
}
|
||||
|
||||
config = {
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
max: max,
|
||||
ticks: yTicks
|
||||
},
|
||||
x: {
|
||||
ticks: xTicks
|
||||
},
|
||||
points: points
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Energy use last month (kWh)</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
43
ui/svelte/src/lib/PowerGauge.svelte
Normal file
43
ui/svelte/src/lib/PowerGauge.svelte
Normal file
@ -0,0 +1,43 @@
|
||||
<script>
|
||||
import PowerGaugeSvg from './PowerGaugeSvg.svelte';
|
||||
import { ampcol } from './Helpers.js';
|
||||
|
||||
export let val;
|
||||
export let max;
|
||||
export let unit;
|
||||
export let label;
|
||||
</script>
|
||||
|
||||
<div class="overlay-plot">
|
||||
<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>
|
||||
<br/>
|
||||
<span class="plot-label">{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;
|
||||
cursor: pointer;
|
||||
}
|
||||
.plot-unit {
|
||||
font-size: 1.0rem;
|
||||
color: grey;
|
||||
}
|
||||
.plot-label {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
</style>
|
||||
39
ui/svelte/src/lib/PowerGaugeSvg.svelte
Normal file
39
ui/svelte/src/lib/PowerGaugeSvg.svelte
Normal file
@ -0,0 +1,39 @@
|
||||
<script>
|
||||
export let pct = 0;
|
||||
export let color = "red";
|
||||
let width = 300;
|
||||
let height = 300;
|
||||
|
||||
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
|
||||
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
|
||||
|
||||
return {
|
||||
x: centerX + (radius * Math.cos(angleInRadians)),
|
||||
y: centerY + (radius * Math.sin(angleInRadians))
|
||||
};
|
||||
}
|
||||
function describeArc(x, y, radius, startAngle, endAngle){
|
||||
var start = polarToCartesian(x, y, radius, endAngle);
|
||||
var end = polarToCartesian(x, y, radius, startAngle);
|
||||
|
||||
var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";
|
||||
|
||||
var d = [
|
||||
"M", start.x, start.y,
|
||||
"A", radius, radius, 0, arcSweep, 0, end.x, end.y
|
||||
].join(" ");
|
||||
|
||||
return d;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="gauge" bind:clientWidth={width} bind:clientHeight={height}>
|
||||
<svg height="100%"
|
||||
width="100%"
|
||||
viewBox="0 0 300 300"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<path d="{ describeArc(150, 150, 115, 210, 510) }" stroke="#eee" fill="none" stroke-width="55"/>
|
||||
<path d="{ describeArc(150, 150, 115, 210, 210 + (510*pct/100)) }" stroke={color} fill="none" stroke-width="55"/>
|
||||
</svg>
|
||||
</div>
|
||||
85
ui/svelte/src/lib/PricePlot.svelte
Normal file
85
ui/svelte/src/lib/PricePlot.svelte
Normal file
@ -0,0 +1,85 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import BarChart from './BarChart.svelte';
|
||||
|
||||
export let json;
|
||||
|
||||
let config = {};
|
||||
let max = 0;
|
||||
let min = 0;
|
||||
|
||||
$: {
|
||||
let hour = new Date().getUTCHours();
|
||||
let i = 0;
|
||||
let val = 0;
|
||||
let h = 0;
|
||||
let d = json["20"] == null ? 2 : 1;
|
||||
let yTicks = [];
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
let cur = new Date();
|
||||
for(i = hour; i<24; i++) {
|
||||
cur.setUTCHours(i);
|
||||
val = json[zeropad(h++)];
|
||||
if(val == null) break;
|
||||
xTicks.push({
|
||||
label: zeropad(cur.getHours())
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(d),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
};
|
||||
for(i = 0; i < 24; i++) {
|
||||
cur.setUTCHours(i);
|
||||
val = json[zeropad(h++)];
|
||||
if(val == null) break;
|
||||
xTicks.push({
|
||||
label: zeropad(cur.getHours())
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(d),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
};
|
||||
|
||||
max = Math.ceil(max);
|
||||
min = Math.floor(min);
|
||||
let range = max;
|
||||
if(min < 0) range += Math.abs(min);
|
||||
let yTickDist = range/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
val = min + (yTickDist*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val.toFixed(2)
|
||||
});
|
||||
}
|
||||
|
||||
config = {
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
max: max,
|
||||
ticks: yTicks
|
||||
},
|
||||
x: {
|
||||
ticks: xTicks
|
||||
},
|
||||
points: points
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Future energy price ({json.currency})</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
24
ui/svelte/src/lib/ReactiveData.svelte
Normal file
24
ui/svelte/src/lib/ReactiveData.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
export let importInstant;
|
||||
export let exportInstant;
|
||||
export let importTotal;
|
||||
export let exportTotal;
|
||||
</script>
|
||||
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Reactive</strong>
|
||||
|
||||
<div class="grid grid-cols-2 mt-4">
|
||||
<div>Instant in</div>
|
||||
<div class="text-right">{typeof importInstant !== 'undefined' ? importInstant.toFixed(0) : '-'} VAr</div>
|
||||
<div>Instant out</div>
|
||||
<div class="text-right">{typeof exportInstant !== 'undefined' ? exportInstant.toFixed(0) : '-'} VAr</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 mt-4">
|
||||
<div>Total in</div>
|
||||
<div class="text-right">{typeof importTotal !== 'undefined' ? importTotal.toFixed(1) : '-'} kVArh</div>
|
||||
<div>Total out</div>
|
||||
<div class="text-right">{typeof exportTotal !== 'undefined' ? exportTotal.toFixed(1) : '-'} kVArh</div>
|
||||
</div>
|
||||
</div>
|
||||
72
ui/svelte/src/lib/TemperaturePlot.svelte
Normal file
72
ui/svelte/src/lib/TemperaturePlot.svelte
Normal file
@ -0,0 +1,72 @@
|
||||
<script>
|
||||
import { zeropad } from './Helpers.js';
|
||||
import BarChart from './BarChart.svelte';
|
||||
|
||||
export let json;
|
||||
|
||||
let config = {};
|
||||
let max = 0;
|
||||
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 = [];
|
||||
if(json.s) {
|
||||
json.s.forEach((obj, i) => {
|
||||
var name = obj.n ? obj.n : obj.a;
|
||||
val = obj.v;
|
||||
if(val == -127) val = 0;
|
||||
xTicks.push({
|
||||
label: name.slice(-4)
|
||||
});
|
||||
points.push({
|
||||
label: val.toFixed(1),
|
||||
value: val,
|
||||
color: '#7c3aed'
|
||||
});
|
||||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
});
|
||||
}
|
||||
|
||||
max = Math.ceil(max);
|
||||
min = Math.floor(min);
|
||||
let range = max;
|
||||
if(min < 0) range += Math.abs(min);
|
||||
let yTickDist = range/4;
|
||||
for(i = 0; i < 5; i++) {
|
||||
val = min + (yTickDist*i);
|
||||
yTicks.push({
|
||||
value: val,
|
||||
label: val.toFixed(1)
|
||||
});
|
||||
}
|
||||
|
||||
config = {
|
||||
height: 226,
|
||||
width: 1520,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
max: max,
|
||||
ticks: yTicks
|
||||
},
|
||||
x: {
|
||||
ticks: xTicks
|
||||
},
|
||||
points: points
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Temperature sensors (°C)</strong>
|
||||
<BarChart config={config} />
|
||||
</div>
|
||||
61
ui/svelte/src/lib/VoltPlot.svelte
Normal file
61
ui/svelte/src/lib/VoltPlot.svelte
Normal file
@ -0,0 +1,61 @@
|
||||
<script>
|
||||
import BarChart from './BarChart.svelte';
|
||||
import { voltcol } from './Helpers.js';
|
||||
|
||||
export let u1;
|
||||
export let u2;
|
||||
export let u3;
|
||||
export let ds;
|
||||
|
||||
let min = 200;
|
||||
let max = 260;
|
||||
let config = {};
|
||||
|
||||
$: {
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
if(u1 > 0) {
|
||||
xTicks.push({ label: ds === 1 ? 'L1-L2' : 'L1' });
|
||||
points.push({
|
||||
label: u1 ? u1 + 'V' : '-',
|
||||
value: u1 ? u1 : 0,
|
||||
color: voltcol(u1 ? (u1-min)/(max-min)*100 : 0)
|
||||
});
|
||||
}
|
||||
if(u2 > 0) {
|
||||
xTicks.push({ label: ds === 1 ? 'L1-L3' : 'L2' });
|
||||
points.push({
|
||||
label: u2 ? u2 + 'V' : '-',
|
||||
value: u2 ? u2 : 0,
|
||||
color: voltcol(u2 ? (u2-min)/(max-min)*100 : 0)
|
||||
});
|
||||
}
|
||||
if(u3 > 0) {
|
||||
xTicks.push({ label: ds === 1 ? 'L2-L3' : 'L3' });
|
||||
points.push({
|
||||
label: u3 ? u3 + 'V' : '-',
|
||||
value: u3 ? u3 : 0,
|
||||
color: voltcol(u3 ? (u3-min)/(max-min)*100 : 0)
|
||||
});
|
||||
}
|
||||
config = {
|
||||
height: 250,
|
||||
width: 224,
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
max: max,
|
||||
ticks: [
|
||||
{ value: 207, label: '-10%' },
|
||||
{ value: 230, label: '230v' },
|
||||
{ value: 253, label: '+10%' }
|
||||
]
|
||||
},
|
||||
x: {
|
||||
ticks: xTicks
|
||||
},
|
||||
points: points
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<BarChart config={config} />
|
||||
9
ui/svelte/src/main.js
Normal file
9
ui/svelte/src/main.js
Normal file
@ -0,0 +1,9 @@
|
||||
import "./app.postcss";
|
||||
import App from "./App.svelte";
|
||||
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById("app"),
|
||||
});
|
||||
|
||||
export default app;
|
||||
2
ui/svelte/src/vite-env.d.ts
vendored
Normal file
2
ui/svelte/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/// <reference types="svelte" />
|
||||
/// <reference types="vite/client" />
|
||||
11
ui/svelte/svelte.config.js
Normal file
11
ui/svelte/svelte.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
import preprocess from "svelte-preprocess";
|
||||
|
||||
const config = {
|
||||
preprocess: [
|
||||
preprocess({
|
||||
postcss: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
11
ui/svelte/tailwind.config.cjs
Normal file
11
ui/svelte/tailwind.config.cjs
Normal file
@ -0,0 +1,11 @@
|
||||
const config = {
|
||||
content: ["./index.html","./src/**/*.{html,js,svelte,ts}"],
|
||||
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
16
ui/svelte/vite.config.js
Normal file
16
ui/svelte/vite.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.235",
|
||||
"/energyprice.json": "http://192.168.233.235",
|
||||
"/dayplot.json": "http://192.168.233.235",
|
||||
"/monthplot.json": "http://192.168.233.235",
|
||||
"/temperature.json": "http://192.168.233.235",
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user