updated multi-inverter sinexcel data path

This commit is contained in:
Yinyin Liu 2026-03-09 12:27:02 +01:00
parent 401d82ea7a
commit c102ab3335
5 changed files with 159 additions and 84 deletions

View File

@ -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,
}
};
}
})
: [];

View File

@ -437,23 +437,76 @@ export interface JSONRecordData {
};
};
// For SodistoreHome
// For SodistoreHome (Sinexcel multi-inverter structure)
InverterRecord: {
GridPower:number;
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;
// 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;
Battery2PackTotalVoltage: number;
Battery2PackTotalCurrent: number;
Battery2Temperature: number;
Battery2Socsecondvalue: number;
ConsumptionPower: number;
TotalPhotovoltaicPower: number;
TotalBatteryPower: number;
TotalLoadPower: number;
TotalGridPower: number;
GridPower: number;
[key: string]: any;
};
};
[key: string]: any;
};
AcDcGrowatt: {

View File

@ -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>
)}

View File

@ -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

View File

@ -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;
}
}