[WIP] adjustments to topology

This commit is contained in:
Sina Blattmann 2023-06-13 09:27:56 +02:00
parent a9d95fd71e
commit 3a4c768074
10 changed files with 206 additions and 135 deletions

View File

@ -4,7 +4,6 @@ import { UnixTime, TimeSpan } from "../../../dataCache/time";
import { createTimes } from "../../../util/graph.util"; import { createTimes } from "../../../util/graph.util";
import { import {
DatePicker, DatePicker,
DateTimePicker,
DateTimeValidationError, DateTimeValidationError,
LocalizationProvider, LocalizationProvider,
} from "@mui/x-date-pickers"; } from "@mui/x-date-pickers";

View File

@ -1,101 +1,14 @@
import React from "react"; import React from "react";
import ScalarGraph, { testData } from "./ScalarGraph"; import ScalarGraph from "./ScalarGraph";
import TopologyColumn from "./TopologyColumn"; import TopologyView from "./TopologyView";
import { Box } from "@mui/material";
import { extractTopologyValues, parseCsv } from "../../../util/graph.util";
import { UnixTime } from "../../../dataCache/time";
const Log = () => { const Log = () => {
const values = extractTopologyValues({ return (
time: UnixTime.fromTicks(192384239), <>
value: parseCsv(testData), <TopologyView />
}); <ScalarGraph />
</>
if (values) { );
return (
<>
<Box
sx={{
display: "flex",
flexDirection: "row",
width: "1000px",
overflow: "auto",
padding: 2,
}}
>
<div>
<TopologyColumn
centerBox={{
title: "Grid",
data: values.acInBus,
connectionData: values.gridToAcIn,
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "AcInBus",
data: values.acInBus,
connectionData: values.dcBusToDcDc,
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "AcOutBus",
data: values.acOutBus,
connectionData: values.dcBusToDcDc,
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "Inverter",
data: values.acOutBus,
connectionData: values.dcBusToDcDc,
}}
/>
</div>
<div>
<TopologyColumn
topBox={{
title: "MPPT",
data: values.acOutBus,
connectionData: values.mpptToDcBus,
}}
centerBox={{
title: "DcBus",
data: values.acOutBus,
connectionData: values.dcBusToDcDc,
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "DcDc",
data: values.acOutBus,
connectionData: values.dcDCToBattery,
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "Battery",
data: values.acOutBus,
}}
/>
</div>
</Box>
<ScalarGraph />
</>
);
}
return null;
}; };
export default Log; export default Log;

View File

@ -641,6 +641,7 @@ const ScalarGraph = () => {
layout={{ layout={{
width: 1000, width: 1000,
height: 500, height: 500,
autosize: true,
title: visibleGraphs[index], title: visibleGraphs[index],
uirevision: uiRevision, uirevision: uiRevision,
xaxis: { xaxis: {
@ -781,7 +782,7 @@ const ScalarGraph = () => {
.length .length
} }
itemSize={() => 500} itemSize={() => 500}
width={1000} width="100%"
itemData={coordinateTimeSeries} itemData={coordinateTimeSeries}
> >
{Row} {Row}

View File

@ -9,12 +9,14 @@ export type BoxData = {
export type TopologyBoxProps = { export type TopologyBoxProps = {
title?: string; title?: string;
data?: BoxData[]; data?: BoxData[];
connectionData?: BoxData[]; };
const isInt = (value: number) => {
return value % 1 === 0;
}; };
export const BOX_SIZE = 150; export const BOX_SIZE = 150;
const TopologyBox = (props: TopologyBoxProps) => { const TopologyBox = (props: TopologyBoxProps) => {
console.log("boxdata", props.data);
return ( return (
<Box <Box
sx={{ sx={{
@ -26,10 +28,22 @@ const TopologyBox = (props: TopologyBoxProps) => {
}} }}
> >
<Box sx={{ padding: "5px" }}> <Box sx={{ padding: "5px" }}>
{props.title} <p style={{ marginBlockStart: "2px" }}>{props.title}</p>
{props.data && {props.data &&
props.data.map((el) => ( props.data.map((el) => (
<p>{`${el.label} ${el.values} ${el.unit}`}</p> <div>
{el.label}
{el.values.map((value) => {
return (
<p
style={{ marginBlockStart: "2px", marginBlockEnd: "2px" }}
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
>{`${
!isInt(Number(value)) ? Number(value).toPrecision(8) : value
}${el.unit}`}</p>
);
})}
</div>
))} ))}
</Box> </Box>
</Box> </Box>

View File

@ -1,12 +1,16 @@
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import TopologyBox, { TopologyBoxProps } from "./ToplogyBox"; import TopologyBox, { TopologyBoxProps } from "./ToplogyBox";
import TopologyFlow from "./TopologyFlow"; import TopologyFlow, { TopologyFlowProps } from "./TopologyFlow";
type TopologyColumnProps = { type TopologyColumnProps = {
topBox?: TopologyBoxProps; topBox?: TopologyBoxProps;
topConnection?: TopologyFlowProps;
centerBox?: TopologyBoxProps; centerBox?: TopologyBoxProps;
centerConnection?: TopologyFlowProps;
bottomBox?: TopologyBoxProps; bottomBox?: TopologyBoxProps;
bottomConnection?: TopologyFlowProps;
}; };
const TopologyColumn = (props: TopologyColumnProps) => { const TopologyColumn = (props: TopologyColumnProps) => {
return ( return (
<Box <Box
@ -21,26 +25,23 @@ const TopologyColumn = (props: TopologyColumnProps) => {
<div> <div>
<TopologyBox {...props.topBox} /> <TopologyBox {...props.topBox} />
<TopologyFlow <TopologyFlow
{...props.topConnection}
orientation="vertical" orientation="vertical"
amount={0.5}
hidden={!props.topBox} hidden={!props.topBox}
data={props.topBox?.connectionData}
/> />
<TopologyBox {...props.centerBox} /> <TopologyBox {...props.centerBox} />
<TopologyFlow <TopologyFlow
{...props.bottomConnection}
orientation="vertical" orientation="vertical"
amount={0.7}
hidden={!props.bottomBox} hidden={!props.bottomBox}
data={props.bottomBox?.connectionData}
/> />
<TopologyBox {...props.bottomBox} /> <TopologyBox {...props.bottomBox} />
</div> </div>
<div> <div>
<TopologyFlow <TopologyFlow
{...props.centerConnection}
orientation="horizontal" orientation="horizontal"
amount={0.1}
hidden={!props.centerBox} hidden={!props.centerBox}
data={props.centerBox?.connectionData}
/> />
</div> </div>
</Box> </Box>

View File

@ -9,8 +9,8 @@
.container { .container {
position: relative; position: relative;
width: 150px; width: 130px;
height: 150px; height: 130px;
overflow: hidden; overflow: hidden;
} }

View File

@ -2,30 +2,35 @@ import { Box } from "@mui/material";
import { BOX_SIZE, BoxData } from "./ToplogyBox"; import { BOX_SIZE, BoxData } from "./ToplogyBox";
import "./TopologyFlow.scss"; import "./TopologyFlow.scss";
type TopologyFlowProps = { export type TopologyFlowProps = {
orientation: "vertical" | "horizontal"; orientation?: "vertical" | "horizontal";
amount: number; amount?: number;
direction?: "leftToRight" | "rightToLeft";
data?: BoxData[]; data?: BoxData[];
hidden?: boolean; hidden?: boolean;
}; };
const TopologyFlow = (props: TopologyFlowProps) => { const TopologyFlow = (props: TopologyFlowProps) => {
const length = Math.abs(props.amount * BOX_SIZE); const length = Math.abs((props.amount ?? 1) * (BOX_SIZE - 20));
console.log("props", props.data);
return ( return (
<> <>
{props.data?.map((value) => value.values)}
<Box <Box
sx={{ sx={{
width: props.orientation === "horizontal" ? BOX_SIZE : length, width: props.orientation === "horizontal" ? BOX_SIZE - 20 : length,
height: props.orientation === "vertical" ? BOX_SIZE : length, height: props.orientation === "vertical" ? BOX_SIZE - 20 : length,
backgroundColor: "grey", backgroundColor: "#f4b3504d",
visibility: props.hidden || !props.data ? "hidden" : "visible", visibility: props.hidden || !props.data ? "hidden" : "visible",
}} }}
> >
{props.data?.map((value) => value.values)}
<div <div
className="container" className="container"
style={{ style={{
transform: props.orientation === "vertical" ? "rotate(90deg)" : "", transform:
props.orientation === "vertical"
? "rotate(90deg)"
: props.direction === "rightToLeft"
? "rotate(180deg)"
: "",
}} }}
> >
<div className="data-flow"> <div className="data-flow">

View File

@ -0,0 +1,122 @@
import { Box } from "@mui/material";
import TopologyColumn from "./TopologyColumn";
import { UnixTime } from "../../../dataCache/time";
import { extractTopologyValues, parseCsv } from "../../../util/graph.util";
import { testData } from "./ScalarGraph";
const TopologyView = () => {
const values = extractTopologyValues({
time: UnixTime.fromTicks(192384239),
value: parseCsv(testData),
});
console.log("csvValue", parseCsv(testData));
if (values) {
return (
<Box
sx={{
display: "flex",
flexDirection: "row",
overflow: "auto",
padding: 2,
}}
>
<div>
<TopologyColumn
centerBox={{
title: "Grid",
data: values.acInBus,
}}
centerConnection={{
amount: 0.5,
data: values.gridToAcIn,
direction: "rightToLeft",
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "AcInBus",
data: values.acInBus,
}}
centerConnection={{
amount: 0.5,
data: values.gridToAcIn,
direction: "leftToRight",
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "AcOutBus",
data: values.acOutBus,
}}
centerConnection={{
amount: 0.5,
data: values.gridToAcIn,
direction: "leftToRight",
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "Inverter",
data: values.acOutBus,
}}
centerConnection={{
amount: 0.5,
data: values.gridToAcIn,
direction: "leftToRight",
}}
/>
</div>
<div>
<TopologyColumn
topBox={{
title: "MPPT",
data: values.acOutBus,
}}
topConnection={{
amount: 0.5,
data: values.gridToAcIn,
}}
centerBox={{
title: "DcBus",
data: values.acOutBus,
}}
centerConnection={{
amount: 0.5,
data: values.gridToAcIn,
direction: "rightToLeft",
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "DcDc",
data: values.acOutBus,
}}
centerConnection={{
amount: 0.5,
data: values.gridToAcIn,
}}
/>
</div>
<div>
<TopologyColumn
centerBox={{
title: "Battery",
data: values.acOutBus,
}}
/>
</div>
</Box>
);
}
return null;
};
export default TopologyView;

View File

@ -1,21 +1,29 @@
import { Maybe } from "yup"; import { Maybe } from "yup";
import {Timestamped} from "./types"; import { Timestamped } from "./types";
import { isDefined } from "./utils/maybe"; import { isDefined } from "./utils/maybe";
export type DataRecord = Record<string, number | string> export type DataRecord = Record<string, number | string>;
export type DataPoint = Timestamped<Maybe<DataRecord>> export type DataPoint = Timestamped<Maybe<DataRecord>>;
export type RecordSeries = Array<DataPoint> export type RecordSeries = Array<DataPoint>;
export type PointSeries = Array<Timestamped<Maybe<number| string>>> export type PointSeries = Array<Timestamped<Maybe<number | string>>>;
export type DataSeries = Array<Maybe<number| string>> export type DataSeries = Array<Maybe<number | string>>;
export function getPoints(recordSeries: RecordSeries, series: keyof DataRecord): PointSeries export function getPoints(
{ recordSeries: RecordSeries,
return recordSeries.map(p => ({time: p.time, value: isDefined(p.value) ? p.value[series] : undefined})) series: keyof DataRecord
): PointSeries {
return recordSeries.map((p) => ({
time: p.time,
value: isDefined(p.value) ? p.value[series] : undefined,
}));
} }
export function getData(recordSeries: RecordSeries, series: keyof DataRecord): DataSeries export function getData(
{ recordSeries: RecordSeries,
return recordSeries.map(p => (isDefined(p.value) ? p.value[series] : undefined)) series: keyof DataRecord
): DataSeries {
return recordSeries.map((p) =>
isDefined(p.value) ? p.value[series] : undefined
);
} }

View File

@ -55,7 +55,7 @@ export const extractTopologyValues = (
const values = topologyValues[topologyKey].map( const values = topologyValues[topologyKey].map(
(topologyPath) => timeSeriesValue[topologyPath] (topologyPath) => timeSeriesValue[topologyPath]
); );
console.log("values", values); console.log("values", topologyValues);
return { return {
...acc, ...acc,
[topologyKey]: [ [topologyKey]: [
@ -64,7 +64,7 @@ export const extractTopologyValues = (
topologyKey === "gridToAcIn" topologyKey === "gridToAcIn"
? [values.reduce((acc, curr) => Number(acc) + Number(curr))] ? [values.reduce((acc, curr) => Number(acc) + Number(curr))]
: values, : values,
label: topologyKey.split("/").pop(), label: topologyValues[topologyKey][0].split("/").pop(),
unit: "V", unit: "V",
} as BoxData, } as BoxData,
], ],
@ -93,6 +93,14 @@ export const topologyValues: { [key: string]: string[] } = {
battery: ["/Battery/Soc", "/Battery/Dc/Voltage"], battery: ["/Battery/Soc", "/Battery/Dc/Voltage"],
}; };
export interface CsvEntry {
value: string | number;
unit: string;
}
export interface Csv {
[key: string]: CsvEntry;
}
export const parseCsv = (text: string) => { export const parseCsv = (text: string) => {
console.log("split", text.split(/\r?\n/)); console.log("split", text.split(/\r?\n/));
const y = text const y = text