Compare commits
2 Commits
a34a70ef2f
...
917464347a
Author | SHA1 | Date |
---|---|---|
Jasper Blanckenburg | 917464347a | |
Jasper Blanckenburg | 1da81476f7 |
|
@ -0,0 +1,80 @@
|
|||
import { source } from 'sveltekit-sse';
|
||||
import {
|
||||
decodeMessage,
|
||||
unmarshalMessage,
|
||||
type AMSError,
|
||||
type AMSStatus,
|
||||
type MarshalledMessage,
|
||||
type ShuntLog,
|
||||
type SlaveLog,
|
||||
type SlaveStatus
|
||||
} from './messages';
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
import { SlaveLogData } from './slave-log';
|
||||
|
||||
export type ShuntData = {
|
||||
current: number;
|
||||
voltage1: number;
|
||||
voltage2: number;
|
||||
};
|
||||
|
||||
export const error: Writable<AMSError | undefined> = writable(undefined);
|
||||
export const amsStatus: Writable<AMSStatus | undefined> = writable(undefined);
|
||||
export const slaveStatus: Writable<Record<number, SlaveStatus>> = writable({});
|
||||
export const slaveLog: Writable<Record<number, SlaveLogData>> = writable({});
|
||||
export const shunt: Writable<ShuntData> = writable({ current: 0, voltage1: 0, voltage2: 0 });
|
||||
|
||||
source('/data')
|
||||
.select('message')
|
||||
.subscribe((value) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
const msg = decodeMessage(unmarshalMessage(JSON.parse(value) as MarshalledMessage));
|
||||
if (!msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.type) {
|
||||
case 'error':
|
||||
error.set(msg as AMSError);
|
||||
break;
|
||||
case 'status':
|
||||
amsStatus.set(msg as AMSStatus);
|
||||
break;
|
||||
case 'slaveStatus': {
|
||||
const status = msg as SlaveStatus;
|
||||
slaveStatus.update((r) => {
|
||||
r[status.slaveId] = status;
|
||||
return r;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'slaveLog':
|
||||
handleSlaveLog(msg as SlaveLog);
|
||||
break;
|
||||
case 'shuntCurrentLog':
|
||||
shunt.update((s) => {
|
||||
s.current = (msg as ShuntLog).value;
|
||||
return s;
|
||||
});
|
||||
break;
|
||||
case 'shuntVoltage1Log':
|
||||
shunt.update((s) => Object.assign(s, { voltage1: (msg as ShuntLog).value }));
|
||||
break;
|
||||
case 'shuntVoltage2Log':
|
||||
shunt.update((s) => Object.assign(s, { voltage2: (msg as ShuntLog).value }));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
function handleSlaveLog(msg: SlaveLog) {
|
||||
slaveLog.update((r) => {
|
||||
if (!(msg.slaveId in r)) {
|
||||
r[msg.slaveId] = new SlaveLogData();
|
||||
}
|
||||
const slave = r[msg.slaveId];
|
||||
slave.handleMsg(msg);
|
||||
return r;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<script lang="ts">
|
||||
import '../app.css';
|
||||
</script>
|
||||
|
||||
<slot />
|
|
@ -1,93 +1,26 @@
|
|||
<script lang="ts">
|
||||
import {
|
||||
type AMSError,
|
||||
type AMSMessage,
|
||||
type AMSStatus,
|
||||
type SlaveLog,
|
||||
type SlaveStatus,
|
||||
type ShuntLog,
|
||||
type MarshalledMessage,
|
||||
unmarshalMessage,
|
||||
decodeMessage
|
||||
} from '$lib/messages';
|
||||
import { source } from 'sveltekit-sse';
|
||||
import MasterStatusDisplay from './master-status-display.svelte';
|
||||
import SlaveStatusDisplay from './slave-status-display.svelte';
|
||||
import '../app.css';
|
||||
import MasterErrorDisplay from './master-error-display.svelte';
|
||||
import { SlaveLogData } from '$lib/slave-log';
|
||||
import ShuntStatusDisplay from './shunt-status-display.svelte';
|
||||
import Overview from './overview.svelte';
|
||||
|
||||
let error: AMSError | undefined;
|
||||
let amsStatus: AMSStatus | undefined;
|
||||
let slaveStatus: Record<number, SlaveStatus> = {};
|
||||
let slaveLog: Record<number, SlaveLogData> = {};
|
||||
let shuntCurrentLog: ShuntLog | undefined;
|
||||
let shuntVoltage1Log: ShuntLog | undefined;
|
||||
let shuntVoltage2Log: ShuntLog | undefined;
|
||||
|
||||
function handleSlaveLog(msg: SlaveLog) {
|
||||
if (!(msg.slaveId in slaveLog)) {
|
||||
slaveLog[msg.slaveId] = new SlaveLogData();
|
||||
}
|
||||
const slave = slaveLog[msg.slaveId];
|
||||
slave.handleMsg(msg);
|
||||
}
|
||||
|
||||
source('/data')
|
||||
.select('message')
|
||||
.subscribe((value) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
const msg = decodeMessage(unmarshalMessage(JSON.parse(value) as MarshalledMessage));
|
||||
if (!msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.type) {
|
||||
case 'error':
|
||||
error = msg as AMSError;
|
||||
break;
|
||||
case 'status':
|
||||
amsStatus = msg as AMSStatus;
|
||||
break;
|
||||
case 'slaveStatus': {
|
||||
const status = msg as SlaveStatus;
|
||||
slaveStatus[status.slaveId] = status;
|
||||
break;
|
||||
}
|
||||
case 'slaveLog':
|
||||
handleSlaveLog(msg as SlaveLog);
|
||||
break;
|
||||
case 'shuntCurrentLog':
|
||||
shuntCurrentLog = msg as ShuntLog;
|
||||
break;
|
||||
case 'shuntVoltage1Log':
|
||||
shuntVoltage1Log = msg as ShuntLog;
|
||||
break;
|
||||
case 'shuntVoltage2Log':
|
||||
shuntVoltage2Log = msg as ShuntLog;
|
||||
break;
|
||||
}
|
||||
});
|
||||
import { amsStatus, error, shunt, slaveLog, slaveStatus } from '$lib/client';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Charging</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="vertical-wrapper">
|
||||
<Overview {amsStatus} current={shuntCurrentLog?.value} voltage={shuntVoltage1Log?.value} />
|
||||
<Overview amsStatus={$amsStatus} shunt={$shunt} showPopout={true} />
|
||||
<div class="wrapper">
|
||||
<MasterErrorDisplay {error} />
|
||||
<MasterStatusDisplay status={amsStatus} />
|
||||
<ShuntStatusDisplay
|
||||
currentLogData={shuntCurrentLog}
|
||||
voltage1LogData={shuntVoltage1Log}
|
||||
voltage2LogData={shuntVoltage2Log}
|
||||
/>
|
||||
<MasterErrorDisplay error={$error} />
|
||||
<MasterStatusDisplay status={$amsStatus} />
|
||||
<ShuntStatusDisplay data={$shunt} />
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
{#each Object.entries(slaveStatus) as [id, status]}
|
||||
<SlaveStatusDisplay {id} {status} logData={slaveLog[id]} />
|
||||
{#each Object.entries($slaveStatus) as [id, status]}
|
||||
<SlaveStatusDisplay {id} {status} logData={$slaveLog[id]} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,32 +1,48 @@
|
|||
<script lang="ts">
|
||||
import type { ShuntData } from '$lib/client';
|
||||
import { AMSState, type AMSStatus } from '$lib/messages';
|
||||
|
||||
export let amsStatus: AMSStatus | undefined;
|
||||
export let current: number | undefined;
|
||||
export let voltage: number | undefined;
|
||||
export let shunt: ShuntData;
|
||||
export let showPopout: boolean = false;
|
||||
</script>
|
||||
|
||||
<div class="overview grid grid-rows-3 gap-3">
|
||||
{#if amsStatus != null && current != null && voltage != null}
|
||||
<div class="progress" data-label="{amsStatus.soc}%">
|
||||
<span class="value" style="width:{amsStatus.soc}%;"></span>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<span class="text-center border-r">{voltage.toFixed(1)} V</span>
|
||||
<span class="text-center border-r">{current.toFixed(1)} A</span>
|
||||
<span class="text-center border-r">{amsStatus.maxCellTemp.toFixed(1)}°C</span>
|
||||
<span class="text-center">SDC {amsStatus.sdcClosed ? '✅' : '❌'}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button
|
||||
class="w-1/2 bg-green-600 text-white font-bold h-8 rounded-md hover:bg-green-800 disabled:bg-gray-600"
|
||||
disabled={amsStatus.state != AMSState.TS_INACTIVE}
|
||||
on:click={() => {
|
||||
fetch('/start-charging', { method: 'POST' });
|
||||
}}>Start Charging</button
|
||||
<div class="flex flex-col w-[30rem] border-2 border-black p-1 m-1">
|
||||
{#if showPopout}
|
||||
<div class="flex flex-row justify-end mb-2">
|
||||
<a
|
||||
class="text-sm underline hover:no-underline"
|
||||
href="/overview"
|
||||
target="_blank"
|
||||
on:click|preventDefault={() => {
|
||||
window.open('/overview', 'newwindow', 'width=500,height=200,resizable=yes');
|
||||
return false;
|
||||
}}>Pop out</a
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-rows-3 gap-3">
|
||||
{#if amsStatus != null}
|
||||
<div class="progress" data-label="{amsStatus.soc}%">
|
||||
<span class="value" style="width:{amsStatus.soc}%;"></span>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<span class="text-center border-r">{shunt.voltage1.toFixed(1)} V</span>
|
||||
<span class="text-center border-r">{shunt.current.toFixed(1)} A</span>
|
||||
<span class="text-center border-r">{amsStatus.maxCellTemp.toFixed(1)}°C</span>
|
||||
<span class="text-center">SDC {amsStatus.sdcClosed ? '✅' : '❌'}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button
|
||||
class="w-1/2 bg-green-600 text-white font-bold h-8 rounded-md hover:bg-green-800 disabled:bg-gray-600"
|
||||
disabled={amsStatus.state != AMSState.TS_INACTIVE}
|
||||
on:click={() => {
|
||||
fetch('/start-charging', { method: 'POST' });
|
||||
}}>Start Charging</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
import Overview from '../overview.svelte';
|
||||
import { amsStatus, shunt } from '$lib/client';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Charging Overview</title>
|
||||
</svelte:head>
|
||||
|
||||
<Overview amsStatus={$amsStatus} shunt={$shunt} />
|
|
@ -1,10 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { ShuntLog } from '$lib/messages';
|
||||
|
||||
export let currentLogData: ShuntLog | undefined;
|
||||
export let voltage1LogData: ShuntLog | undefined;
|
||||
export let voltage2LogData: ShuntLog | undefined;
|
||||
import type { ShuntData } from '$lib/client';
|
||||
|
||||
export let data: ShuntData;
|
||||
</script>
|
||||
|
||||
<div class="shunt-content">
|
||||
|
@ -13,19 +10,19 @@
|
|||
<div class="log-collumn">
|
||||
<div class="log-entry">
|
||||
<div>Current:</div>
|
||||
<div><b>{Math.round(currentLogData?.value*10)/10}A</b></div>
|
||||
<div><b>{data.current.toFixed(1)} A</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-collumn">
|
||||
<div class="log-entry">
|
||||
<div>Voltage Accu:</div>
|
||||
<div><b>{Math.round(voltage1LogData?.value*100)/100}V</b></div>
|
||||
<div><b>{data.voltage1.toFixed(2)} V</b></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-collumn">
|
||||
<div class="log-entry">
|
||||
<div>Voltage Vehicle:</div>
|
||||
<div><b>{Math.round(voltage2LogData?.value*100)/100}V</b></div>
|
||||
<div><b>{data.voltage2.toFixed(2)} V</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue