Compare commits
2 Commits
Shunt-inte
...
39fec8bdfa
| Author | SHA1 | Date | |
|---|---|---|---|
| 39fec8bdfa | |||
| f1ca9ed5ff |
5475
package-lock.json
generated
Normal file
5475
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
export interface AMSMessage {
|
||||
type: 'error' | 'status' | 'shunt' | 'slaveStatus' | 'slaveLog';
|
||||
type: 'error' | 'status' | 'slaveStatus' | 'slaveLog' | 'shuntCurrentLog' | 'shuntVoltage1Log' | 'shuntVoltage2Log';
|
||||
}
|
||||
|
||||
export interface AMSError extends AMSMessage {
|
||||
@ -29,30 +29,6 @@ export interface AMSStatus extends AMSMessage {
|
||||
// TODO: IMD state & R_iso
|
||||
}
|
||||
|
||||
export interface Shunt extends AMSMessage {
|
||||
type: 'shunt';
|
||||
|
||||
logType: 'current' | 'voltage1' | 'voltage2';
|
||||
}
|
||||
|
||||
export interface ShuntCurrent extends Shunt {
|
||||
logType: 'current';
|
||||
|
||||
current: number;
|
||||
}
|
||||
|
||||
export interface ShuntVoltage1 extends Shunt {
|
||||
logType: 'voltage1';
|
||||
|
||||
voltage: number;
|
||||
}
|
||||
|
||||
export interface ShuntVoltage2 extends Shunt {
|
||||
logType: 'voltage2';
|
||||
|
||||
voltage: number;
|
||||
}
|
||||
|
||||
export interface SlaveStatus extends AMSMessage {
|
||||
type: 'slaveStatus';
|
||||
|
||||
@ -92,3 +68,9 @@ export interface SlaveLogTemperature extends SlaveLog {
|
||||
startIndex: number;
|
||||
temperatures: [number, number, number, number, number, number, number, number];
|
||||
}
|
||||
|
||||
export interface ShuntLog extends AMSMessage {
|
||||
type: 'shuntCurrentLog' | 'shuntVoltage1Log' | 'shuntVoltage2Log';
|
||||
|
||||
value: number;
|
||||
}
|
||||
@ -1,22 +1,21 @@
|
||||
<script lang="ts">
|
||||
import type { AMSError, AMSMessage, AMSStatus, Shunt, ShuntCurrent, ShuntVoltage1, ShuntVoltage2, SlaveLog, SlaveStatus } from '$lib/messages';
|
||||
import type { AMSError, AMSMessage, AMSStatus, SlaveLog, SlaveStatus, ShuntLog } from '$lib/messages';
|
||||
import { source } from 'sveltekit-sse';
|
||||
import MasterStatusDisplay from './master-status-display.svelte';
|
||||
import SlaveStatusDisplay from './slave-status-display.svelte';
|
||||
import ShuntStatusDisplay from './shunt-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';
|
||||
// const value = source('/data').select('message');
|
||||
|
||||
let error: AMSError | undefined;
|
||||
let amsStatus: AMSStatus | undefined;
|
||||
let shunt: Shunt | undefined;
|
||||
let shuntA: ShuntCurrent | undefined
|
||||
let shuntV1: ShuntVoltage1 | undefined;
|
||||
let shuntV2: ShuntVoltage2 | 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)) {
|
||||
@ -40,9 +39,6 @@
|
||||
case 'status':
|
||||
amsStatus = msg as AMSStatus;
|
||||
break;
|
||||
case 'shunt':
|
||||
shunt = msg as Shunt;
|
||||
break;
|
||||
case 'slaveStatus': {
|
||||
const status = msg as SlaveStatus;
|
||||
slaveStatus[status.slaveId] = status;
|
||||
@ -51,14 +47,25 @@
|
||||
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;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="wrapper">
|
||||
<MasterErrorDisplay {error} />
|
||||
<MasterStatusDisplay status={amsStatus} />
|
||||
|
||||
<div class="vertical-wrapper">
|
||||
<MasterErrorDisplay {error} />
|
||||
<MasterStatusDisplay status={amsStatus} />
|
||||
<ShuntStatusDisplay currentLogData={shuntCurrentLog} voltage1LogData={shuntVoltage1Log} voltage2LogData={shuntVoltage2Log} />
|
||||
</div>
|
||||
{#each Object.entries(slaveStatus) as [id, status]}
|
||||
<SlaveStatusDisplay {id} {status} logData={slaveLog[id]} />
|
||||
{/each}
|
||||
@ -71,4 +78,13 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vertical-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@ -4,15 +4,12 @@ import type {
|
||||
AMSError,
|
||||
AMSMessage,
|
||||
AMSStatus,
|
||||
Shunt,
|
||||
ShuntCurrent,
|
||||
ShuntVoltage1,
|
||||
ShuntVoltage2,
|
||||
SlaveLog,
|
||||
SlaveLogLastCell,
|
||||
SlaveLogTemperature,
|
||||
SlaveLogVoltage,
|
||||
SlaveStatus
|
||||
SlaveStatus,
|
||||
ShuntLog
|
||||
} from '$lib/messages';
|
||||
import { N_CELLS_PER_SLAVE, N_TEMP_SENSORS_PER_SLAVE } from '$lib/defs';
|
||||
|
||||
@ -22,8 +19,9 @@ const CAN_ID_AMS_SLAVE_STATUS_BASE = 0x080;
|
||||
const CAN_ID_AMS_SLAVE_STATUS_MASK = 0xff0;
|
||||
const CAN_ID_AMS_SLAVE_LOG_BASE = 0x600;
|
||||
const CAN_ID_AMS_SLAVE_LOG_MASK = 0xf00;
|
||||
const CAN_ID_AMS_SHUNT_BASE = 0x520;
|
||||
const CAN_ID_AMS_SHUNT_MASK = 0xff0;
|
||||
const CAN_ID_SHUNT_CURRENT = 0x521;
|
||||
const CAN_ID_SHUNT_VOLTAGE_1 = 0x522;
|
||||
const CAN_ID_SHUNT_VOLTAGE_2 = 0x523;
|
||||
|
||||
type RawMessage = {
|
||||
ext?: boolean;
|
||||
@ -65,45 +63,6 @@ function decodeStatus(msg: RawMessage): AMSStatus | null {
|
||||
};
|
||||
}
|
||||
|
||||
function decodeShunt(msg: RawMessage): Shunt | null {
|
||||
if (msg.data.length != 6) {
|
||||
console.warn( 'invalid shunt frame', msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
const index = msg.id & 0x00f;
|
||||
const data = msg.data;
|
||||
if (index == 1) {
|
||||
const msg: ShuntCurrent = {
|
||||
type: 'shunt',
|
||||
|
||||
logType: 'current',
|
||||
current: data.readInt32BE(2) * 1e-3,
|
||||
};
|
||||
return msg;
|
||||
} else if (index == 2) {
|
||||
const msg: ShuntVoltage1 = {
|
||||
type: 'shunt',
|
||||
|
||||
logType: 'voltage1',
|
||||
voltage: data.readInt32BE(2) * 1e-3,
|
||||
};
|
||||
return msg;
|
||||
} else if (index == 3) {
|
||||
const msg: ShuntVoltage2 = {
|
||||
type: 'shunt',
|
||||
|
||||
logType: 'voltage2',
|
||||
voltage: data.readInt32BE(2) * 1e-3,
|
||||
};
|
||||
return msg;
|
||||
} else {
|
||||
console.warn('Unknown shunt index', msg.id);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function decodeSlaveStatus(msg: RawMessage): SlaveStatus | null {
|
||||
if (msg.data.length != 8) {
|
||||
console.warn('invalid slave status frame', msg);
|
||||
@ -177,6 +136,21 @@ function decodeSlaveLog(msg: RawMessage): SlaveLog | null {
|
||||
}
|
||||
}
|
||||
|
||||
function decodeShunt(msg: RawMessage, type: String): ShuntLog | null {
|
||||
if (msg.data.length != 6) {
|
||||
console.warn('invalid shunt log frame', msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = msg.data;
|
||||
|
||||
return {
|
||||
type: type,
|
||||
|
||||
value: data.readInt32BE(2) * 1e-3,
|
||||
};
|
||||
}
|
||||
|
||||
export function POST() {
|
||||
return produce(async function start({ emit }) {
|
||||
const network = can.createRawChannel('can0');
|
||||
@ -185,8 +159,9 @@ export function POST() {
|
||||
{ id: CAN_ID_AMS_STATUS, mask: 0xfff },
|
||||
{ id: CAN_ID_AMS_SLAVE_STATUS_BASE, mask: CAN_ID_AMS_SLAVE_STATUS_MASK },
|
||||
{ id: CAN_ID_AMS_SLAVE_LOG_BASE, mask: CAN_ID_AMS_SLAVE_LOG_MASK },
|
||||
{ id: CAN_ID_AMS_SHUNT_BASE, mask:
|
||||
CAN_ID_AMS_SHUNT_MASK }
|
||||
{ id: CAN_ID_SHUNT_CURRENT, mask: 0xfff },
|
||||
{ id: CAN_ID_SHUNT_VOLTAGE_1, mask: 0xfff },
|
||||
{ id: CAN_ID_SHUNT_VOLTAGE_2, mask: 0xfff }
|
||||
]);
|
||||
|
||||
network.addListener('onMessage', (msg: RawMessage) => {
|
||||
@ -200,8 +175,6 @@ export function POST() {
|
||||
message = decodeSlaveStatus(msg);
|
||||
} else if ((msg.id & CAN_ID_AMS_SLAVE_LOG_MASK) == CAN_ID_AMS_SLAVE_LOG_BASE) {
|
||||
message = decodeSlaveLog(msg);
|
||||
} else if ((msg.id & CAN_ID_AMS_SHUNT_MASK) == CAN_ID_AMS_SHUNT_BASE) {
|
||||
message = decodeShunt(msg);
|
||||
} else {
|
||||
switch (msg.id) {
|
||||
case CAN_ID_AMS_ERROR:
|
||||
@ -210,8 +183,15 @@ export function POST() {
|
||||
case CAN_ID_AMS_STATUS:
|
||||
message = decodeStatus(msg);
|
||||
break;
|
||||
default:
|
||||
console.warn('unknown frame', msg);
|
||||
case CAN_ID_SHUNT_CURRENT:
|
||||
message = decodeShunt(msg, 'shuntCurrentLog');
|
||||
break;
|
||||
case CAN_ID_SHUNT_VOLTAGE_1:
|
||||
message = decodeShunt(msg, 'shuntVoltage1Log');
|
||||
break;
|
||||
case CAN_ID_SHUNT_VOLTAGE_2:
|
||||
message = decodeShunt(msg, 'shuntVoltage2Log');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,20 +1,33 @@
|
||||
<script lang="ts">
|
||||
import type { Shunt, ShuntCurrent, ShuntVoltage1, ShuntVoltage2 } from "$lib/messages";
|
||||
export let shuntData: Shunt | undefined;
|
||||
export let shuntA: ShuntCurrent | undefined;
|
||||
export let shuntV1: ShuntVoltage1 | undefined;
|
||||
export let shuntV2: ShuntVoltage2 | undefined;
|
||||
import type { ShuntLog } from '$lib/messages';
|
||||
|
||||
export let currentLogData: ShuntLog | undefined;
|
||||
export let voltage1LogData: ShuntLog | undefined;
|
||||
export let voltage2LogData: ShuntLog | undefined;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="shunt-content">
|
||||
{#if shuntData}
|
||||
<h2><b>Shunt Data</b></h2>
|
||||
<div class="log-collumn">
|
||||
<div>Current: {Math.round(shuntA.current * 100) / 100} </div>
|
||||
<div>Battery side voltage: {Math.round(shuntV1.voltage * 100) / 100}</div>
|
||||
<div>Vehicle side voltage: {Math.round(shuntV2.voltage * 100) / 100}</div>
|
||||
</div>
|
||||
{/if}
|
||||
<h2><b>Shunt Status</b></h2>
|
||||
|
||||
<div class="log-collumn">
|
||||
<div class="log-entry">
|
||||
<div>Current:</div>
|
||||
<div><b>{Math.round(currentLogData?.value*10)/10}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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@ -22,14 +35,26 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 12vw;
|
||||
border: 2px solid black;
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
border: 2px solid black;
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
background-color: hsl(0, 60%, var(--lightness));
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
display: grid;
|
||||
grid-template-columns: 5fr 3fr;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
background-color: hsl(var(--hue), 80%, 80%);
|
||||
}
|
||||
|
||||
.log-collumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: hsl(0, 60%, var(--lightness));
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
@ -1,20 +1,58 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
import type { SlaveStatus } from '$lib/messages';
|
||||
import type { SlaveLogData } from '$lib/slave-log';
|
||||
import { SlaveLogData } from '$lib/slave-log';
|
||||
|
||||
export let id: number;
|
||||
export let status: SlaveStatus;
|
||||
export let logData: SlaveLogData | undefined;
|
||||
|
||||
let interval;
|
||||
let lastMsgTime: number = 0;
|
||||
let timeDifference: number = 0;
|
||||
|
||||
onMount(() => {
|
||||
interval = setInterval(() => {
|
||||
timeDifference = Date.now()-lastMsgTime;
|
||||
}, 50);
|
||||
});
|
||||
|
||||
$: totalVoltage = logData?.voltages.slice(0, 15).reduce((acc, x) => acc + x, 0);
|
||||
|
||||
$: {
|
||||
slavePing(logData);
|
||||
}
|
||||
|
||||
function slavePing(logData: SlaveLogData | undefined): void {
|
||||
lastMsgTime = Date.now();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="slave-content" style:--lightness={status.error ? "60%" : "100%"}>
|
||||
<h2><b>Slave #{id}</b></h2>
|
||||
<div class="slave-content" style:--lightness={status.error ? '70%' : '100%'}>
|
||||
<h2><b>Slave #{id} Δrx_t: {Math.round(timeDifference / 1000)}s</b></h2>
|
||||
|
||||
<div class="log-collumn">
|
||||
<div class="log-entry"><div>Error:</div><div><b>{status.error}</b></div></div>
|
||||
<div class="log-entry"><div>Min. cell voltage:</div><div><b>{Math.round(status.minCellVolt*100)/100}V</b></div></div>
|
||||
<div class="log-entry"><div>Max. cell voltage:</div><div><b>{Math.round(status.maxCellVolt*100)/100}V</b></div></div>
|
||||
<div class="log-entry"><div>Max. temperature:</div><div><b>{Math.round(status.maxTemp*100)/100}°</b></div></div>
|
||||
<div class="log-collumn" style:--lightness={'' + Math.max(100 - ((timeDifference-200) / 150), 70) + '%'}>
|
||||
<div class="log-entry">
|
||||
<div>Error:</div>
|
||||
<div><b>{status.error}</b></div>
|
||||
</div>
|
||||
<div class="log-entry">
|
||||
<div>Min. cell voltage:</div>
|
||||
<div><b>{Math.round(status.minCellVolt * 1000) / 1000}V</b></div>
|
||||
</div>
|
||||
<div class="log-entry">
|
||||
<div>Max. cell voltage:</div>
|
||||
<div><b>{Math.round(status.maxCellVolt * 1000) / 1000}V</b></div>
|
||||
</div>
|
||||
<div class="log-entry">
|
||||
<div>Max. temperature:</div>
|
||||
<div><b>{Math.round(status.maxTemp * 100) / 100}°</b></div>
|
||||
</div>
|
||||
<div class="log-entry">
|
||||
<div>Total voltage:</div>
|
||||
<div><b>{Math.round(totalVoltage * 100) / 100}V</b></div>
|
||||
</div>
|
||||
<!-- <div>SoC</div>
|
||||
<div>{status.soc}</div> -->
|
||||
<!-- <div>Failed temperature sensors</div>
|
||||
@ -25,15 +63,17 @@
|
||||
<div class="log-collumn">
|
||||
{#each logData.voltages as volt, i}
|
||||
{#if i < 15}
|
||||
<div class="log-entry" style:--hue={Math.max(((volt-2.5)*70.5), 0)}>
|
||||
<div>V{i}:</div><div><b>{Math.round(volt*100)/100}V</b></div>
|
||||
<div class="log-entry" style:--hue={Math.max((volt - 2.5) * 70.5, 0)}>
|
||||
<div>V{i}:</div>
|
||||
<div><b>{Math.round(volt * 1000) / 1000}V</b></div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
{#each logData.temperatures as temp, i}
|
||||
{#if i > 33 && i < 44}
|
||||
<div class="log-entry" style:--hue={210-(temp*3.5)}>
|
||||
<div>T{i}:</div><div><b>{temp}°</b></div>
|
||||
<div class="log-entry" style:--hue={210 - temp * 3.5}>
|
||||
<div>T{i}:</div>
|
||||
<div><b>{temp}°</b></div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
@ -51,7 +91,7 @@
|
||||
border: 2px solid black;
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
background-color: hsl(0, 60%, --lightness);
|
||||
background-color: hsl(0, 60%, var(--lightness));
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
@ -65,6 +105,7 @@
|
||||
.log-collumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: hsl(0, 60%, var(--lightness));
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
Reference in New Issue
Block a user