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 navigate = useNavigate();
|
||||||
const inverter = (props.values as any)?.InverterRecord;
|
const inverter = (props.values as any)?.InverterRecord;
|
||||||
const batteryClusterNumber = props.installation.batteryClusterNumber;
|
const batteryClusterNumber = props.installation.batteryClusterNumber;
|
||||||
|
|
||||||
|
const hasDevices = !!inverter?.Devices;
|
||||||
|
|
||||||
const sortedBatteryView = inverter
|
const sortedBatteryView = inverter
|
||||||
? Array.from({ length: batteryClusterNumber }, (_, i) => {
|
? 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 {
|
return {
|
||||||
BatteryId: String(index),
|
BatteryId: String(i + 1),
|
||||||
battery: {
|
battery: {
|
||||||
Voltage: inverter[`Battery${index}Voltage`],
|
Voltage: device?.[`Battery${batteryIndex}PackTotalVoltage`] ?? 0,
|
||||||
Current: inverter[`Battery${index}Current`],
|
Current: device?.[`Battery${batteryIndex}PackTotalCurrent`] ?? 0,
|
||||||
Power: inverter[`Battery${index}Power`],
|
Power: device?.[`Battery${batteryIndex}Power`] ?? 0,
|
||||||
Soc: inverter[`Battery${index}Soc`],
|
Soc: device?.[`Battery${batteryIndex}Soc`] ?? device?.[`Battery${batteryIndex}SocSecondvalue`] ?? 0,
|
||||||
Soh: inverter[`Battery${index}Soh`],
|
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`] ?? 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: {
|
InverterRecord: {
|
||||||
GridPower:number;
|
// Top-level aggregated values
|
||||||
Battery1Power:number;
|
TotalPhotovoltaicPower: number;
|
||||||
Battery1Soc:number;
|
TotalBatteryPower: number;
|
||||||
Battery1Soh:number;
|
TotalLoadPower: number;
|
||||||
Battery1Voltage:number;
|
TotalGridPower: number;
|
||||||
Battery1Current:number;
|
AvgBatteryVoltage: number;
|
||||||
Battery2Power:number;
|
TotalBatteryCurrent: number;
|
||||||
Battery2Soc:number;
|
AvgBatterySoc: number;
|
||||||
Battery2Voltage:number;
|
AvgBatterySoh: number;
|
||||||
Battery2Current:number;
|
AvgBatteryTemp: number;
|
||||||
Battery2Soh:number;
|
OperatingPriority?: string;
|
||||||
PvPower:number;
|
MinSoc: number;
|
||||||
ConsumptionPower:number;
|
MaxChargeCurrent: number;
|
||||||
WorkingMode?:string;
|
MaxDischargingCurrent: number;
|
||||||
OperatingMode?:string;
|
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: {
|
AcDcGrowatt: {
|
||||||
|
|
|
||||||
|
|
@ -376,11 +376,10 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
||||||
fontSize: '14px'
|
fontSize: '14px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.current_installation.device === 4
|
{values.InverterRecord?.OperatingPriority
|
||||||
? values.InverterRecord?.WorkingMode
|
?? values.InverterRecord?.WorkingMode
|
||||||
: props.current_installation.device === 3
|
?? values.InverterRecord?.OperatingMode
|
||||||
? values.InverterRecord?.OperatingMode
|
?? values.Config?.OperatingPriority}
|
||||||
: values.Config.OperatingPriority}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -39,29 +39,31 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
||||||
|
|
||||||
const isMobile = window.innerWidth <= 1490;
|
const isMobile = window.innerWidth <= 1490;
|
||||||
|
|
||||||
const totalBatteryPower: number = Number(
|
const inv = props.values?.InverterRecord;
|
||||||
props.values && props.values.InverterRecord
|
const hasDevices = !!inv?.Devices;
|
||||||
? Array.from({ length: props.batteryClusterNumber }).reduce(
|
|
||||||
(sum: number, _, index) => {
|
|
||||||
const i = index + 1;
|
|
||||||
|
|
||||||
const rawPower =
|
const totalBatteryPower: number = hasDevices
|
||||||
props.values.InverterRecord[`Battery${i}Power`] as unknown;
|
? (inv?.TotalBatteryPower ?? 0)
|
||||||
|
: Number(
|
||||||
|
Array.from({ length: props.batteryClusterNumber }).reduce(
|
||||||
|
(sum: number, _, index) => sum + (Number(inv?.[`Battery${index + 1}Power`]) || 0),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const power = Number(rawPower) || 0;
|
const pvPower: number = hasDevices
|
||||||
|
? (inv?.TotalPhotovoltaicPower ?? 0)
|
||||||
|
: (inv?.PvPower ??
|
||||||
|
['PvPower1', 'PvPower2', 'PvPower3', 'PvPower4']
|
||||||
|
.map((key) => inv?.[key] ?? 0)
|
||||||
|
.reduce((sum, val) => sum + val, 0));
|
||||||
|
|
||||||
return sum + power;
|
const totalLoadPower: number = hasDevices
|
||||||
},
|
? (inv?.TotalLoadPower ?? 0)
|
||||||
0
|
: (inv?.ConsumptionPower ?? 0);
|
||||||
)
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
|
|
||||||
const pvPower =
|
const totalGridPower: number =
|
||||||
props.values?.InverterRecord?.PvPower ??
|
inv?.TotalGridPower ?? inv?.GridPower ?? 0;
|
||||||
['PvPower1', 'PvPower2', 'PvPower3', 'PvPower4']
|
|
||||||
.map((key) => props.values?.InverterRecord?.[key] ?? 0)
|
|
||||||
.reduce((sum, val) => sum + val, 0);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl" style={{ backgroundColor: 'white' }}>
|
<Container maxWidth="xl" style={{ backgroundColor: 'white' }}>
|
||||||
|
|
@ -142,7 +144,7 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
||||||
data: props.values?.InverterRecord
|
data: props.values?.InverterRecord
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
value: props.values.InverterRecord.GridPower,
|
value: totalGridPower,
|
||||||
unit: 'W'
|
unit: 'W'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -154,14 +156,14 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
||||||
orientation: 'horizontal',
|
orientation: 'horizontal',
|
||||||
data: props.values?.InverterRecord
|
data: props.values?.InverterRecord
|
||||||
? {
|
? {
|
||||||
value: props.values.InverterRecord.GridPower,
|
value: totalGridPower,
|
||||||
unit: 'W'
|
unit: 'W'
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
amount: props.values?.InverterRecord
|
amount: props.values?.InverterRecord
|
||||||
? getAmount(
|
? getAmount(
|
||||||
highestConnectionValue,
|
highestConnectionValue,
|
||||||
props.values.InverterRecord.GridPower
|
totalGridPower
|
||||||
)
|
)
|
||||||
: 0,
|
: 0,
|
||||||
showValues: showValues
|
showValues: showValues
|
||||||
|
|
@ -225,7 +227,7 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
||||||
data: props.values?.InverterRecord
|
data: props.values?.InverterRecord
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
value: props.values.InverterRecord.ConsumptionPower,
|
value: totalLoadPower,
|
||||||
unit: 'W'
|
unit: 'W'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -237,14 +239,14 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
||||||
position: 'bottom',
|
position: 'bottom',
|
||||||
data: props.values?.InverterRecord
|
data: props.values?.InverterRecord
|
||||||
? {
|
? {
|
||||||
value: props.values.InverterRecord.ConsumptionPower,
|
value: totalLoadPower,
|
||||||
unit: 'W'
|
unit: 'W'
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
amount: props.values?.InverterRecord
|
amount: props.values?.InverterRecord
|
||||||
? getAmount(
|
? getAmount(
|
||||||
highestConnectionValue,
|
highestConnectionValue,
|
||||||
props.values.InverterRecord.ConsumptionPower
|
totalLoadPower
|
||||||
)
|
)
|
||||||
: 0,
|
: 0,
|
||||||
showValues: showValues
|
showValues: showValues
|
||||||
|
|
@ -254,23 +256,32 @@ function TopologySodistoreHome(props: TopologySodistoreHomeProps) {
|
||||||
/>
|
/>
|
||||||
{/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/}
|
{/*-------------------------------------------------------------------------------------------------------------------------------------------------------------*/}
|
||||||
{Array.from({ length: props.batteryClusterNumber }).map((_, index) => {
|
{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 (
|
return (
|
||||||
<TopologyColumn
|
<TopologyColumn
|
||||||
key={i}
|
key={index + 1}
|
||||||
centerBox={{
|
centerBox={{
|
||||||
title: `Battery C${i}`,
|
title: `Battery C${index + 1}`,
|
||||||
data: props.values.InverterRecord
|
data: inv
|
||||||
? [
|
? [
|
||||||
{
|
{ value: soc, unit: '%' },
|
||||||
value: props.values.InverterRecord[`Battery${i}Soc`],
|
{ value: power, unit: 'W' }
|
||||||
unit: '%'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: props.values.InverterRecord[`Battery${i}Power`],
|
|
||||||
unit: 'W'
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
: undefined,
|
: undefined,
|
||||||
connected: true
|
connected: true
|
||||||
|
|
|
||||||
|
|
@ -516,36 +516,27 @@ export const transformInputToDailyDataJson = async (
|
||||||
let value: number | undefined = undefined;
|
let value: number | undefined = undefined;
|
||||||
|
|
||||||
if (product === 2) {
|
if (product === 2) {
|
||||||
// SodioHome: custom extraction with fallbacks for Growatt/Sinexcel
|
// SodioHome: use top-level aggregated values (Sinexcel multi-inverter)
|
||||||
const inv = result?.InverterRecord;
|
const inv = result?.InverterRecord;
|
||||||
if (inv) {
|
if (inv) {
|
||||||
switch (category_index) {
|
switch (category_index) {
|
||||||
case 0: // soc
|
case 0: // soc
|
||||||
value = inv.Battery1Soc;
|
value = inv.AvgBatterySoc ?? inv.Battery1Soc;
|
||||||
break;
|
break;
|
||||||
case 1: // temperature
|
case 1: // temperature
|
||||||
// Growatt: Battery1AmbientTemperature, Sinexcel: Battery1Temperature
|
value = inv.AvgBatteryTemp ?? inv.Battery1AmbientTemperature ?? inv.Battery1Temperature;
|
||||||
value = inv.Battery1AmbientTemperature ?? inv.Battery1Temperature;
|
|
||||||
break;
|
break;
|
||||||
case 2: // battery power
|
case 2: // battery power
|
||||||
value = inv.Battery1Power;
|
value = inv.TotalBatteryPower ?? inv.Battery1Power;
|
||||||
break;
|
break;
|
||||||
case 3: // grid power
|
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;
|
value = inv.TotalGridPower ?? inv.GridPower;
|
||||||
break;
|
break;
|
||||||
case 4: // pv production
|
case 4: // pv production
|
||||||
// Growatt: PvPower (aggregated), Sinexcel: PvTotalPower or sum PvPower1-4
|
value = inv.TotalPhotovoltaicPower ?? inv.PvPower ?? inv.PvTotalPower;
|
||||||
value =
|
|
||||||
inv.PvPower ??
|
|
||||||
inv.PvTotalPower ??
|
|
||||||
['PvPower1', 'PvPower2', 'PvPower3', 'PvPower4']
|
|
||||||
.map((key) => inv[key] ?? 0)
|
|
||||||
.reduce((sum, val) => sum + val, 0);
|
|
||||||
break;
|
break;
|
||||||
case 6: // consumption
|
case 6: // consumption
|
||||||
value = inv.ConsumptionPower;
|
value = inv.TotalLoadPower ?? inv.ConsumptionPower;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue