updated multi-inverter sinexcel data path
This commit is contained in:
parent
401d82ea7a
commit
c102ab3335
|
|
@ -38,20 +38,41 @@ function BatteryViewSodioHome(props: BatteryViewSodioHomeProps) {
|
|||
const navigate = useNavigate();
|
||||
const inverter = (props.values as any)?.InverterRecord;
|
||||
const batteryClusterNumber = props.installation.batteryClusterNumber;
|
||||
|
||||
const hasDevices = !!inverter?.Devices;
|
||||
|
||||
const sortedBatteryView = inverter
|
||||
? Array.from({ length: batteryClusterNumber }, (_, i) => {
|
||||
const index = i + 1; // Battery1, Battery2, ...
|
||||
if (hasDevices) {
|
||||
// Sinexcel: map across devices — 0→D1/B1, 1→D1/B2, 2→D2/B1, 3→D2/B2
|
||||
const deviceId = String(Math.floor(i / 2) + 1);
|
||||
const batteryIndex = (i % 2) + 1;
|
||||
const device = inverter.Devices[deviceId];
|
||||
|
||||
return {
|
||||
BatteryId: String(i + 1),
|
||||
battery: {
|
||||
Voltage: device?.[`Battery${batteryIndex}PackTotalVoltage`] ?? 0,
|
||||
Current: device?.[`Battery${batteryIndex}PackTotalCurrent`] ?? 0,
|
||||
Power: device?.[`Battery${batteryIndex}Power`] ?? 0,
|
||||
Soc: device?.[`Battery${batteryIndex}Soc`] ?? device?.[`Battery${batteryIndex}SocSecondvalue`] ?? 0,
|
||||
Soh: device?.[`Battery${batteryIndex}Soh`] ?? 0,
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// Growatt: flat Battery1, Battery2, ...
|
||||
const index = i + 1;
|
||||
return {
|
||||
BatteryId: String(index),
|
||||
battery: {
|
||||
Voltage: inverter[`Battery${index}Voltage`],
|
||||
Current: inverter[`Battery${index}Current`],
|
||||
Power: inverter[`Battery${index}Power`],
|
||||
Soc: inverter[`Battery${index}Soc`],
|
||||
Soh: inverter[`Battery${index}Soh`],
|
||||
Voltage: inverter[`Battery${index}Voltage`] ?? 0,
|
||||
Current: inverter[`Battery${index}Current`] ?? 0,
|
||||
Power: inverter[`Battery${index}Power`] ?? 0,
|
||||
Soc: inverter[`Battery${index}Soc`] ?? 0,
|
||||
Soh: inverter[`Battery${index}Soh`] ?? 0,
|
||||
}
|
||||
};
|
||||
}
|
||||
})
|
||||
: [];
|
||||
|
||||
|
|
|
|||
|
|
@ -437,23 +437,76 @@ export interface JSONRecordData {
|
|||
};
|
||||
};
|
||||
|
||||
// For SodistoreHome
|
||||
// For SodistoreHome (Sinexcel multi-inverter structure)
|
||||
InverterRecord: {
|
||||
// Top-level aggregated values
|
||||
TotalPhotovoltaicPower: number;
|
||||
TotalBatteryPower: number;
|
||||
TotalLoadPower: number;
|
||||
TotalGridPower: number;
|
||||
AvgBatteryVoltage: number;
|
||||
TotalBatteryCurrent: number;
|
||||
AvgBatterySoc: number;
|
||||
AvgBatterySoh: number;
|
||||
AvgBatteryTemp: number;
|
||||
OperatingPriority?: string;
|
||||
MinSoc: number;
|
||||
MaxChargeCurrent: number;
|
||||
MaxDischargingCurrent: number;
|
||||
GridPower: number;
|
||||
GridFrequency: number;
|
||||
InverterPower: number;
|
||||
EnableGridExport?: string;
|
||||
GridExportPower: number;
|
||||
// Legacy flat fields (Growatt compatibility)
|
||||
Battery1Power?: number;
|
||||
Battery1Soc?: number;
|
||||
Battery1Soh?: number;
|
||||
Battery1Voltage?: number;
|
||||
Battery1Current?: number;
|
||||
Battery2Power?: number;
|
||||
Battery2Soc?: number;
|
||||
Battery2Voltage?: number;
|
||||
Battery2Current?: number;
|
||||
Battery2Soh?: number;
|
||||
PvPower?: number;
|
||||
ConsumptionPower?: number;
|
||||
WorkingMode?: string;
|
||||
OperatingMode?: string;
|
||||
PvTotalPower?: number;
|
||||
Battery1AmbientTemperature?: number;
|
||||
Battery1Temperature?: number;
|
||||
// Per-device records (Sinexcel multi-inverter)
|
||||
Devices?: {
|
||||
[deviceId: string]: {
|
||||
Battery1Power: number;
|
||||
Battery1Soc: number;
|
||||
Battery1Soh: number;
|
||||
Battery1Voltage: number;
|
||||
Battery1Current: number;
|
||||
Battery1PackTotalVoltage: number;
|
||||
Battery1PackTotalCurrent: number;
|
||||
Battery1Temperature: number;
|
||||
Battery1SocSecondvalue: number;
|
||||
Battery2Power: number;
|
||||
Battery2Soc: number;
|
||||
Battery2Soh: number;
|
||||
Battery2Voltage: number;
|
||||
Battery2Current: number;
|
||||
Battery2Soh:number;
|
||||
PvPower:number;
|
||||
Battery2PackTotalVoltage: number;
|
||||
Battery2PackTotalCurrent: number;
|
||||
Battery2Temperature: number;
|
||||
Battery2Socsecondvalue: number;
|
||||
ConsumptionPower: number;
|
||||
WorkingMode?:string;
|
||||
OperatingMode?:string;
|
||||
TotalPhotovoltaicPower: number;
|
||||
TotalBatteryPower: number;
|
||||
TotalLoadPower: number;
|
||||
TotalGridPower: number;
|
||||
GridPower: number;
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
AcDcGrowatt: {
|
||||
|
|
|
|||
|
|
@ -376,11 +376,10 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
|||
fontSize: '14px'
|
||||
}}
|
||||
>
|
||||
{props.current_installation.device === 4
|
||||
? values.InverterRecord?.WorkingMode
|
||||
: props.current_installation.device === 3
|
||||
? values.InverterRecord?.OperatingMode
|
||||
: values.Config.OperatingPriority}
|
||||
{values.InverterRecord?.OperatingPriority
|
||||
?? values.InverterRecord?.WorkingMode
|
||||
?? values.InverterRecord?.OperatingMode
|
||||
?? values.Config?.OperatingPriority}
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -39,29 +39,31 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
|||
|
||||
const isMobile = window.innerWidth <= 1490;
|
||||
|
||||
const totalBatteryPower: number = Number(
|
||||
props.values && props.values.InverterRecord
|
||||
? Array.from({ length: props.batteryClusterNumber }).reduce(
|
||||
(sum: number, _, index) => {
|
||||
const i = index + 1;
|
||||
const inv = props.values?.InverterRecord;
|
||||
const hasDevices = !!inv?.Devices;
|
||||
|
||||
const rawPower =
|
||||
props.values.InverterRecord[`Battery${i}Power`] as unknown;
|
||||
|
||||
const power = Number(rawPower) || 0;
|
||||
|
||||
return sum + power;
|
||||
},
|
||||
const totalBatteryPower: number = hasDevices
|
||||
? (inv?.TotalBatteryPower ?? 0)
|
||||
: Number(
|
||||
Array.from({ length: props.batteryClusterNumber }).reduce(
|
||||
(sum: number, _, index) => sum + (Number(inv?.[`Battery${index + 1}Power`]) || 0),
|
||||
0
|
||||
)
|
||||
: 0
|
||||
);
|
||||
|
||||
const pvPower =
|
||||
props.values?.InverterRecord?.PvPower ??
|
||||
const pvPower: number = hasDevices
|
||||
? (inv?.TotalPhotovoltaicPower ?? 0)
|
||||
: (inv?.PvPower ??
|
||||
['PvPower1', 'PvPower2', 'PvPower3', 'PvPower4']
|
||||
.map((key) => props.values?.InverterRecord?.[key] ?? 0)
|
||||
.reduce((sum, val) => sum + val, 0);
|
||||
.map((key) => inv?.[key] ?? 0)
|
||||
.reduce((sum, val) => sum + val, 0));
|
||||
|
||||
const totalLoadPower: number = hasDevices
|
||||
? (inv?.TotalLoadPower ?? 0)
|
||||
: (inv?.ConsumptionPower ?? 0);
|
||||
|
||||
const totalGridPower: number =
|
||||
inv?.TotalGridPower ?? inv?.GridPower ?? 0;
|
||||
|
||||
return (
|
||||
<Container maxWidth="xl" style={{ backgroundColor: 'white' }}>
|
||||
|
|
@ -142,7 +144,7 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
|||
data: props.values?.InverterRecord
|
||||
? [
|
||||
{
|
||||
value: props.values.InverterRecord.GridPower,
|
||||
value: totalGridPower,
|
||||
unit: 'W'
|
||||
}
|
||||
]
|
||||
|
|
@ -154,14 +156,14 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
|||
orientation: 'horizontal',
|
||||
data: props.values?.InverterRecord
|
||||
? {
|
||||
value: props.values.InverterRecord.GridPower,
|
||||
value: totalGridPower,
|
||||
unit: 'W'
|
||||
}
|
||||
: undefined,
|
||||
amount: props.values?.InverterRecord
|
||||
? getAmount(
|
||||
highestConnectionValue,
|
||||
props.values.InverterRecord.GridPower
|
||||
totalGridPower
|
||||
)
|
||||
: 0,
|
||||
showValues: showValues
|
||||
|
|
@ -225,7 +227,7 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
|||
data: props.values?.InverterRecord
|
||||
? [
|
||||
{
|
||||
value: props.values.InverterRecord.ConsumptionPower,
|
||||
value: totalLoadPower,
|
||||
unit: 'W'
|
||||
}
|
||||
]
|
||||
|
|
@ -237,14 +239,14 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
|||
position: 'bottom',
|
||||
data: props.values?.InverterRecord
|
||||
? {
|
||||
value: props.values.InverterRecord.ConsumptionPower,
|
||||
value: totalLoadPower,
|
||||
unit: 'W'
|
||||
}
|
||||
: undefined,
|
||||
amount: props.values?.InverterRecord
|
||||
? getAmount(
|
||||
highestConnectionValue,
|
||||
props.values.InverterRecord.ConsumptionPower
|
||||
totalLoadPower
|
||||
)
|
||||
: 0,
|
||||
showValues: showValues
|
||||
|
|
@ -254,23 +256,32 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
|||
/>
|
||||
{/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/}
|
||||
{Array.from({ length: props.batteryClusterNumber }).map((_, index) => {
|
||||
const i = index + 1; // battery cluster index starting from 1
|
||||
let soc: number;
|
||||
let power: number;
|
||||
|
||||
if (hasDevices) {
|
||||
// Sinexcel: map across devices — 0→D1/B1, 1→D1/B2, 2→D2/B1, 3→D2/B2
|
||||
const deviceId = String(Math.floor(index / 2) + 1);
|
||||
const batteryIndex = (index % 2) + 1;
|
||||
const device = inv?.Devices?.[deviceId];
|
||||
soc = device?.[`Battery${batteryIndex}Soc`] ?? device?.[`Battery${batteryIndex}SocSecondvalue`] ?? 0;
|
||||
power = device?.[`Battery${batteryIndex}Power`] ?? 0;
|
||||
} else {
|
||||
// Growatt: flat Battery1, Battery2, ...
|
||||
const i = index + 1;
|
||||
soc = Number(inv?.[`Battery${i}Soc`]) || 0;
|
||||
power = Number(inv?.[`Battery${i}Power`]) || 0;
|
||||
}
|
||||
|
||||
return (
|
||||
<TopologyColumn
|
||||
key={i}
|
||||
key={index + 1}
|
||||
centerBox={{
|
||||
title: `Battery C${i}`,
|
||||
data: props.values.InverterRecord
|
||||
title: `Battery C${index + 1}`,
|
||||
data: inv
|
||||
? [
|
||||
{
|
||||
value: props.values.InverterRecord[`Battery${i}Soc`],
|
||||
unit: '%'
|
||||
},
|
||||
{
|
||||
value: props.values.InverterRecord[`Battery${i}Power`],
|
||||
unit: 'W'
|
||||
}
|
||||
{ value: soc, unit: '%' },
|
||||
{ value: power, unit: 'W' }
|
||||
]
|
||||
: undefined,
|
||||
connected: true
|
||||
|
|
|
|||
|
|
@ -516,36 +516,27 @@ export const transformInputToDailyDataJson = async (
|
|||
let value: number | undefined = undefined;
|
||||
|
||||
if (product === 2) {
|
||||
// SodioHome: custom extraction with fallbacks for Growatt/Sinexcel
|
||||
// SodioHome: use top-level aggregated values (Sinexcel multi-inverter)
|
||||
const inv = result?.InverterRecord;
|
||||
if (inv) {
|
||||
switch (category_index) {
|
||||
case 0: // soc
|
||||
value = inv.Battery1Soc;
|
||||
value = inv.AvgBatterySoc ?? inv.Battery1Soc;
|
||||
break;
|
||||
case 1: // temperature
|
||||
// Growatt: Battery1AmbientTemperature, Sinexcel: Battery1Temperature
|
||||
value = inv.Battery1AmbientTemperature ?? inv.Battery1Temperature;
|
||||
value = inv.AvgBatteryTemp ?? inv.Battery1AmbientTemperature ?? inv.Battery1Temperature;
|
||||
break;
|
||||
case 2: // battery power
|
||||
value = inv.Battery1Power;
|
||||
value = inv.TotalBatteryPower ?? inv.Battery1Power;
|
||||
break;
|
||||
case 3: // grid power
|
||||
// Growatt: GridPower (always valid), Sinexcel: GridPower may be 0 when
|
||||
// electric meter is offline, TotalGridPower is the reliable fallback
|
||||
value = inv.TotalGridPower ?? inv.GridPower;
|
||||
break;
|
||||
case 4: // pv production
|
||||
// Growatt: PvPower (aggregated), Sinexcel: PvTotalPower or sum PvPower1-4
|
||||
value =
|
||||
inv.PvPower ??
|
||||
inv.PvTotalPower ??
|
||||
['PvPower1', 'PvPower2', 'PvPower3', 'PvPower4']
|
||||
.map((key) => inv[key] ?? 0)
|
||||
.reduce((sum, val) => sum + val, 0);
|
||||
value = inv.TotalPhotovoltaicPower ?? inv.PvPower ?? inv.PvTotalPower;
|
||||
break;
|
||||
case 6: // consumption
|
||||
value = inv.ConsumptionPower;
|
||||
value = inv.TotalLoadPower ?? inv.ConsumptionPower;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue