diff --git a/README.md b/README.md
index d14d971..56d3999 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ to the device's internal Wifi access point. For information about how to connect
## Requirements
- Python >= 3.9
+- pymodbus >= 3.11.0
## Disclaimer
@@ -47,7 +48,7 @@ During instantiation of a Sun2000 object the following parameters are accepted:
| port | Port, usually 502, changed to 6607 on newer firmware versions. |
| timeout | Connection timeout |
| wait | Time to wait after connection before a register read can be performed. Increases stability. |
-| slave | Number of inverter unit to be read by default, used in cascading scenarios. Defaults to 0, but some devices need it to be set to other values. |
+| device_id | Number of inverter unit to be read by default, used in cascading scenarios. Defaults to 0, but some devices need it to be set to other values. |
### Read metrics
@@ -70,30 +71,27 @@ Looking at the [above example](#usage) the different methods would return the fo
Furthermore, a method `read_range` exists accepting the address of the register to start reading and either a quantity of registers or the address of the last
register to be read. The result is returned as byte-string for further processing.
-Each `read*` method accepts a `slave` argument which is used in cascading scenarios to address the desired inverter unit.
+Each `read*` method accepts a `device_id` argument which is used in cascading scenarios to address the desired inverter unit.
### Write settings
For writing a register the `write` method can be used, taking the register address and the value as arguments.
-Furthermore, the `write` method accepts a `slave` argument which is used in cascading scenarios to address the desired inverter unit.
+Furthermore, the `write` method accepts a `device_id` argument which is used in cascading scenarios to address the desired inverter unit.
## Registers
-The following registers are provided by the Sun2000's Modbus interface and can be read accordingly. Documentation can be found
-[here](https://javierin.com/wp-content/uploads/sites/2/2021/09/Solar-Inverter-Modbus-Interface-Definitions.pdf).
+The following registers are provided by the Sun2000's Modbus interface and can be read and written accordingly. Documentation can be found
+[here](https://support.huawei.com/enterprise/en/doc/EDOC1100480291?idPath=258788305|254827209|258792409|22755755§ion=k003).
### InverterEquipmentRegister
| Name | Type | Gain | Unit | Access Type |
-|-----------------------------------------|------------------------|------|------|-------------|
+|:----------------------------------------|:-----------------------|:-----|:-----|:------------|
| Model | String | | | RO |
| SN | String | | | RO |
| PN | String | | | RO |
-| FirmwareVerion | String | | | RO |
-| SoftwareVerion | String | | | RO |
-| ProtocolVerion | String | | | RO |
-| ModelID | Number | 1 | | RO |
+| ModelID | Number | | | RO |
| NumberOfPVStrings | Number | 1 | | RO |
| NumberOfMPPTrackers | Number | 1 | | RO |
| RatedPower | Number | 1 | W | RO |
@@ -101,12 +99,24 @@ The following registers are provided by the Sun2000's Modbus interface and can b
| MaximumApparentPower | Number | 1000 | kVA | RO |
| MaximumReactivePowerFedToTheGrid | Number | 1000 | kvar | RO |
| MaximumReactivePowerAbsorbedFromTheGrid | Number | 1000 | kvar | RO |
+| OfferingNameOfSouthboundDevice1 | String | | | RO |
+| OfferingNameOfSouthboundDevice2 | String | | | RO |
+| OfferingNameOfSouthboundDevice3 | String | | | RO |
+| HardwareVersion | String | | | RO |
+| MonitoringBoardSN | String | | | RO |
+| MonitoringSoftwareVersion | String | | | RO |
+| MasterDSPVersion | String | | | RO |
+| CPLDVersion | String | | | RO |
+| AFCIVersion | String | | | RO |
+| DCMBUSVersion | String | | | RO |
+| REGKEY | String | | | RO |
| State1 | Binary String/Bitfield | | | RO |
| State2 | Binary String/Bitfield | | | RO |
| State3 | Binary String/Bitfield | | | RO |
| Alarm1 | Binary String/Bitfield | | | RO |
| Alarm2 | Binary String/Bitfield | | | RO |
| Alarm3 | Binary String/Bitfield | | | RO |
+| ESN | Number | | | RO |
| PV1Voltage | Number | 10 | V | RO |
| PV1Current | Number | 100 | A | RO |
| PV2Voltage | Number | 10 | V | RO |
@@ -173,24 +183,37 @@ The following registers are provided by the Sun2000's Modbus interface and can b
| Efficiency | Number | 100 | % | RO |
| InternalTemperature | Number | 10 | °C | RO |
| InsulationResistance | Number | 1000 | MOhm | RO |
-| DeviceStatus | Number | 1 | | RO |
-| FaultCode | Number | 1 | | RO |
-| StartupTime | Number | 1 | | RO |
-| ShutdownTime | Number | 1 | | RO |
+| DeviceStatus | Number | | | RO |
+| FaultCode | Number | | | RO |
+| StartupTime | Number | 1 | s | RO |
+| ShutdownTime | Number | 1 | s | RO |
| AccumulatedEnergyYield | Number | 100 | kWh | RO |
| DailyEnergyYield | Number | 100 | kWh | RO |
-| ActiveAdjustmentMode | Number | 1 | | RO |
-| ActiveAdjustmentValue | Number | 1 | | RO |
-| ActiveAdjustmentCommand | Number | 1 | | RO |
-| ReactiveAdjustmentMode | Number | 1 | | RO |
-| ReactiveAdjustmentValue | Number | 1 | | RO |
-| ReactiveAdjustmentCommand | Number | 1 | | RO |
+| ManagementSystemStatus | Number | 1 | | RO |
+| AuthorizationFunction | Binary String/Bitfield | | | RO |
+| LicenseStatus | Number | | | RO |
+| LicenseExpirationTime | Number | 1 | s | RO |
+| LicenseLoadingTime | Number | 1 | s | RO |
+| LicenseRevocationTime | Number | 1 | s | RO |
+| LicenseSN | String | | | RO |
+| RevocationCode | String | | | RO |
+| ModuleStatus4G | Number | | | RO |
+| IPAddress4G | Number | 1 | | RO |
+| SubnetMask4G | Number | 1 | | RO |
+| IMEI4G | String | | | RO |
+| SignalStrength4G | Number | 1 | | RO |
+| MaximumNumberOfPINAttempts4G | Number | 1 | | RO |
+| PINVerificationStatus4G | Number | | | RO |
+| OriginalModelName | Bytestring | | | RO |
+| ActiveAdjustmentMode | Bytestring | | | RO |
+| ReactiveAdjustmentMode | Bytestring | | | RO |
+| ChargeDischargeMode | Number | | | RO |
| PowerMeterCollectionActivePower | Number | 1 | W | RO |
| TotalNumberOfOptimizers | Number | 1 | | RO |
| NumberOfOnlineOptimizers | Number | 1 | | RO |
| FeatureData | Number | 1 | | RO |
-| SystemTime | Number | 1 | | RW |
-| QUCharacteristicCurveMode | Number | 1 | | RW |
+| SystemTime | Number | 1 | s | RW |
+| QUCharacteristicCurveMode | Number | | | RW |
| QUDispatchTriggerPower | Number | 1 | % | RW |
| FixedActivePowerDeratedInKW | Number | 10 | kW | RW |
| ReactivePowerCompensationInPF | Number | 1000 | | RW |
@@ -203,186 +226,214 @@ The following registers are provided by the Sun2000's Modbus interface and can b
| PFUCharacteristicCurve | Bytestring | | | RW |
| ReactivePowerAdjustmentTime | Number | 1 | s | RW |
| QUPowerPercentageToExitScheduling | Number | 1 | % | RW |
-| Startup | Number | 1 | | WO |
-| Shutdown | Number | 1 | | WO |
-| GridCode | Number | 1 | | RW |
+| Startup | Number | | | WO |
+| Shutdown | Number | | | WO |
+| GridCode | Number | | | RW |
| ReactivePowerChangeGradient | Number | 1000 | %/s | RW |
| ActivePowerChangeGradient | Number | 1000 | %/s | RW |
| ScheduleInstructionValidDuration | Number | 1 | s | RW |
+| ActivePowerLimit | Number | 1 | W | RW |
| TimeZone | Number | 1 | min | RW |
+| TLSEncryption | Number | | | RW |
+| WLANWakeup | Number | | | RW |
+| FastPowerScheduling | Number | | | RW |
+| BatteryChargingMode | Number | | | RW |
+| BatteryChargeAndDischargePower | Number | 1 | W | RW |
+| RemoteChargeDischargeControlMode | Number | | | RW |
+| ScheduledTask | Number | | | RW |
+| DefaultMaximumFeedInPower | Number | 1 | W | RW |
+| DefaultActivePowerChangeGradient | Number | 1000 | %/s | RW |
+| PeakShaving | Number | | | RW |
+| BackupPowerSOCForPeakShaving | Number | 10 | % | RW |
+| PeakPower | Bytestring | | | RW |
+| AIOpticalStorage | Number | | | RW |
+| BackupBoxModel | Number | | | RW |
+| PhaseToGroundCircuitProtection | Number | | | RW |
### BatteryEquipmentRegister
-| Name | Type | Gain | Unit | Access Type |
-|----------------------------------------|------------|------|---------|-------------|
-| RunningStatus | Number | 1 | | RO |
-| WorkingModeSettings | Number | 1 | | RW |
-| BusVoltage | Number | 10 | V | RO |
-| BusCurrent | Number | 10 | A | RO |
-| ChargeDischargePower | Number | 1 | W | RO |
-| MaximumChargePower | Number | 1 | W | RO |
-| MaximumDischargePower | Number | 1 | W | RO |
-| RatedCapacity | Number | 1 | Wh | RO |
-| SOC | Number | 10 | % | RO |
-| BackupPowerSOC | Number | 10 | % | RW |
-| TotalCharge | Number | 100 | kWh | RO |
-| TotalDischarge | Number | 100 | kWh | RO |
-| CurrentDayChargeCapacity | Number | 100 | kWh | RO |
-| CurrentDayDischargeCapacity | Number | 100 | kWh | RO |
-| TimeOfUseElectricityPricePeriods | Bytestring | | | RW |
-| MaximumChargingPower | Number | 1 | W | RW |
-| MaximumDischargingPower | Number | 1 | W | RW |
-| ChargingCutoffCapacity | Number | 10 | % | RW |
-| DischargeCutoffCapacity | Number | 10 | % | RW |
-| ForcedChargingAndDischargingPeriod | Number | 1 | minutes | RW |
-| ChargeFromGridFunction | Number | 1 | | RW |
-| GridChargeCutoffSOC | Number | 10 | % | RW |
-| ForcibleChargeDischarge | Number | 1 | | WO |
-| FixedChargingAndDischargingPeriods | Bytestring | | | RW |
-| PowerOfChargeFromGrid | Number | 0.1 | W | RW |
-| MaximumPowerOfChargeFromGrid | Number | 0.1 | W | RW |
-| ForcibleChargeDischargeSettingMode | Number | 1 | | RW |
-| ForcibleChargePower | Number | 0.1 | W | RW |
-| ForcibleDischargePower | Number | 0.1 | W | RW |
-| TimeOfUseChargingAndDischargingPeriods | Bytestring | | | RW |
-| ExcessPVEnergyUseInTOU | Number | 1 | | RW |
-| ActivePowerControlMode | Number | 1 | | RW |
-| MaximumFeedGridPowerInKW | Number | 1000 | kW | RW |
-| MaximumFeedGridPowerInPercentage | Number | 10 | % | RW |
-| MaximumChargeFromGridPower | Number | 0.1 | W | RW |
-| SwitchToOffGrid | Number | 1 | | RW |
-| VoltageInIndependentOperation | Number | 1 | | RW |
-| Unit1ProductModel | Number | 1 | | RW |
-| Unit1SN | String | | | RO |
-| Unit1No | Number | 1 | | RW |
-| Unit1SoftwareVersion | String | | | RO |
-| Unit1DCDCVersion | String | | | RO |
-| Unit1BMSVersion | String | | | RO |
-| Unit1RunningStatus | Number | 1 | | RO |
-| Unit1WorkingMode | Number | 1 | | RO |
-| Unit1BusVoltage | Number | 10 | V | RO |
-| Unit1BusCurrent | Number | 10 | A | RO |
-| Unit1BatterySOC | Number | 10 | % | RO |
-| Unit1ChargeAndDischargePower | Number | 1 | W | RO |
-| Unit1RemainingChargeDischargeTime | Number | 1 | minutes | RO |
-| Unit1RatedChargePower | Number | 1 | W | RO |
-| Unit1RatedDischargePower | Number | 1 | W | RO |
-| Unit1CurrentDayChargeCapacity | Number | 100 | kWh | RO |
-| Unit1CurrentDayDischargeCapacity | Number | 100 | kWh | RO |
-| Unit1TotalCharge | Number | 100 | kWh | RO |
-| Unit1TotalDischarge | Number | 100 | kWh | RO |
-| Unit1BatteryTemperature | Number | 10 | °C | RO |
-| Unit1FaultID | Number | 1 | | RO |
-| Unit2ProductModel | Number | 1 | | RW |
-| Unit2SN | String | | | RO |
-| Unit2No | Number | 1 | | RW |
-| Unit2SoftwareVersion | String | | | RO |
-| Unit2RunningStatus | Number | 1 | | RO |
-| Unit2BusVoltage | Number | 10 | V | RO |
-| Unit2BusCurrent | Number | 10 | A | RO |
-| Unit2BatterySOC | Number | 10 | % | RO |
-| Unit2ChargeAndDischargePower | Number | 1 | W | RO |
-| Unit2CurrentDayChargeCapacity | Number | 100 | kWh | RO |
-| Unit2CurrentDayDischargeCapacity | Number | 100 | kWh | RO |
-| Unit2TotalCharge | Number | 100 | kWh | RO |
-| Unit2TotalDischarge | Number | 100 | kWh | RO |
-| Unit2BatteryTemperature | Number | 10 | °C | RO |
-| Unit1BatteryPack1SN | String | | | RO |
-| Unit1BatteryPack1No | Number | 1 | | RW |
-| Unit1BatteryPack1FirmwareVersion | String | | | RO |
-| Unit1BatteryPack1WorkingStatus | Number | 1 | | RO |
-| Unit1BatteryPack1Voltage | Number | 10 | V | RO |
-| Unit1BatteryPack1Current | Number | 10 | A | RO |
-| Unit1BatteryPack1SOC | Number | 10 | % | RO |
-| Unit1BatteryPack1ChargeDischargePower | Number | 1 | W | RO |
-| Unit1BatteryPack1TotalCharge | Number | 100 | kWh | RO |
-| Unit1BatteryPack1TotalDischarge | Number | 100 | kWh | RO |
-| Unit1BatteryPack1MinimumTemperature | Number | 10 | °C | RO |
-| Unit1BatteryPack1MaximumTemperature | Number | 10 | °C | RO |
-| Unit1BatteryPack2SN | String | | | RO |
-| Unit1BatteryPack2No | Number | 1 | | RW |
-| Unit1BatteryPack2FirmwareVersion | String | | | RO |
-| Unit1BatteryPack2WorkingStatus | Number | 1 | | RO |
-| Unit1BatteryPack2Voltage | Number | 10 | V | RO |
-| Unit1BatteryPack2Current | Number | 10 | A | RO |
-| Unit1BatteryPack2SOC | Number | 10 | % | RO |
-| Unit1BatteryPack2ChargeDischargePower | Number | 1 | W | RO |
-| Unit1BatteryPack2TotalCharge | Number | 100 | kWh | RO |
-| Unit1BatteryPack2TotalDischarge | Number | 100 | kWh | RO |
-| Unit1BatteryPack2MinimumTemperature | Number | 10 | °C | RO |
-| Unit1BatteryPack2MaximumTemperature | Number | 10 | °C | RO |
-| Unit1BatteryPack3SN | String | | | RO |
-| Unit1BatteryPack3No | Number | 1 | | RW |
-| Unit1BatteryPack3FirmwareVersion | String | | | RO |
-| Unit1BatteryPack3WorkingStatus | Number | 1 | | RO |
-| Unit1BatteryPack3Voltage | Number | 10 | V | RO |
-| Unit1BatteryPack3Current | Number | 10 | A | RO |
-| Unit1BatteryPack3SOC | Number | 10 | % | RO |
-| Unit1BatteryPack3ChargeDischargePower | Number | 1 | W | RO |
-| Unit1BatteryPack3TotalCharge | Number | 100 | kWh | RO |
-| Unit1BatteryPack3TotalDischarge | Number | 100 | kWh | RO |
-| Unit1BatteryPack3MinimumTemperature | Number | 10 | °C | RO |
-| Unit1BatteryPack3MaximumTemperature | Number | 10 | °C | RO |
-| Unit2BatteryPack1SN | String | | | RO |
-| Unit2BatteryPack1No | Number | 1 | | RW |
-| Unit2BatteryPack1FirmwareVersion | String | | | RO |
-| Unit2BatteryPack1WorkingStatus | Number | 1 | | RO |
-| Unit2BatteryPack1Voltage | Number | 10 | V | RO |
-| Unit2BatteryPack1Current | Number | 10 | A | RO |
-| Unit2BatteryPack1SOC | Number | 10 | % | RO |
-| Unit2BatteryPack1ChargeDischargePower | Number | 1 | W | RO |
-| Unit2BatteryPack1TotalCharge | Number | 100 | kWh | RO |
-| Unit2BatteryPack1TotalDischarge | Number | 100 | kWh | RO |
-| Unit2BatteryPack1MinimumTemperature | Number | 10 | °C | RO |
-| Unit2BatteryPack1MaximumTemperature | Number | 10 | °C | RO |
-| Unit2BatteryPack2SN | String | | | RO |
-| Unit2BatteryPack2No | Number | 1 | | RW |
-| Unit2BatteryPack2FirmwareVersion | String | | | RO |
-| Unit2BatteryPack2WorkingStatus | Number | 1 | | RO |
-| Unit2BatteryPack2Voltage | Number | 10 | V | RO |
-| Unit2BatteryPack2Current | Number | 10 | A | RO |
-| Unit2BatteryPack2SOC | Number | 10 | % | RO |
-| Unit2BatteryPack2ChargeDischargePower | Number | 1 | W | RO |
-| Unit2BatteryPack2TotalCharge | Number | 100 | kWh | RO |
-| Unit2BatteryPack2TotalDischarge | Number | 100 | kWh | RO |
-| Unit2BatteryPack2MinimumTemperature | Number | 10 | °C | RO |
-| Unit2BatteryPack2MaximumTemperature | Number | 10 | °C | RO |
-| Unit2BatteryPack3SN | String | | | RO |
-| Unit2BatteryPack3No | Number | 1 | | RW |
-| Unit2BatteryPack3FirmwareVersion | String | | | RO |
-| Unit2BatteryPack3WorkingStatus | Number | 1 | | RO |
-| Unit2BatteryPack3Voltage | Number | 10 | V | RO |
-| Unit2BatteryPack3Current | Number | 10 | A | RO |
-| Unit2BatteryPack3SOC | Number | 10 | % | RO |
-| Unit2BatteryPack3ChargeDischargePower | Number | 1 | W | RO |
-| Unit2BatteryPack3TotalCharge | Number | 100 | kWh | RO |
-| Unit2BatteryPack3TotalDischarge | Number | 100 | kWh | RO |
-| Unit2BatteryPack3MinimumTemperature | Number | 10 | °C | RO |
-| Unit2BatteryPack3MaximumTemperature | Number | 10 | °C | RO |
+| Name | Type | Gain | Unit | Access Type |
+|:-------------------------------------------------|:-----------|:-----|:-----|:------------|
+| ProductModel | Number | 1 | | RW |
+| RunningStatus | Number | 1 | | RO |
+| WorkingModeSettings | Number | 1 | | RW |
+| BusVoltage | Number | 10 | V | RO |
+| BusCurrent | Number | 10 | A | RO |
+| ChargeDischargePower | Number | 1 | W | RO |
+| MaximumChargePower | Number | 1 | W | RO |
+| MaximumDischargePower | Number | 1 | W | RO |
+| RatedCapacity | Number | 1 | Wh | RO |
+| SOC | Number | 10 | % | RO |
+| BackupPowerSOC | Number | 10 | % | RW |
+| TargetSOC | Number | 10 | % | RW |
+| TotalCharge | Number | 100 | kWh | RO |
+| TotalDischarge | Number | 100 | kWh | RO |
+| CurrentDayChargeCapacity | Number | 100 | kWh | RO |
+| CurrentDayDischargeCapacity | Number | 100 | kWh | RO |
+| TimeOfUseElectricityPricePeriods | Bytestring | 1 | | RW |
+| MaximumChargingPower | Number | 1 | W | RW |
+| MaximumDischargingPower | Number | 1 | W | RW |
+| ChargingCutoffCapacity | Number | 10 | % | RW |
+| DischargeCutoffCapacity | Number | 10 | % | RW |
+| ForcedChargingAndDischargingPeriod | Number | 1 | mins | RW |
+| ForcedChargingAndDischargingPower | Number | 1 | W | RW |
+| ChargeFromGridFunction | Number | 1 | | RW |
+| GridChargeCutoffSOC | Number | 10 | % | RW |
+| ForcibleChargeDischarge | Number | 1 | | RW |
+| FixedChargingAndDischargingPeriods | Bytestring | 1 | | RW |
+| PowerOfChargeFromGrid | Number | 1 | W | RW |
+| MaximumPowerOfChargeFromGrid | Number | 1 | W | RW |
+| ForcibleChargeDischargeSettingMode | Number | 1 | | RW |
+| ForcibleChargePower | Number | 1 | W | RW |
+| ForcibleDischargePower | Number | 1 | W | RW |
+| TimeOfUseChargingAndDischargingPeriods | Bytestring | 1 | | RW |
+| ExcessPVEnergyUseInTOU | Number | 1 | | RW |
+| ActivePowerControlMode | Number | 1 | | RW |
+| MaximumFeedGridPowerInW | Number | 1 | W | RW |
+| MaximumFeedGridPowerInPercentage | Number | 10 | % | RW |
+| MaximumChargeFromGridPower | Number | 1 | W | RW |
+| SwitchToOffGrid | Number | 1 | | RW |
+| VoltageInIndependentOperation | Number | 1 | V | RW |
+| SOHCalibrationStatus | Number | 1 | | RO |
+| SOHCalibrationReleaseTheLowerDischargeLimitOfSOC | Number | 10 | | RO |
+| SOHCalibrationEnableTheBackupPowerSOC | Number | 10 | | RO |
+| Unit1ProductModel | Number | 1 | | RW |
+| Unit1SN | String | 1 | | RO |
+| Unit1No | Number | 1 | | RW |
+| Unit1SoftwareVersion | String | 1 | | RO |
+| Unit1DCDCVersion | String | 1 | | RO |
+| Unit1BMSVersion | String | 1 | | RO |
+| Unit1RunningStatus | Number | 1 | | RO |
+| Unit1WorkingMode | Number | 1 | | RO |
+| Unit1BusVoltage | Number | 10 | V | RO |
+| Unit1BusCurrent | Number | 10 | A | RO |
+| Unit1BatterySOC | Number | 10 | % | RO |
+| Unit1ChargeAndDischargePower | Number | 1 | W | RO |
+| Unit1RemainingChargeDischargeTime | Number | 1 | mins | RO |
+| Unit1RatedChargePower | Number | 1 | W | RO |
+| Unit1RatedDischargePower | Number | 1 | W | RO |
+| Unit1CurrentDayChargeCapacity | Number | 100 | kWh | RO |
+| Unit1CurrentDayDischargeCapacity | Number | 100 | kWh | RO |
+| Unit1TotalCharge | Number | 100 | kWh | RO |
+| Unit1TotalDischarge | Number | 100 | kWh | RO |
+| Unit1BatteryTemperature | Number | 10 | °C | RO |
+| Unit1FaultID | Number | 1 | | RO |
+| Unit2ProductModel | Number | 1 | | RW |
+| Unit2SN | String | 1 | | RO |
+| Unit2No | Number | 1 | | RW |
+| Unit2SoftwareVersion | String | 1 | | RO |
+| Unit2RunningStatus | Number | 1 | | RO |
+| Unit2BusVoltage | Number | 10 | V | RO |
+| Unit2BusCurrent | Number | 10 | A | RO |
+| Unit2BatterySOC | Number | 10 | % | RO |
+| Unit2ChargeAndDischargePower | Number | 1 | W | RO |
+| Unit2CurrentDayChargeCapacity | Number | 100 | kWh | RO |
+| Unit2CurrentDayDischargeCapacity | Number | 100 | kWh | RO |
+| Unit2TotalCharge | Number | 100 | kWh | RO |
+| Unit2TotalDischarge | Number | 100 | kWh | RO |
+| Unit2BatteryTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack1SN | String | | | RO |
+| Unit1BatteryPack1No | Number | | | RW |
+| Unit1BatteryPack1FirmwareVersion | String | | | RO |
+| Unit1BatteryPack1WorkingStatus | Number | | | RO |
+| Unit1BatteryPack1Voltage | Number | 10 | V | RO |
+| Unit1BatteryPack1Current | Number | 10 | A | RO |
+| Unit1BatteryPack1SOC | Number | 10 | % | RO |
+| Unit1BatteryPack1ChargeDischargePower | Number | 1 | W | RO |
+| Unit1BatteryPack1TotalCharge | Number | 100 | kWh | RO |
+| Unit1BatteryPack1TotalDischarge | Number | 100 | kWh | RO |
+| Unit1BatteryPack1MinimumTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack1MaximumTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack1SOHCalibrationStatus | Number | | | RO |
+| Unit1BatteryPack2SN | String | | | RO |
+| Unit1BatteryPack2No | Number | | | RW |
+| Unit1BatteryPack2FirmwareVersion | String | | | RO |
+| Unit1BatteryPack2WorkingStatus | Number | | | RO |
+| Unit1BatteryPack2Voltage | Number | 10 | V | RO |
+| Unit1BatteryPack2Current | Number | 10 | A | RO |
+| Unit1BatteryPack2SOC | Number | 10 | % | RO |
+| Unit1BatteryPack2ChargeDischargePower | Number | 1 | W | RO |
+| Unit1BatteryPack2TotalCharge | Number | 100 | kWh | RO |
+| Unit1BatteryPack2TotalDischarge | Number | 100 | kWh | RO |
+| Unit1BatteryPack2MinimumTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack2MaximumTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack2SOHCalibrationStatus | Number | | | RO |
+| Unit1BatteryPack3SN | String | | | RO |
+| Unit1BatteryPack3No | Number | | | RW |
+| Unit1BatteryPack3FirmwareVersion | String | | | RO |
+| Unit1BatteryPack3WorkingStatus | Number | | | RO |
+| Unit1BatteryPack3Voltage | Number | 10 | V | RO |
+| Unit1BatteryPack3Current | Number | 10 | A | RO |
+| Unit1BatteryPack3SOC | Number | 10 | % | RO |
+| Unit1BatteryPack3ChargeDischargePower | Number | 1 | W | RO |
+| Unit1BatteryPack3TotalCharge | Number | 100 | kWh | RO |
+| Unit1BatteryPack3TotalDischarge | Number | 100 | kWh | RO |
+| Unit1BatteryPack3MinimumTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack3MaximumTemperature | Number | 10 | °C | RO |
+| Unit1BatteryPack3SOHCalibrationStatus | Number | | | RO |
+| Unit2BatteryPack1SN | String | | | RO |
+| Unit2BatteryPack1No | Number | | | RW |
+| Unit2BatteryPack1FirmwareVersion | String | | | RO |
+| Unit2BatteryPack1WorkingStatus | Number | | | RO |
+| Unit2BatteryPack1Voltage | Number | 10 | V | RO |
+| Unit2BatteryPack1Current | Number | 10 | A | RO |
+| Unit2BatteryPack1SOC | Number | 10 | % | RO |
+| Unit2BatteryPack1ChargeDischargePower | Number | 1 | W | RO |
+| Unit2BatteryPack1TotalCharge | Number | 100 | kWh | RO |
+| Unit2BatteryPack1TotalDischarge | Number | 100 | kWh | RO |
+| Unit2BatteryPack1MinimumTemperature | Number | 10 | °C | RO |
+| Unit2BatteryPack1MaximumTemperature | Number | 10 | °C | RO |
+| Unit2BatteryPack1SOHCalibrationStatus | Number | | | RO |
+| Unit2BatteryPack2SN | String | | | RO |
+| Unit2BatteryPack2No | Number | | | RW |
+| Unit2BatteryPack2FirmwareVersion | String | | | RO |
+| Unit2BatteryPack2WorkingStatus | Number | | | RO |
+| Unit2BatteryPack2Voltage | Number | 10 | V | RO |
+| Unit2BatteryPack2Current | Number | 10 | A | RO |
+| Unit2BatteryPack2SOC | Number | 10 | % | RO |
+| Unit2BatteryPack2ChargeDischargePower | Number | 1 | W | RO |
+| Unit2BatteryPack2TotalCharge | Number | 100 | kWh | RO |
+| Unit2BatteryPack2TotalDischarge | Number | 100 | kWh | RO |
+| Unit2BatteryPack2MinimumTemperature | Number | 10 | °C | RO |
+| Unit2BatteryPack2MaximumTemperature | Number | 10 | °C | RO |
+| Unit2BatteryPack2SOHCalibrationStatus | Number | | | RO |
+| Unit2BatteryPack3SN | String | | | RO |
+| Unit2BatteryPack3No | Number | | | RW |
+| Unit2BatteryPack3FirmwareVersion | String | | | RO |
+| Unit2BatteryPack3WorkingStatus | Number | | | RO |
+| Unit2BatteryPack3Voltage | Number | 10 | V | RO |
+| Unit2BatteryPack3Current | Number | 10 | A | RO |
+| Unit2BatteryPack3SOC | Number | 10 | % | RO |
+| Unit2BatteryPack3ChargeDischargePower | Number | 1 | W | RO |
+| Unit2BatteryPack3TotalCharge | Number | 100 | kWh | RO |
+| Unit2BatteryPack3TotalDischarge | Number | 100 | kWh | RO |
+| Unit2BatteryPack3MinimumTemperature | Number | 10 | °C | RO |
+| Unit2BatteryPack3MaximumTemperature | Number | 10 | °C | RO |
+| Unit2BatteryPack3SOHCalibrationStatus | Number | | | RO |
### MeterEquipmentRegister
-| Name | Type | Gain | Unit | Access Type |
-|---------------------------|--------|------|------|-------------|
-| MeterStatus | Number | 1 | | RO |
-| APhaseVoltage | Number | 10 | V | RO |
-| BPhaseVoltage | Number | 10 | V | RO |
-| CPhaseVoltage | Number | 10 | V | RO |
-| APhaseCurrent | Number | 100 | A | RO |
-| BPhaseCurrent | Number | 100 | A | RO |
-| CPhaseCurrent | Number | 100 | A | RO |
-| ActivePower | Number | 1 | W | RO |
-| ReactivePower | Number | 1 | var | RO |
-| PowerFactor | Number | 1000 | | RO |
-| GridFrequency | Number | 100 | Hz | RO |
-| PositiveActiveElectricity | Number | 100 | kWh | RO |
-| ReverseActivePower | Number | 100 | kWh | RO |
-| AccumulatedReactivePower | Number | 100 | kvar | RO |
-| MeterType | Number | 1 | | RO |
-| ABLineVoltage | Number | 10 | V | RO |
-| BCLineVoltage | Number | 10 | V | RO |
-| CALineVoltage | Number | 10 | V | RO |
-| APhaseActivePower | Number | 1 | W | RO |
-| BPhaseActivePower | Number | 1 | W | RO |
-| CPhaseActivePower | Number | 1 | W | RO |
-| MeterModelDetectionResult | Number | 1 | | RO |
+| Name | Type | Gain | Unit | Access Type |
+|:--------------------------|:-------|:-----|:------|:------------|
+| MeterType | Number | 1 | | RO |
+| MeterStatus | Number | 1 | | RO |
+| MeterModelDetectionResult | Number | 1 | | RO |
+| APhaseVoltage | Number | 10 | V | RO |
+| BPhaseVoltage | Number | 10 | V | RO |
+| CPhaseVoltage | Number | 10 | V | RO |
+| APhaseCurrent | Number | 100 | A | RO |
+| BPhaseCurrent | Number | 100 | A | RO |
+| CPhaseCurrent | Number | 100 | A | RO |
+| ActivePower | Number | 1 | W | RO |
+| ReactivePower | Number | 1 | var | RO |
+| PowerFactor | Number | 1000 | | RO |
+| GridFrequency | Number | 100 | Hz | RO |
+| PositiveActiveElectricity | Number | 100 | kWh | RO |
+| ReverseActivePower | Number | 100 | kWh | RO |
+| AccumulatedReactivePower | Number | 100 | kvarh | RO |
+| ABLineVoltage | Number | 10 | V | RO |
+| BCLineVoltage | Number | 10 | V | RO |
+| CALineVoltage | Number | 10 | V | RO |
+| APhaseActivePower | Number | 1 | W | RO |
+| BPhaseActivePower | Number | 1 | W | RO |
+| CPhaseActivePower | Number | 1 | W | RO |
diff --git a/helpers/doc-generator/.gitignore b/helpers/doc-generator/.gitignore
new file mode 100644
index 0000000..53752db
--- /dev/null
+++ b/helpers/doc-generator/.gitignore
@@ -0,0 +1 @@
+output
diff --git a/helpers/doc-generator/main.py b/helpers/doc-generator/main.py
new file mode 100644
index 0000000..3ef98aa
--- /dev/null
+++ b/helpers/doc-generator/main.py
@@ -0,0 +1,35 @@
+from sun2000_modbus.datatypes import DataType
+from sun2000_modbus.registers import InverterEquipmentRegister, BatteryEquipmentRegister, MeterEquipmentRegister
+
+
+datatype_mapping = {
+ DataType.STRING: 'String',
+ DataType.UINT16_BE: 'Number',
+ DataType.UINT32_BE: 'Number',
+ DataType.INT16_BE: 'Number',
+ DataType.INT32_BE: 'Number',
+ DataType.BITFIELD16: 'Binary String/Bitfield',
+ DataType.BITFIELD32: 'Binary String/Bitfield',
+ DataType.MULTIDATA: 'Bytestring',
+}
+
+
+def omit_none(gain) -> str:
+ if gain:
+ return gain
+ return ''
+
+def process_register(register, filename) -> None:
+ with open(f'output/{filename}', 'w') as inverter_docs:
+ inverter_docs.write('| Name | Type | Gain | Unit | Access Type |\n')
+ inverter_docs.write('| :- | :- | :- | :- | :- |\n')
+ for item in register:
+ inverter_docs.write(f'| {item.name} | {datatype_mapping[item.value.data_type]} | {omit_none(item.value.gain)} | {omit_none(item.value.unit)} | {item.value.access_type.name} |\n')
+
+def main() -> None:
+ process_register(InverterEquipmentRegister, 'inverter.md')
+ process_register(BatteryEquipmentRegister, 'battery.md')
+ process_register(MeterEquipmentRegister, 'meter.md')
+
+if __name__ == "__main__":
+ main()
diff --git a/helpers/register-parser/.gitignore b/helpers/register-parser/.gitignore
new file mode 100644
index 0000000..1aafc3b
--- /dev/null
+++ b/helpers/register-parser/.gitignore
@@ -0,0 +1,2 @@
+input
+output
diff --git a/helpers/register-parser/register-parser.ipynb b/helpers/register-parser/register-parser.ipynb
new file mode 100644
index 0000000..66d042b
--- /dev/null
+++ b/helpers/register-parser/register-parser.ipynb
@@ -0,0 +1,1673 @@
+{
+ "cells": [
+ {
+ "metadata": {},
+ "cell_type": "markdown",
+ "source": [
+ "This Jupyter notebook handles the generation of all register enum values based on a \"Modbus Interface Definitions\"-PDF file provided by Huawei and the existing register enum class content for remapping already existing values.\n",
+ "\n",
+ "Input parameters:\n",
+ "\n",
+ "- `pdf_path`: Path to the \"Modbus Interface Definitions\"-PDF file\n",
+ "- `register_pages`: Page range where the tables of one register (e.g. \"Inverter Equipment Register\") are located in the PDF\n",
+ "- `old_registers_file_path`: Path of the text file containing the current register enum values\n",
+ "- `output_file_path`: Path of the resulting text-file containing the generated register enum values\n",
+ "\n",
+ "The process flow consists of the following steps:\n",
+ "\n",
+ "1. Parse the \"Modbus Interface Definitions\"-PDF into a pandas DataFrame\n",
+ " 1. The pages set in `register_pages` of the \"Modbus Interface Definitions\"-PDF file set in `pdf_path` are read by tabula to extract the contained table contents\n",
+ " 2. All found tables are merged into one, unnecessary columns are dropped, all columns are named accordingly and empty rows are dropped\n",
+ " 3. Carriage-returns are removed from the _name_-column\n",
+ " 4. The values in the columns _type_, _unit_ and _gain_ are mapped\n",
+ " 5. The table is sorted along the _address_ values\n",
+ " 6. The table is displayed for examination\n",
+ "2. Parse the current register enum values into a pandas DataFrame\n",
+ " 1. The file set in `old_registers_file_path` is opened for reading\n",
+ " 2. Each line is manipulated to represent a CSV-line\n",
+ " 3. All CSV-lines are read into a pandas DataFrame, all columns are named accordingly\n",
+ " 4. The table is displayed for examination\n",
+ "3. DataFrames are joined\n",
+ " 1. The both DataFrames from step 1 and 2 are left-joined on the _address_-columns\n",
+ " 2. The table is displayed for examination\n",
+ "4. Generated register enum values are exported to output file\n",
+ " 1. Each row in the joined column is converted to the target format for a register enum value\n",
+ " 2. All rows are exported to the file set in `output_file_path`\n",
+ "\n",
+ "The content of the output file can be copied over to the respective register enum class in `registers.py` (e.g. `InverterEquipmentRegister`). Some manual post-processing might be required."
+ ],
+ "id": "b7bfe393773b194c"
+ },
+ {
+ "cell_type": "code",
+ "id": "initial_id",
+ "metadata": {
+ "collapsed": true,
+ "ExecuteTime": {
+ "end_time": "2025-12-01T21:30:04.823571Z",
+ "start_time": "2025-12-01T21:30:04.300437Z"
+ }
+ },
+ "source": [
+ "import pandas as pd\n",
+ "import tabula\n",
+ "from IPython.display import display\n",
+ "\n",
+ "pdf_path = '../../docs/modbus.pdf'\n",
+ "register_pages = '78-80'\n",
+ "old_registers_file_path = 'input/registers.txt'\n",
+ "output_file_path = 'output/powermeter.txt'\n",
+ "\n",
+ "#------------------------------------------------\n",
+ "datatype_mapping = {\n",
+ " 'STR': 'STRING',\n",
+ " 'String': 'STRING',\n",
+ " 'STRING': 'STRING',\n",
+ " 'U16': 'UINT16_BE',\n",
+ " 'UINT16': 'UINT16_BE',\n",
+ " 'ENUM16': 'UINT16_BE',\n",
+ " 'U32': 'UINT32_BE',\n",
+ " 'UINT32': 'UINT32_BE',\n",
+ " 'EPOCHTIME': 'UINT32_BE',\n",
+ " 'I16': 'INT16_BE',\n",
+ " 'INT16': 'INT16_BE',\n",
+ " 'I32': 'INT32_BE',\n",
+ " 'INT32': 'INT32_BE',\n",
+ " 'Bitfield16': 'BITFIELD16',\n",
+ " 'Bitfield32': 'BITFIELD32',\n",
+ " 'DBitfield32': 'BITFIELD32',\n",
+ " 'MLD/Bytes': 'MULTIDATA',\n",
+ " 'MULTIDATA': 'MULTIDATA',\n",
+ " 'BYTES': 'MULTIDATA',\n",
+ " 'Bytes': 'MULTIDATA',\n",
+ "}\n",
+ "\n",
+ "\n",
+ "unit_mapping = {\n",
+ " 'N/A': \"None\",\n",
+ " 'NA': \"None\",\n",
+ " 'Var': \"'var'\",\n",
+ " 'kVar': \"'kvar'\",\n",
+ " 'kVarh': \"'kvarh'\",\n",
+ " 'MΩ': \"'MOhm'\",\n",
+ " 'kW': \"'W'\",\n",
+ " 'Kw': \"'W'\",\n",
+ "}\n",
+ "\n",
+ "\n",
+ "gain_mapping = {\n",
+ " 'N/A': \"None\",\n",
+ " 'NA': \"None\",\n",
+ "}\n",
+ "\n",
+ "\n",
+ "def process_name_column(merged_table: pd.DataFrame) -> pd.DataFrame:\n",
+ " merged_table['name'] = merged_table['name'].str.replace('\\r', ' ')\n",
+ "\n",
+ " return merged_table\n",
+ "\n",
+ "\n",
+ "def process_type_column(merged_table: pd.DataFrame) -> pd.DataFrame:\n",
+ " merged_table['type'] = merged_table['type'].str.replace('\\r', '')\n",
+ " merged_table['parsed_type'] = merged_table['type'].map(datatype_mapping)\n",
+ "\n",
+ " return merged_table\n",
+ "\n",
+ "\n",
+ "def process_unit_column(merged_table: pd.DataFrame) -> pd.DataFrame:\n",
+ " merged_table['unit'] = merged_table['unit'].str.replace('\\r', '')\n",
+ " merged_table['parsed_unit'] = merged_table['unit'].apply(lambda x: unit_mapping.get(x, f'\\'{x}\\''))\n",
+ "\n",
+ " return merged_table\n",
+ "\n",
+ "\n",
+ "def process_gain_column(merged_table: pd.DataFrame) -> pd.DataFrame:\n",
+ " merged_table['parsed_gain'] = merged_table.apply(lambda x: 1 if x['unit'] in ['kW', 'Kw'] else gain_mapping.get(x['gain'], x['gain']), axis=1)\n",
+ "\n",
+ " return merged_table\n",
+ "\n",
+ "\n",
+ "# Display all rows for examination of data\n",
+ "pd.set_option('display.max_rows', None)\n",
+ "\n",
+ "tables = tabula.read_pdf(pdf_path, pages=register_pages, multiple_tables=True, lattice=True, pandas_options={'dtype': str})\n",
+ "if not tables:\n",
+ " print('No tables found')\n",
+ " exit(1)\n",
+ "else:\n",
+ " merged_table = pd.concat(objs=tables, ignore_index=True)\n",
+ " merged_table.drop(columns={merged_table.columns[0], merged_table.columns[9]}, inplace=True)\n",
+ " column_mapping = {\n",
+ " merged_table.columns[0]: 'index',\n",
+ " merged_table.columns[1]: 'name',\n",
+ " merged_table.columns[2]: 'mode',\n",
+ " merged_table.columns[3]: 'type',\n",
+ " merged_table.columns[4]: 'unit',\n",
+ " merged_table.columns[5]: 'gain',\n",
+ " merged_table.columns[6]: 'address',\n",
+ " merged_table.columns[7]: 'quantity'\n",
+ " }\n",
+ " merged_table.rename(columns=column_mapping, inplace=True)\n",
+ " merged_table.dropna(inplace=True)\n",
+ "\n",
+ " merged_table = process_name_column(merged_table)\n",
+ " merged_table = process_type_column(merged_table)\n",
+ " merged_table = process_unit_column(merged_table)\n",
+ " merged_table = process_gain_column(merged_table)\n",
+ "\n",
+ " merged_table.sort_values(by=['address'], inplace=True)\n",
+ "\n",
+ " # Examination step\n",
+ " display(merged_table)"
+ ],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ " index name mode type unit gain address \\\n",
+ "0 1 Meter status RO UINT16 N/A 1 37100 \n",
+ "1 2 Grid voltage (A phase) RO INT32 V 10 37101 \n",
+ "2 3 B phase voltage RO INT32 V 10 37103 \n",
+ "3 4 C phase voltage RO INT32 V 10 37105 \n",
+ "4 5 Grid current(A phase) RO INT32 A 100 37107 \n",
+ "5 6 B phase current RO INT32 A 100 37109 \n",
+ "6 7 C phase current RO INT32 A 100 37111 \n",
+ "7 8 Active power RO INT32 W 1 37113 \n",
+ "8 9 Reactive power RO INT32 Var 1 37115 \n",
+ "9 10 Power factor RO INT16 NA 1000 37117 \n",
+ "10 11 Grid frequency RO INT16 Hz 100 37118 \n",
+ "11 12 Positive active electricity RO INT32 kWh 100 37119 \n",
+ "12 13 Reverse active power RO INT32 kWh 100 37121 \n",
+ "13 14 Accumulat ed reactive power RO INT32 kVarh 100 37123 \n",
+ "14 15 Meter type RO UINT16 N/A 1 37125 \n",
+ "15 16 A-B line voltage RO INT32 V 10 37126 \n",
+ "16 17 B-C line voltage RO INT32 V 10 37128 \n",
+ "17 18 CA line voltage RO INT32 V 10 37130 \n",
+ "18 19 A phase active power RO INT32 W 1 37132 \n",
+ "19 20 B phase active power RO INT32 W 1 37134 \n",
+ "20 21 C phase active power RO INT32 W 1 37136 \n",
+ "21 22 Meter model detection result RO UINT16 N/A 1 37138 \n",
+ "\n",
+ " quantity parsed_type parsed_unit parsed_gain \n",
+ "0 1 UINT16_BE None 1 \n",
+ "1 2 INT32_BE 'V' 10 \n",
+ "2 2 INT32_BE 'V' 10 \n",
+ "3 2 INT32_BE 'V' 10 \n",
+ "4 2 INT32_BE 'A' 100 \n",
+ "5 2 INT32_BE 'A' 100 \n",
+ "6 2 INT32_BE 'A' 100 \n",
+ "7 2 INT32_BE 'W' 1 \n",
+ "8 2 INT32_BE 'var' 1 \n",
+ "9 1 INT16_BE None 1000 \n",
+ "10 1 INT16_BE 'Hz' 100 \n",
+ "11 2 INT32_BE 'kWh' 100 \n",
+ "12 2 INT32_BE 'kWh' 100 \n",
+ "13 2 INT32_BE 'kvarh' 100 \n",
+ "14 1 UINT16_BE None 1 \n",
+ "15 2 INT32_BE 'V' 10 \n",
+ "16 2 INT32_BE 'V' 10 \n",
+ "17 2 INT32_BE 'V' 10 \n",
+ "18 2 INT32_BE 'W' 1 \n",
+ "19 2 INT32_BE 'W' 1 \n",
+ "20 2 INT32_BE 'W' 1 \n",
+ "21 1 UINT16_BE None 1 "
+ ],
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " index | \n",
+ " name | \n",
+ " mode | \n",
+ " type | \n",
+ " unit | \n",
+ " gain | \n",
+ " address | \n",
+ " quantity | \n",
+ " parsed_type | \n",
+ " parsed_unit | \n",
+ " parsed_gain | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 1 | \n",
+ " Meter status | \n",
+ " RO | \n",
+ " UINT16 | \n",
+ " N/A | \n",
+ " 1 | \n",
+ " 37100 | \n",
+ " 1 | \n",
+ " UINT16_BE | \n",
+ " None | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2 | \n",
+ " Grid voltage (A phase) | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37101 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 3 | \n",
+ " B phase voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37103 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 4 | \n",
+ " C phase voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37105 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 5 | \n",
+ " Grid current(A phase) | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " A | \n",
+ " 100 | \n",
+ " 37107 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'A' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 6 | \n",
+ " B phase current | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " A | \n",
+ " 100 | \n",
+ " 37109 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'A' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 7 | \n",
+ " C phase current | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " A | \n",
+ " 100 | \n",
+ " 37111 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'A' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 8 | \n",
+ " Active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37113 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 9 | \n",
+ " Reactive power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " Var | \n",
+ " 1 | \n",
+ " 37115 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'var' | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 10 | \n",
+ " Power factor | \n",
+ " RO | \n",
+ " INT16 | \n",
+ " NA | \n",
+ " 1000 | \n",
+ " 37117 | \n",
+ " 1 | \n",
+ " INT16_BE | \n",
+ " None | \n",
+ " 1000 | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 11 | \n",
+ " Grid frequency | \n",
+ " RO | \n",
+ " INT16 | \n",
+ " Hz | \n",
+ " 100 | \n",
+ " 37118 | \n",
+ " 1 | \n",
+ " INT16_BE | \n",
+ " 'Hz' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " 12 | \n",
+ " Positive active electricity | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " kWh | \n",
+ " 100 | \n",
+ " 37119 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'kWh' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " 13 | \n",
+ " Reverse active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " kWh | \n",
+ " 100 | \n",
+ " 37121 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'kWh' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " 14 | \n",
+ " Accumulat ed reactive power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " kVarh | \n",
+ " 100 | \n",
+ " 37123 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'kvarh' | \n",
+ " 100 | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " 15 | \n",
+ " Meter type | \n",
+ " RO | \n",
+ " UINT16 | \n",
+ " N/A | \n",
+ " 1 | \n",
+ " 37125 | \n",
+ " 1 | \n",
+ " UINT16_BE | \n",
+ " None | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " 16 | \n",
+ " A-B line voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37126 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " 17 | \n",
+ " B-C line voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37128 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " 18 | \n",
+ " CA line voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37130 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " 19 | \n",
+ " A phase active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37132 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " 20 | \n",
+ " B phase active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37134 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 20 | \n",
+ " 21 | \n",
+ " C phase active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37136 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 21 | \n",
+ " 22 | \n",
+ " Meter model detection result | \n",
+ " RO | \n",
+ " UINT16 | \n",
+ " N/A | \n",
+ " 1 | \n",
+ " 37138 | \n",
+ " 1 | \n",
+ " UINT16_BE | \n",
+ " None | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data",
+ "jetTransient": {
+ "display_id": null
+ }
+ }
+ ],
+ "execution_count": 21
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-12-01T21:30:17.152949Z",
+ "start_time": "2025-12-01T21:30:17.145273Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "from io import StringIO\n",
+ "import pandas\n",
+ "\n",
+ "csv_lines = ''\n",
+ "with open(old_registers_file_path, 'r') as input_file:\n",
+ " for line in input_file:\n",
+ " csv_line = line.replace('=', ',').replace('(', ',').replace(')', '').replace(' ', '')\n",
+ " csv_lines += csv_line\n",
+ "\n",
+ "old_registers = pandas.read_csv(StringIO(csv_lines), header=None, names=['name', 'register', 'address', 'quantity', 'type', 'gain', 'unit', 'mode', 'mapping'], dtype=str)\n",
+ "\n",
+ "# Examination step\n",
+ "display(old_registers)"
+ ],
+ "id": "73ef97640afc6320",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ " name register address quantity \\\n",
+ "0 MeterType Register 37125 1 \n",
+ "1 MeterStatus Register 37100 1 \n",
+ "2 MeterModelDetectionResult Register 37138 1 \n",
+ "3 APhaseVoltage Register 37101 2 \n",
+ "4 BPhaseVoltage Register 37103 2 \n",
+ "5 CPhaseVoltage Register 37105 2 \n",
+ "6 APhaseCurrent Register 37107 2 \n",
+ "7 BPhaseCurrent Register 37109 2 \n",
+ "8 CPhaseCurrent Register 37111 2 \n",
+ "9 ActivePower Register 37113 2 \n",
+ "10 ReactivePower Register 37115 2 \n",
+ "11 PowerFactor Register 37117 1 \n",
+ "12 GridFrequency Register 37118 1 \n",
+ "13 PositiveActiveElectricity Register 37119 2 \n",
+ "14 ReverseActivePower Register 37121 2 \n",
+ "15 AccumulatedReactivePower Register 37123 2 \n",
+ "16 ABLineVoltage Register 37126 2 \n",
+ "17 BCLineVoltage Register 37128 2 \n",
+ "18 CALineVoltage Register 37130 2 \n",
+ "19 APhaseActivePower Register 37132 2 \n",
+ "20 BPhaseActivePower Register 37134 2 \n",
+ "21 CPhaseActivePower Register 37136 2 \n",
+ "\n",
+ " type gain unit mode \\\n",
+ "0 datatypes.DataType.UINT16_BE 1 NaN AccessType.RO \n",
+ "1 datatypes.DataType.UINT16_BE 1 NaN AccessType.RO \n",
+ "2 datatypes.DataType.UINT16_BE 1 NaN AccessType.RO \n",
+ "3 datatypes.DataType.INT32_BE 10 'V' AccessType.RO \n",
+ "4 datatypes.DataType.INT32_BE 10 'V' AccessType.RO \n",
+ "5 datatypes.DataType.INT32_BE 10 'V' AccessType.RO \n",
+ "6 datatypes.DataType.INT32_BE 100 'A' AccessType.RO \n",
+ "7 datatypes.DataType.INT32_BE 100 'A' AccessType.RO \n",
+ "8 datatypes.DataType.INT32_BE 100 'A' AccessType.RO \n",
+ "9 datatypes.DataType.INT32_BE 1 'W' AccessType.RO \n",
+ "10 datatypes.DataType.INT32_BE 1 'var' AccessType.RO \n",
+ "11 datatypes.DataType.INT16_BE 1000 NaN AccessType.RO \n",
+ "12 datatypes.DataType.INT16_BE 100 'Hz' AccessType.RO \n",
+ "13 datatypes.DataType.INT32_BE 100 'kWh' AccessType.RO \n",
+ "14 datatypes.DataType.INT32_BE 100 'kWh' AccessType.RO \n",
+ "15 datatypes.DataType.INT32_BE 100 'kvar' AccessType.RO \n",
+ "16 datatypes.DataType.INT32_BE 10 'V' AccessType.RO \n",
+ "17 datatypes.DataType.INT32_BE 10 'V' AccessType.RO \n",
+ "18 datatypes.DataType.INT32_BE 10 'V' AccessType.RO \n",
+ "19 datatypes.DataType.INT32_BE 1 'W' AccessType.RO \n",
+ "20 datatypes.DataType.INT32_BE 1 'W' AccessType.RO \n",
+ "21 datatypes.DataType.INT32_BE 1 'W' AccessType.RO \n",
+ "\n",
+ " mapping \n",
+ "0 mappings.MeterType \n",
+ "1 mappings.MeterStatus \n",
+ "2 mappings.MeterModelDetectionResult \n",
+ "3 NaN \n",
+ "4 NaN \n",
+ "5 NaN \n",
+ "6 NaN \n",
+ "7 NaN \n",
+ "8 NaN \n",
+ "9 NaN \n",
+ "10 NaN \n",
+ "11 NaN \n",
+ "12 NaN \n",
+ "13 NaN \n",
+ "14 NaN \n",
+ "15 NaN \n",
+ "16 NaN \n",
+ "17 NaN \n",
+ "18 NaN \n",
+ "19 NaN \n",
+ "20 NaN \n",
+ "21 NaN "
+ ],
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " name | \n",
+ " register | \n",
+ " address | \n",
+ " quantity | \n",
+ " type | \n",
+ " gain | \n",
+ " unit | \n",
+ " mode | \n",
+ " mapping | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " MeterType | \n",
+ " Register | \n",
+ " 37125 | \n",
+ " 1 | \n",
+ " datatypes.DataType.UINT16_BE | \n",
+ " 1 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " mappings.MeterType | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " MeterStatus | \n",
+ " Register | \n",
+ " 37100 | \n",
+ " 1 | \n",
+ " datatypes.DataType.UINT16_BE | \n",
+ " 1 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " mappings.MeterStatus | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " MeterModelDetectionResult | \n",
+ " Register | \n",
+ " 37138 | \n",
+ " 1 | \n",
+ " datatypes.DataType.UINT16_BE | \n",
+ " 1 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " mappings.MeterModelDetectionResult | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " APhaseVoltage | \n",
+ " Register | \n",
+ " 37101 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " BPhaseVoltage | \n",
+ " Register | \n",
+ " 37103 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " CPhaseVoltage | \n",
+ " Register | \n",
+ " 37105 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " APhaseCurrent | \n",
+ " Register | \n",
+ " 37107 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'A' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " BPhaseCurrent | \n",
+ " Register | \n",
+ " 37109 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'A' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " CPhaseCurrent | \n",
+ " Register | \n",
+ " 37111 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'A' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " ActivePower | \n",
+ " Register | \n",
+ " 37113 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " ReactivePower | \n",
+ " Register | \n",
+ " 37115 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'var' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " PowerFactor | \n",
+ " Register | \n",
+ " 37117 | \n",
+ " 1 | \n",
+ " datatypes.DataType.INT16_BE | \n",
+ " 1000 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " GridFrequency | \n",
+ " Register | \n",
+ " 37118 | \n",
+ " 1 | \n",
+ " datatypes.DataType.INT16_BE | \n",
+ " 100 | \n",
+ " 'Hz' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " PositiveActiveElectricity | \n",
+ " Register | \n",
+ " 37119 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'kWh' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " ReverseActivePower | \n",
+ " Register | \n",
+ " 37121 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'kWh' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " AccumulatedReactivePower | \n",
+ " Register | \n",
+ " 37123 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'kvar' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " ABLineVoltage | \n",
+ " Register | \n",
+ " 37126 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " BCLineVoltage | \n",
+ " Register | \n",
+ " 37128 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " CALineVoltage | \n",
+ " Register | \n",
+ " 37130 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " APhaseActivePower | \n",
+ " Register | \n",
+ " 37132 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 20 | \n",
+ " BPhaseActivePower | \n",
+ " Register | \n",
+ " 37134 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 21 | \n",
+ " CPhaseActivePower | \n",
+ " Register | \n",
+ " 37136 | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data",
+ "jetTransient": {
+ "display_id": null
+ }
+ }
+ ],
+ "execution_count": 22
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-12-01T21:30:21.914371Z",
+ "start_time": "2025-12-01T21:30:21.905380Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "joined = merged_table.merge(old_registers, how='left', left_on='address', right_on='address')\n",
+ "\n",
+ "# Examination step\n",
+ "display(joined)"
+ ],
+ "id": "ddfd2e9dbcf9ad9e",
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ " index name_x mode_x type_x unit_x gain_x address \\\n",
+ "0 1 Meter status RO UINT16 N/A 1 37100 \n",
+ "1 2 Grid voltage (A phase) RO INT32 V 10 37101 \n",
+ "2 3 B phase voltage RO INT32 V 10 37103 \n",
+ "3 4 C phase voltage RO INT32 V 10 37105 \n",
+ "4 5 Grid current(A phase) RO INT32 A 100 37107 \n",
+ "5 6 B phase current RO INT32 A 100 37109 \n",
+ "6 7 C phase current RO INT32 A 100 37111 \n",
+ "7 8 Active power RO INT32 W 1 37113 \n",
+ "8 9 Reactive power RO INT32 Var 1 37115 \n",
+ "9 10 Power factor RO INT16 NA 1000 37117 \n",
+ "10 11 Grid frequency RO INT16 Hz 100 37118 \n",
+ "11 12 Positive active electricity RO INT32 kWh 100 37119 \n",
+ "12 13 Reverse active power RO INT32 kWh 100 37121 \n",
+ "13 14 Accumulat ed reactive power RO INT32 kVarh 100 37123 \n",
+ "14 15 Meter type RO UINT16 N/A 1 37125 \n",
+ "15 16 A-B line voltage RO INT32 V 10 37126 \n",
+ "16 17 B-C line voltage RO INT32 V 10 37128 \n",
+ "17 18 CA line voltage RO INT32 V 10 37130 \n",
+ "18 19 A phase active power RO INT32 W 1 37132 \n",
+ "19 20 B phase active power RO INT32 W 1 37134 \n",
+ "20 21 C phase active power RO INT32 W 1 37136 \n",
+ "21 22 Meter model detection result RO UINT16 N/A 1 37138 \n",
+ "\n",
+ " quantity_x parsed_type parsed_unit parsed_gain name_y \\\n",
+ "0 1 UINT16_BE None 1 MeterStatus \n",
+ "1 2 INT32_BE 'V' 10 APhaseVoltage \n",
+ "2 2 INT32_BE 'V' 10 BPhaseVoltage \n",
+ "3 2 INT32_BE 'V' 10 CPhaseVoltage \n",
+ "4 2 INT32_BE 'A' 100 APhaseCurrent \n",
+ "5 2 INT32_BE 'A' 100 BPhaseCurrent \n",
+ "6 2 INT32_BE 'A' 100 CPhaseCurrent \n",
+ "7 2 INT32_BE 'W' 1 ActivePower \n",
+ "8 2 INT32_BE 'var' 1 ReactivePower \n",
+ "9 1 INT16_BE None 1000 PowerFactor \n",
+ "10 1 INT16_BE 'Hz' 100 GridFrequency \n",
+ "11 2 INT32_BE 'kWh' 100 PositiveActiveElectricity \n",
+ "12 2 INT32_BE 'kWh' 100 ReverseActivePower \n",
+ "13 2 INT32_BE 'kvarh' 100 AccumulatedReactivePower \n",
+ "14 1 UINT16_BE None 1 MeterType \n",
+ "15 2 INT32_BE 'V' 10 ABLineVoltage \n",
+ "16 2 INT32_BE 'V' 10 BCLineVoltage \n",
+ "17 2 INT32_BE 'V' 10 CALineVoltage \n",
+ "18 2 INT32_BE 'W' 1 APhaseActivePower \n",
+ "19 2 INT32_BE 'W' 1 BPhaseActivePower \n",
+ "20 2 INT32_BE 'W' 1 CPhaseActivePower \n",
+ "21 1 UINT16_BE None 1 MeterModelDetectionResult \n",
+ "\n",
+ " register quantity_y type_y gain_y unit_y \\\n",
+ "0 Register 1 datatypes.DataType.UINT16_BE 1 NaN \n",
+ "1 Register 2 datatypes.DataType.INT32_BE 10 'V' \n",
+ "2 Register 2 datatypes.DataType.INT32_BE 10 'V' \n",
+ "3 Register 2 datatypes.DataType.INT32_BE 10 'V' \n",
+ "4 Register 2 datatypes.DataType.INT32_BE 100 'A' \n",
+ "5 Register 2 datatypes.DataType.INT32_BE 100 'A' \n",
+ "6 Register 2 datatypes.DataType.INT32_BE 100 'A' \n",
+ "7 Register 2 datatypes.DataType.INT32_BE 1 'W' \n",
+ "8 Register 2 datatypes.DataType.INT32_BE 1 'var' \n",
+ "9 Register 1 datatypes.DataType.INT16_BE 1000 NaN \n",
+ "10 Register 1 datatypes.DataType.INT16_BE 100 'Hz' \n",
+ "11 Register 2 datatypes.DataType.INT32_BE 100 'kWh' \n",
+ "12 Register 2 datatypes.DataType.INT32_BE 100 'kWh' \n",
+ "13 Register 2 datatypes.DataType.INT32_BE 100 'kvar' \n",
+ "14 Register 1 datatypes.DataType.UINT16_BE 1 NaN \n",
+ "15 Register 2 datatypes.DataType.INT32_BE 10 'V' \n",
+ "16 Register 2 datatypes.DataType.INT32_BE 10 'V' \n",
+ "17 Register 2 datatypes.DataType.INT32_BE 10 'V' \n",
+ "18 Register 2 datatypes.DataType.INT32_BE 1 'W' \n",
+ "19 Register 2 datatypes.DataType.INT32_BE 1 'W' \n",
+ "20 Register 2 datatypes.DataType.INT32_BE 1 'W' \n",
+ "21 Register 1 datatypes.DataType.UINT16_BE 1 NaN \n",
+ "\n",
+ " mode_y mapping \n",
+ "0 AccessType.RO mappings.MeterStatus \n",
+ "1 AccessType.RO NaN \n",
+ "2 AccessType.RO NaN \n",
+ "3 AccessType.RO NaN \n",
+ "4 AccessType.RO NaN \n",
+ "5 AccessType.RO NaN \n",
+ "6 AccessType.RO NaN \n",
+ "7 AccessType.RO NaN \n",
+ "8 AccessType.RO NaN \n",
+ "9 AccessType.RO NaN \n",
+ "10 AccessType.RO NaN \n",
+ "11 AccessType.RO NaN \n",
+ "12 AccessType.RO NaN \n",
+ "13 AccessType.RO NaN \n",
+ "14 AccessType.RO mappings.MeterType \n",
+ "15 AccessType.RO NaN \n",
+ "16 AccessType.RO NaN \n",
+ "17 AccessType.RO NaN \n",
+ "18 AccessType.RO NaN \n",
+ "19 AccessType.RO NaN \n",
+ "20 AccessType.RO NaN \n",
+ "21 AccessType.RO mappings.MeterModelDetectionResult "
+ ],
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " index | \n",
+ " name_x | \n",
+ " mode_x | \n",
+ " type_x | \n",
+ " unit_x | \n",
+ " gain_x | \n",
+ " address | \n",
+ " quantity_x | \n",
+ " parsed_type | \n",
+ " parsed_unit | \n",
+ " parsed_gain | \n",
+ " name_y | \n",
+ " register | \n",
+ " quantity_y | \n",
+ " type_y | \n",
+ " gain_y | \n",
+ " unit_y | \n",
+ " mode_y | \n",
+ " mapping | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 1 | \n",
+ " Meter status | \n",
+ " RO | \n",
+ " UINT16 | \n",
+ " N/A | \n",
+ " 1 | \n",
+ " 37100 | \n",
+ " 1 | \n",
+ " UINT16_BE | \n",
+ " None | \n",
+ " 1 | \n",
+ " MeterStatus | \n",
+ " Register | \n",
+ " 1 | \n",
+ " datatypes.DataType.UINT16_BE | \n",
+ " 1 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " mappings.MeterStatus | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2 | \n",
+ " Grid voltage (A phase) | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37101 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ " APhaseVoltage | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 3 | \n",
+ " B phase voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37103 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ " BPhaseVoltage | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 4 | \n",
+ " C phase voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37105 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ " CPhaseVoltage | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 5 | \n",
+ " Grid current(A phase) | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " A | \n",
+ " 100 | \n",
+ " 37107 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'A' | \n",
+ " 100 | \n",
+ " APhaseCurrent | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'A' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 6 | \n",
+ " B phase current | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " A | \n",
+ " 100 | \n",
+ " 37109 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'A' | \n",
+ " 100 | \n",
+ " BPhaseCurrent | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'A' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 7 | \n",
+ " C phase current | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " A | \n",
+ " 100 | \n",
+ " 37111 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'A' | \n",
+ " 100 | \n",
+ " CPhaseCurrent | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'A' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 8 | \n",
+ " Active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37113 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ " ActivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 9 | \n",
+ " Reactive power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " Var | \n",
+ " 1 | \n",
+ " 37115 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'var' | \n",
+ " 1 | \n",
+ " ReactivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'var' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 10 | \n",
+ " Power factor | \n",
+ " RO | \n",
+ " INT16 | \n",
+ " NA | \n",
+ " 1000 | \n",
+ " 37117 | \n",
+ " 1 | \n",
+ " INT16_BE | \n",
+ " None | \n",
+ " 1000 | \n",
+ " PowerFactor | \n",
+ " Register | \n",
+ " 1 | \n",
+ " datatypes.DataType.INT16_BE | \n",
+ " 1000 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 11 | \n",
+ " Grid frequency | \n",
+ " RO | \n",
+ " INT16 | \n",
+ " Hz | \n",
+ " 100 | \n",
+ " 37118 | \n",
+ " 1 | \n",
+ " INT16_BE | \n",
+ " 'Hz' | \n",
+ " 100 | \n",
+ " GridFrequency | \n",
+ " Register | \n",
+ " 1 | \n",
+ " datatypes.DataType.INT16_BE | \n",
+ " 100 | \n",
+ " 'Hz' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " 12 | \n",
+ " Positive active electricity | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " kWh | \n",
+ " 100 | \n",
+ " 37119 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'kWh' | \n",
+ " 100 | \n",
+ " PositiveActiveElectricity | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'kWh' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " 13 | \n",
+ " Reverse active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " kWh | \n",
+ " 100 | \n",
+ " 37121 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'kWh' | \n",
+ " 100 | \n",
+ " ReverseActivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'kWh' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " 14 | \n",
+ " Accumulat ed reactive power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " kVarh | \n",
+ " 100 | \n",
+ " 37123 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'kvarh' | \n",
+ " 100 | \n",
+ " AccumulatedReactivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 100 | \n",
+ " 'kvar' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " 15 | \n",
+ " Meter type | \n",
+ " RO | \n",
+ " UINT16 | \n",
+ " N/A | \n",
+ " 1 | \n",
+ " 37125 | \n",
+ " 1 | \n",
+ " UINT16_BE | \n",
+ " None | \n",
+ " 1 | \n",
+ " MeterType | \n",
+ " Register | \n",
+ " 1 | \n",
+ " datatypes.DataType.UINT16_BE | \n",
+ " 1 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " mappings.MeterType | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " 16 | \n",
+ " A-B line voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37126 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ " ABLineVoltage | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " 17 | \n",
+ " B-C line voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37128 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ " BCLineVoltage | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " 18 | \n",
+ " CA line voltage | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " V | \n",
+ " 10 | \n",
+ " 37130 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'V' | \n",
+ " 10 | \n",
+ " CALineVoltage | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 10 | \n",
+ " 'V' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " 19 | \n",
+ " A phase active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37132 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ " APhaseActivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " 20 | \n",
+ " B phase active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37134 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ " BPhaseActivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 20 | \n",
+ " 21 | \n",
+ " C phase active power | \n",
+ " RO | \n",
+ " INT32 | \n",
+ " W | \n",
+ " 1 | \n",
+ " 37136 | \n",
+ " 2 | \n",
+ " INT32_BE | \n",
+ " 'W' | \n",
+ " 1 | \n",
+ " CPhaseActivePower | \n",
+ " Register | \n",
+ " 2 | \n",
+ " datatypes.DataType.INT32_BE | \n",
+ " 1 | \n",
+ " 'W' | \n",
+ " AccessType.RO | \n",
+ " NaN | \n",
+ "
\n",
+ " \n",
+ " | 21 | \n",
+ " 22 | \n",
+ " Meter model detection result | \n",
+ " RO | \n",
+ " UINT16 | \n",
+ " N/A | \n",
+ " 1 | \n",
+ " 37138 | \n",
+ " 1 | \n",
+ " UINT16_BE | \n",
+ " None | \n",
+ " 1 | \n",
+ " MeterModelDetectionResult | \n",
+ " Register | \n",
+ " 1 | \n",
+ " datatypes.DataType.UINT16_BE | \n",
+ " 1 | \n",
+ " NaN | \n",
+ " AccessType.RO | \n",
+ " mappings.MeterModelDetectionResult | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data",
+ "jetTransient": {
+ "display_id": null
+ }
+ }
+ ],
+ "execution_count": 23
+ },
+ {
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2025-12-01T21:30:36.216444Z",
+ "start_time": "2025-12-01T21:30:36.209791Z"
+ }
+ },
+ "cell_type": "code",
+ "source": [
+ "import csv\n",
+ "\n",
+ "joined['new_register'] = joined.apply(lambda x: f'{'\"' + x['name_x'] + '\"' if pandas.isnull(x['name_y']) else x['name_y']} = Register({x['address']}, {x['quantity_x']}, datatypes.DataType.{x['parsed_type']}, {x['parsed_gain']}, {x['parsed_unit']}, AccessType.{x['mode_x']}, {None if pandas.isnull(x['mapping']) else x['mapping']})', axis=1)\n",
+ "joined.to_csv(output_file_path, columns=['new_register'], index=False, header=False, quoting=csv.QUOTE_NONE, sep=';')"
+ ],
+ "id": "136feb9761e37ec1",
+ "outputs": [],
+ "execution_count": 24
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 2
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython2",
+ "version": "2.7.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/helpers/register-parser/requirements.txt b/helpers/register-parser/requirements.txt
new file mode 100644
index 0000000..fec379d
--- /dev/null
+++ b/helpers/register-parser/requirements.txt
@@ -0,0 +1,3 @@
+tabula-py
+pandas
+ipython
diff --git a/pyproject.toml b/pyproject.toml
index 768d138..ea9d232 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,7 +17,7 @@ dynamic = ["version", "description"]
requires-python = ">=3.9"
keywords = ["sun2000", "modbus", "photovoltaic"]
dependencies = [
- "pymodbus>=3.7.4",
+ "pymodbus>=3.11.0",
]
[project.urls]
diff --git a/requirements.txt b/requirements.txt
index b000634..9329510 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1 @@
-pymodbus>=3.7.4
+pymodbus>=3.11.0
diff --git a/sun2000_modbus/inverter.py b/sun2000_modbus/inverter.py
index 0f02323..510b864 100644
--- a/sun2000_modbus/inverter.py
+++ b/sun2000_modbus/inverter.py
@@ -5,6 +5,7 @@
from pymodbus.exceptions import ModbusIOException, ConnectionException
from . import datatypes
+from .datatypes import DataType
from .registers import AccessType
logger = logging.getLogger(__name__)
@@ -17,9 +18,9 @@
class Sun2000:
- def __init__(self, host, port=502, timeout=5, wait=2, slave=0): # some models need slave=1
+ def __init__(self, host, port=502, timeout=5, wait=2, device_id=0): # some models need device_id=1
self.wait = wait
- self.slave = slave
+ self.device_id = device_id
self.inverter = ModbusTcpClient(host=host, port=port, timeout=timeout)
def connect(self):
@@ -48,31 +49,34 @@ def isConnected(self):
def connected(self):
return self.isConnected()
- def read_raw_value(self, register, slave=None):
+ def read_raw_value(self, register, device_id=None):
if not self.isConnected():
raise ValueError('Inverter is not connected')
try:
- register_value = self.inverter.read_holding_registers(address=register.value.address, count=register.value.quantity, slave=self.slave if slave is None else slave)
+ register_value = self.inverter.read_holding_registers(address=register.value.address, count=register.value.quantity, device_id=self.device_id if device_id is None else device_id)
if type(register_value) == ModbusIOException:
logger.error('Inverter unit did not respond')
raise register_value
except ConnectionException:
logger.error('A connection error occurred')
raise
+ except Exception:
+ logger.error(f'An error occurred during reading address {register.value.address}')
+ raise
return datatypes.decode(register_value.encode()[1:], register.value.data_type)
- def read(self, register, slave=None):
- raw_value = self.read_raw_value(register, slave)
+ def read(self, register, device_id=None):
+ raw_value = self.read_raw_value(register, device_id)
- if register.value.gain is None:
+ if register.value.gain is None or register.value.data_type in [DataType.STRING, DataType.BITFIELD16, DataType.BITFIELD32, DataType.MULTIDATA]:
return raw_value
else:
return raw_value / register.value.gain
- def read_formatted(self, register, slave=None, use_locale=False):
- value = self.read(register, slave)
+ def read_formatted(self, register, device_id=None, use_locale=False):
+ value = self.read(register, device_id)
if register.value.unit is not None:
if use_locale:
@@ -84,7 +88,7 @@ def read_formatted(self, register, slave=None, use_locale=False):
else:
return value
- def read_range(self, start_address, quantity=0, end_address=0, slave=None):
+ def read_range(self, start_address, quantity=0, end_address=0, device_id=None):
if quantity == 0 and end_address == 0:
raise ValueError('Either parameter quantity or end_address is required and must be greater than 0')
if quantity != 0 and end_address != 0:
@@ -98,17 +102,20 @@ def read_range(self, start_address, quantity=0, end_address=0, slave=None):
if end_address != 0:
quantity = end_address - start_address + 1
try:
- register_range_value = self.inverter.read_holding_registers(address=start_address, count=quantity, slave=self.slave if slave is None else slave)
+ register_range_value = self.inverter.read_holding_registers(address=start_address, count=quantity, device_id=self.device_id if device_id is None else device_id)
if type(register_range_value) == ModbusIOException:
logger.error('Inverter unit did not respond')
raise register_range_value
except ConnectionException:
logger.error('A connection error occurred')
raise
+ except Exception:
+ logger.error(f'An error occurred during reading starting from address {start_address}')
+ raise
return datatypes.decode(register_range_value.encode()[1:], datatypes.DataType.MULTIDATA)
- def write(self, register, value, slave=None):
+ def write(self, register, value, device_id=None):
if not self.isConnected():
raise ValueError('Inverter is not connected')
if not register.value.access_type in [AccessType.RW, AccessType.WO]:
@@ -118,7 +125,7 @@ def write(self, register, value, slave=None):
chunks = [int.from_bytes(encoded_value[i:i+2], byteorder='big', signed=False) for i in range(0, len(encoded_value), 2)]
try:
- response = self.inverter.write_registers(address=register.value.address, values=chunks, slave=self.slave if slave is None else slave)
+ response = self.inverter.write_registers(address=register.value.address, values=chunks, device_id=self.device_id if device_id is None else device_id)
if type(response) == ModbusIOException:
logger.error('Inverter unit did not respond')
raise response
diff --git a/sun2000_modbus/mappings.py b/sun2000_modbus/mappings.py
index f6c8e1b..130fbc7 100644
--- a/sun2000_modbus/mappings.py
+++ b/sun2000_modbus/mappings.py
@@ -1,119 +1,180 @@
DeviceStatus = {
- 0x0000: 'Standby: initializing',
- 0x0001: 'Standby: detecting insulation resistance',
- 0x0002: 'Standby: detecting irradiation',
- 0x0003: 'Standby: Grid detecting',
+ 0x0000: 'Standby: initialization',
+ 0x0001: 'Standby: insulation resistance detection',
+ 0x0002: 'Standby: sunlight detection',
+ 0x0003: 'Standby: grid detecting',
0x0100: 'Starting',
0x0200: 'On-grid',
- 0x0201: 'Grid connection: power limited',
- 0x0202: 'Grid connection: self-derating',
- 0x0203: 'Off-grid Running',
- 0x0300: 'Shutdown: fault',
- 0x0301: 'Shutdown: command',
- 0x0302: 'Shutdown: OVGR',
- 0x0303: 'Shutdown: communication disconnected',
- 0x0304: 'Shutdown: power limited',
- 0x0305: 'Shutdown: manual startup required',
- 0x0306: 'Shutdown: DC switches disconnected',
- 0x0307: 'Shutdown: rapid cutoff',
- 0x0308: 'Shutdown: input underpowered',
+ 0x0201: 'Grid connected: power limited',
+ 0x0202: 'Grid connected: self derating',
+ 0x0203: 'Off-grid operation',
+ 0x0300: 'OFF: unexpected shutdown',
+ 0x0301: 'OFF: instructed shutdown',
+ 0x0302: 'OFF: OVGR',
+ 0x0303: 'OFF: communication interrupted',
+ 0x0304: 'OFF: power limited',
+ 0x0305: 'OFF: manual startup required',
+ 0x0307: 'Shutdown: rapid shutdown',
+ 0x030A: 'Shutdown: commanded rapid shutdown',
+ 0x030B: 'Shutdown: the backup power system is abnormal',
+ # 0x030C is not officially documented, yet, but the Huawei support declared it as a valid status (https://www.photovoltaikforum.com/thread/160098-what-s-up-huawei/?postID=4478596#post4478596)
+ 0x030C: 'Shutdown: battery end-of-discharge SOC',
0x0401: 'Grid scheduling: cosPhi-P curve',
0x0402: 'Grid scheduling: Q-U curve',
0x0403: 'Grid scheduling: PF-U curve',
- 0x0404: 'Grid scheduling: dry contact',
0x0405: 'Grid scheduling: Q-P curve',
- 0x0500: 'Spot-check ready',
- 0x0501: 'Spot-checking',
- 0x0600: 'Inspecting',
- 0x0700: 'AFCI self check',
- 0x0800: 'I-V scanning',
- 0x0900: 'DC input detection',
- 0x0A00: 'Running: off-grid charging',
- 0xA000: 'Standby: no irradiation'
+ 0x0600: 'Inspecting ongoing',
+ 0x0700: 'AFCI check',
+ 0x0800: 'I-V curve scanning',
+ 0x0A00: 'Running: grid-disconnected and charged',
+ 0x0A01: 'Standby: the backup power system is abnormal',
+ 0xA000: 'Standby: no irradiation',
}
-RunningStatus = {
- 0: 'offline',
- 1: 'standby',
- 2: 'running',
- 3: 'fault',
- 4: 'sleep mode'
+LicenseStatus = {
+ 0x0000: 'No License',
+ 0x0001: 'Normal',
+ 0x0002: 'In grace period',
+ 0x0003: 'Revoked',
+ 0x0004: 'SN not match',
+ 0x0005: 'Expired',
}
-WorkingMode = {
- 0: 'none',
- 1: 'Forcible charge/discharge',
- 2: 'Time of Use (LG)',
- 3: 'Fixed charge/discharge',
- 4: 'Maximise self consumption',
- 5: 'Fully fed to grid',
- 6: 'Time of Use (LUNA2000)'
+ModuleStatus4G = {
+ 0x0000: 'Card not found',
+ 0x0001: 'Card registration failed',
+ 0x0002: 'No connection',
+ 0x0003: 'Low signal strength',
+ 0x0004: 'Medium signal strength',
+ 0x0005: 'High signal strength',
+ 0x0006: 'Connected',
+ 0x0100: 'Card in position',
+ 0x0101: 'PIN required',
+ 0x0102: 'PUK required',
+ 0xFFFF: 'Module not found',
}
-ProductModel = {
- 0: 'None',
- 1: 'LG-RESU',
- 2: 'HUAWEI-LUNA2000'
+PINVerificationStatus4G = {
+ 0x0000: 'Initial state',
+ 0x0001: 'Verifying...',
}
-WorkingModeSettings = {
- 0: 'Adaptive',
- 1: 'Fixed charge/discharge',
- 2: 'Maximise self consumption',
- 3: 'Time of Use (LG)',
- 4: 'Fully fed to grid',
- 5: 'Time of Use (LUNA2000)'
+ChargeDischargeMode = {
+ 0x0000: 'N/A',
+ 0x0001: 'Forced charge/discharge',
+ 0x0002: 'Time-of-use',
+ 0x0003: 'Fixed charge and discharge',
+ 0x0004: 'Max. self-consumption',
+ 0x0005: 'Fully fed to grid',
+ 0x0006: 'TOU',
+ 0x0007: 'Remote scheduling - Max. self-consumption',
+ 0x0008: 'Remote scheduling - Fully fed to grid',
+ 0x0009: 'Remote scheduling - TOU',
+ 0x000A: 'AI control',
+ 0x000B: 'Remote scheduling - AI control',
+ 0x000C: 'Three-party scheduling',
}
-ChargeFromGridFunction = {
- 0: 'Disable',
- 1: 'Enable'
+QUCharacteristicCurveMode = {
+ 0x0000: 'non-hysteresis',
+ 0x0001: 'hysteresis',
}
-ForcibleChargeDischarge = {
- 0: 'Stop',
- 1: 'Charge',
- 2: 'Discharge'
+RemoteChargeDischargeControlMode = {
+ 0x0000: 'Local control',
+ 0x0001: 'Remote control - Max. self-consumption',
+ 0x0002: 'Remote control - Fully fed to grid',
+ 0x0003: 'Remote control - TOU',
+ 0x0004: 'Remote control - AI control',
+ 0x0005: 'Remote control - Three-party scheduling',
+}
+
+PeakShaving = {
+ 0x0000: 'Disabled',
+ 0x0001: 'Active power limit',
+ 0x0002: 'Apparent power limit',
+}
+
+BackupBoxModel = {
+ 0x0000: 'Backup Box - B0/B1',
+ 0x0001: 'Compatible Third Party Backup Box',
+ 0x0002: 'SmartGuard',
+ 0x0003: 'No Backup Box',
+}
+
+RunningStatus = {
+ 0x0000: 'offline',
+ 0x0001: 'standby',
+ 0x0002: 'running',
+ 0x0003: 'fault',
+ 0x0004: 'sleep mode',
+}
+
+WorkingModeSettings = {
+ 0x0000: 'Adaptive',
+ 0x0001: 'Fixed charge/discharge',
+ 0x0002: 'Maximise self consumption',
+ 0x0003: 'Time of Use (LG)',
+ 0x0004: 'Fully fed to grid',
+ 0x0005: 'Time of Use (LUNA2000)',
}
-ForcibleChargeDischargeSettingMode = {
- 0: 'Duration'
+ForcibleChargeDischarge = {
+ 0x0000: 'Stop',
+ 0x0001: 'Charge',
+ 0x0002: 'Discharge',
}
ExcessPVEnergyUseInTOU = {
- 0: 'Fed to grid',
- 1: 'Charge'
+ 0x0000: 'Fed to grid',
+ 0x0001: 'Charge',
}
-SwitchToOffGrid = {
- 0: 'Switch from grid-tied to off-grid'
+ActivePowerControlMode = {
+ 0x0000: 'Unlimited',
+ 0x0001: 'DI active scheduling',
+ 0x0005: 'Zero power grid connection',
+ 0x0006: 'Power-limited grid connection (kW)',
+ 0x0007: 'Power-limited grid connection (%)',
}
VoltageIndependentOperation = {
- 0: '101 V',
- 1: '202 V'
+ 0x0000: '101 V',
+ 0x0001: '202 V',
}
-MeterStatus = {
- 0: 'offline',
- 1: 'online'
+ProductModel = {
+ 0x0000: 'None',
+ 0x0001: 'LG-RESU',
+ 0x0002: 'HUAWEI-LUNA2000',
+}
+
+WorkingMode = {
+ 0x0000: 'none',
+ 0x0001: 'Forcible charge/discharge',
+ 0x0002: 'Time of Use (LG)',
+ 0x0003: 'Fixed charge/discharge',
+ 0x0004: 'Maximise self consumption',
+ 0x0005: 'Fully fed to grid',
+ 0x0006: 'Time of Use (LUNA2000)',
+ 0x0007: 'Remote scheduling - maximum self-use',
+ 0x0008: 'Remote scheduling - full internet access',
+ 0x0009: 'Remote scheduling - TOU',
+ 0x000A: 'AI energy management and scheduling',
}
MeterType = {
- 0: 'single-phase',
- 1: 'three-phase'
+ 0x0000: 'single-phase',
+ 0x0001: 'three-phase',
}
-MeterModelDetectionResult = {
- 0: 'being identified',
- 1: 'The selected model is the same as the actual model of the connected meter',
- 2: 'The selected model is different from the actual model of the connected meter'
+MeterStatus = {
+ 0x0000: 'offline',
+ 0x0001: 'normal',
}
-ActivePowerControlMode = {
- 0: 'Unlimited',
- 1: 'DI active scheduling',
- 5: 'Zero power grid connection',
- 6: 'Powerlimited grid connection (kW)',
- 7: 'Powerlimited grid connection (%)'
+MeterModelDetectionResult = {
+ 0x0000: 'being identified',
+ 0x0001: 'The selected model is the same as the actual model of the connected meter',
+ 0x0002: 'The selected model is different from the actual model of the connected meter',
}
diff --git a/sun2000_modbus/registers.py b/sun2000_modbus/registers.py
index 17e54cb..8c0d170 100644
--- a/sun2000_modbus/registers.py
+++ b/sun2000_modbus/registers.py
@@ -33,10 +33,7 @@ class InverterEquipmentRegister(Enum):
Model = Register(30000, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
SN = Register(30015, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
PN = Register(30025, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- FirmwareVersion = Register(30035, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- SoftwareVersion = Register(30050, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- ProtocolVersion = Register(30068, 2, datatypes.DataType.UINT32_BE, None, None, AccessType.RO, None)
- ModelID = Register(30070, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ ModelID = Register(30070, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
NumberOfPVStrings = Register(30071, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
NumberOfMPPTrackers = Register(30072, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
RatedPower = Register(30073, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RO, None)
@@ -44,12 +41,24 @@ class InverterEquipmentRegister(Enum):
MaximumApparentPower = Register(30077, 2, datatypes.DataType.UINT32_BE, 1000, 'kVA', AccessType.RO, None)
MaximumReactivePowerFedToTheGrid = Register(30079, 2, datatypes.DataType.INT32_BE, 1000, 'kvar', AccessType.RO, None)
MaximumReactivePowerAbsorbedFromTheGrid = Register(30081, 2, datatypes.DataType.INT32_BE, 1000, 'kvar', AccessType.RO, None)
+ OfferingNameOfSouthboundDevice1 = Register(30561, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ OfferingNameOfSouthboundDevice2 = Register(30576, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ OfferingNameOfSouthboundDevice3 = Register(30591, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ HardwareVersion = Register(31000, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ MonitoringBoardSN = Register(31015, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ MonitoringSoftwareVersion = Register(31025, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ MasterDSPVersion = Register(31040, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ CPLDVersion = Register(31070, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ AFCIVersion = Register(31085, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ DCMBUSVersion = Register(31115, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ REGKEY = Register(31200, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
State1 = Register(32000, 1, datatypes.DataType.BITFIELD16, None, None, AccessType.RO, None)
State2 = Register(32002, 1, datatypes.DataType.BITFIELD16, None, None, AccessType.RO, None)
State3 = Register(32003, 2, datatypes.DataType.BITFIELD32, None, None, AccessType.RO, None)
Alarm1 = Register(32008, 1, datatypes.DataType.BITFIELD16, None, None, AccessType.RO, None)
Alarm2 = Register(32009, 1, datatypes.DataType.BITFIELD16, None, None, AccessType.RO, None)
Alarm3 = Register(32010, 1, datatypes.DataType.BITFIELD16, None, None, AccessType.RO, None)
+ ESN = Register(32015, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
PV1Voltage = Register(32016, 1, datatypes.DataType.INT16_BE, 10, 'V', AccessType.RO, None)
PV1Current = Register(32017, 1, datatypes.DataType.INT16_BE, 100, 'A', AccessType.RO, None)
PV2Voltage = Register(32018, 1, datatypes.DataType.INT16_BE, 10, 'V', AccessType.RO, None)
@@ -116,207 +125,248 @@ class InverterEquipmentRegister(Enum):
Efficiency = Register(32086, 1, datatypes.DataType.UINT16_BE, 100, '%', AccessType.RO, None)
InternalTemperature = Register(32087, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
InsulationResistance = Register(32088, 1, datatypes.DataType.UINT16_BE, 1000, 'MOhm', AccessType.RO, None)
- DeviceStatus = Register(32089, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, mappings.DeviceStatus)
- FaultCode = Register(32090, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
- StartupTime = Register(32091, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RO, None)
- ShutdownTime = Register(32093, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RO, None)
+ DeviceStatus = Register(32089, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, mappings.DeviceStatus)
+ FaultCode = Register(32090, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
+ StartupTime = Register(32091, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RO, None)
+ ShutdownTime = Register(32093, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RO, None)
AccumulatedEnergyYield = Register(32106, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
DailyEnergyYield = Register(32114, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
- ActiveAdjustmentMode = Register(35300, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
- ActiveAdjustmentValue = Register(35302, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RO, None)
- ActiveAdjustmentCommand = Register(35303, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
- ReactiveAdjustmentMode = Register(35304, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
- ReactiveAdjustmentValue = Register(35305, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RO, None)
- ReactiveAdjustmentCommand = Register(35307, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ ManagementSystemStatus = Register(35127, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ AuthorizationFunction = Register(35136, 2, datatypes.DataType.BITFIELD32, None, None, AccessType.RO, None)
+ LicenseStatus = Register(35138, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, mappings.LicenseStatus)
+ LicenseExpirationTime = Register(35139, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RO, None)
+ LicenseLoadingTime = Register(35141, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RO, None)
+ LicenseRevocationTime = Register(35143, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RO, None)
+ LicenseSN = Register(35145, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ RevocationCode = Register(35155, 64, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ ModuleStatus4G = Register(35249, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, mappings.ModuleStatus4G)
+ IPAddress4G = Register(35250, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RO, None)
+ SubnetMask4G = Register(35252, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RO, None)
+ IMEI4G = Register(35254, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ SignalStrength4G = Register(35264, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ MaximumNumberOfPINAttempts4G = Register(35265, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ PINVerificationStatus4G = Register(35266, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, mappings.PINVerificationStatus4G)
+ OriginalModelName = Register(35268, 15, datatypes.DataType.MULTIDATA, None, None, AccessType.RO, None)
+ ActiveAdjustmentMode = Register(35300, 4, datatypes.DataType.MULTIDATA, None, None, AccessType.RO, None)
+ ReactiveAdjustmentMode = Register(35304, 4, datatypes.DataType.MULTIDATA, None, None, AccessType.RO, None)
+ ChargeDischargeMode = Register(37006, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, mappings.ChargeDischargeMode)
PowerMeterCollectionActivePower = Register(37113, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
TotalNumberOfOptimizers = Register(37200, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
NumberOfOnlineOptimizers = Register(37201, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
FeatureData = Register(37202, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
- SystemTime = Register(40000, 2, datatypes.DataType.UINT32_BE, 1, None, AccessType.RW, None)
- QUCharacteristicCurveMode = Register(40037, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
- QUDispatchTriggerPower = Register(40038, 1, datatypes.DataType.UINT16_BE, 1, '%', AccessType.RW, None)
+ SystemTime = Register(40000, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RW, None)
+ QUCharacteristicCurveMode = Register(40037, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, mappings.QUCharacteristicCurveMode)
+ QUDispatchTriggerPower = Register(40038, 1, datatypes.DataType.INT16_BE, 1, '%', AccessType.RW, None)
FixedActivePowerDeratedInKW = Register(40120, 1, datatypes.DataType.UINT16_BE, 10, 'kW', AccessType.RW, None)
ReactivePowerCompensationInPF = Register(40122, 1, datatypes.DataType.INT16_BE, 1000, None, AccessType.RW, None)
ReactivePowerCompensationQS = Register(40123, 1, datatypes.DataType.INT16_BE, 1000, None, AccessType.RW, None)
- ActivePowerPercentageDerating = Register(40125, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
+ ActivePowerPercentageDerating = Register(40125, 1, datatypes.DataType.INT16_BE, 10, '%', AccessType.RW, None)
FixedActivePowerDeratedInW = Register(40126, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
ReactivePowerCompensationAtNight = Register(40129, 2, datatypes.DataType.INT32_BE, 1000, 'kvar', AccessType.RW, None)
CosPhiPPnCharacteristicCurve = Register(40133, 21, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
QUCharacteristicCurve = Register(40154, 21, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
PFUCharacteristicCurve = Register(40175, 21, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
ReactivePowerAdjustmentTime = Register(40196, 1, datatypes.DataType.UINT16_BE, 1, 's', AccessType.RW, None)
- QUPowerPercentageToExitScheduling = Register(40198, 1, datatypes.DataType.UINT16_BE, 1, '%', AccessType.RW, None)
- Startup = Register(40200, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.WO, None)
- Shutdown = Register(40201, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.WO, None)
- GridCode = Register(42000, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ QUPowerPercentageToExitScheduling = Register(40198, 1, datatypes.DataType.INT16_BE, 1, '%', AccessType.RW, None)
+ Startup = Register(40200, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.WO, None)
+ Shutdown = Register(40201, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.WO, None)
+ GridCode = Register(42000, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
ReactivePowerChangeGradient = Register(42015, 2, datatypes.DataType.UINT32_BE, 1000, '%/s', AccessType.RW, None)
ActivePowerChangeGradient = Register(42017, 2, datatypes.DataType.UINT32_BE, 1000, '%/s', AccessType.RW, None)
ScheduleInstructionValidDuration = Register(42019, 2, datatypes.DataType.UINT32_BE, 1, 's', AccessType.RW, None)
+ ActivePowerLimit = Register(42405, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
TimeZone = Register(43006, 1, datatypes.DataType.INT16_BE, 1, 'min', AccessType.RW, None)
+ TLSEncryption = Register(43098, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
+ WLANWakeup = Register(45052, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
+ FastPowerScheduling = Register(45086, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
+ BatteryChargingMode = Register(47086, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
+ BatteryChargeAndDischargePower = Register(47321, 1, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
+ RemoteChargeDischargeControlMode = Register(47589, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, mappings.RemoteChargeDischargeControlMode)
+ ScheduledTask = Register(47674, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
+ DefaultMaximumFeedInPower = Register(47675, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
+ DefaultActivePowerChangeGradient = Register(47677, 2, datatypes.DataType.UINT32_BE, 1000, '%/s', AccessType.RW, None)
+ PeakShaving = Register(47954, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, mappings.PeakShaving)
+ BackupPowerSOCForPeakShaving = Register(47955, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
+ PeakPower = Register(47956, 64, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
+ AIOpticalStorage = Register(48020, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
+ BackupBoxModel = Register(48089, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, mappings.BackupBoxModel)
+ PhaseToGroundCircuitProtection = Register(48090, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
class BatteryEquipmentRegister(Enum):
# Overall
+ ProductModel = Register(47106, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
RunningStatus = Register(37762, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, mappings.RunningStatus)
WorkingModeSettings = Register(47086, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.WorkingModeSettings)
BusVoltage = Register(37763, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
BusCurrent = Register(37764, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
ChargeDischargePower = Register(37765, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- MaximumChargePower = Register(37046, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- MaximumDischargePower = Register(37048, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- RatedCapacity = Register(37758, 2, datatypes.DataType.INT32_BE, 1, 'Wh', AccessType.RO, None)
+ MaximumChargePower = Register(37046, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RO, None)
+ MaximumDischargePower = Register(37048, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RO, None)
+ RatedCapacity = Register(37758, 2, datatypes.DataType.UINT32_BE, 1, 'Wh', AccessType.RO, None)
SOC = Register(37760, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
BackupPowerSOC = Register(47102, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
- TotalCharge = Register(37780, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- TotalDischarge = Register(37782, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- CurrentDayChargeCapacity = Register(37784, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- CurrentDayDischargeCapacity = Register(37786, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- TimeOfUseElectricityPricePeriods = Register(47028, 41, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
- MaximumChargingPower = Register(47075, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
- MaximumDischargingPower = Register(47077, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
+ TargetSOC = Register(47101, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
+ TotalCharge = Register(37780, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ TotalDischarge = Register(37782, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ CurrentDayChargeCapacity = Register(37784, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ CurrentDayDischargeCapacity = Register(37786, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ TimeOfUseElectricityPricePeriods = Register(47028, 41, datatypes.DataType.MULTIDATA, 1, None, AccessType.RW, None)
+ MaximumChargingPower = Register(47075, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
+ MaximumDischargingPower = Register(47077, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
ChargingCutoffCapacity = Register(47081, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
DischargeCutoffCapacity = Register(47082, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
- ForcedChargingAndDischargingPeriod = Register(47083, 1, datatypes.DataType.UINT16_BE, 1, 'minutes', AccessType.RW, None)
- ChargeFromGridFunction = Register(47087, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ChargeFromGridFunction)
+ ForcedChargingAndDischargingPeriod = Register(47083, 1, datatypes.DataType.UINT16_BE, 1, 'mins', AccessType.RW, None)
+ ForcedChargingAndDischargingPower = Register(47084, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
+ ChargeFromGridFunction = Register(47087, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
GridChargeCutoffSOC = Register(47088, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RW, None)
- ForcibleChargeDischarge = Register(47100, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.WO, mappings.ForcibleChargeDischarge)
- FixedChargingAndDischargingPeriods = Register(47200, 41, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
- PowerOfChargeFromGrid = Register(47242, 2, datatypes.DataType.INT32_BE, 0.1, 'W', AccessType.RW, None)
- MaximumPowerOfChargeFromGrid = Register(47244, 2, datatypes.DataType.INT32_BE, 0.1, 'W', AccessType.RW, None)
- ForcibleChargeDischargeSettingMode = Register(47246, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ForcibleChargeDischargeSettingMode)
- ForcibleChargePower = Register(47247, 2, datatypes.DataType.INT32_BE, 0.1, 'W', AccessType.RW, None)
- ForcibleDischargePower = Register(47249, 2, datatypes.DataType.INT32_BE, 0.1, 'W', AccessType.RW, None)
- TimeOfUseChargingAndDischargingPeriods = Register(47255, 43, datatypes.DataType.MULTIDATA, None, None, AccessType.RW, None)
+ ForcibleChargeDischarge = Register(47100, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ForcibleChargeDischarge)
+ FixedChargingAndDischargingPeriods = Register(47200, 41, datatypes.DataType.MULTIDATA, 1, None, AccessType.RW, None)
+ PowerOfChargeFromGrid = Register(47242, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
+ MaximumPowerOfChargeFromGrid = Register(47244, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
+ ForcibleChargeDischargeSettingMode = Register(47246, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ ForcibleChargePower = Register(47247, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
+ ForcibleDischargePower = Register(47249, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
+ TimeOfUseChargingAndDischargingPeriods = Register(47255, 43, datatypes.DataType.MULTIDATA, 1, None, AccessType.RW, None)
ExcessPVEnergyUseInTOU = Register(47299, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ExcessPVEnergyUseInTOU)
ActivePowerControlMode = Register(47415, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ActivePowerControlMode)
- MaximumFeedGridPowerInKW = Register(47416, 2, datatypes.DataType.INT32_BE, 1000, 'kW', AccessType.RW, None)
+ MaximumFeedGridPowerInW = Register(47416, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RW, None)
MaximumFeedGridPowerInPercentage = Register(47418, 1, datatypes.DataType.INT16_BE, 10, '%', AccessType.RW, None)
- MaximumChargeFromGridPower = Register(47590, 2, datatypes.DataType.INT32_BE, 0.1, 'W', AccessType.RW, None)
- SwitchToOffGrid = Register(47604, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.SwitchToOffGrid)
- VoltageInIndependentOperation = Register(47605, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.VoltageIndependentOperation)
+ MaximumChargeFromGridPower = Register(47590, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RW, None)
+ SwitchToOffGrid = Register(47604, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ VoltageInIndependentOperation = Register(47605, 1, datatypes.DataType.UINT16_BE, 1, 'V', AccessType.RW, mappings.VoltageIndependentOperation)
+ SOHCalibrationStatus = Register(37926, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ SOHCalibrationReleaseTheLowerDischargeLimitOfSOC = Register(37927, 1, datatypes.DataType.UINT16_BE, 10, None, AccessType.RO, None)
+ SOHCalibrationEnableTheBackupPowerSOC = Register(37928, 1, datatypes.DataType.UINT16_BE, 10, None, AccessType.RO, None)
# Unit 1
Unit1ProductModel = Register(47000, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ProductModel)
- Unit1SN = Register(37052, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ Unit1SN = Register(37052, 10, datatypes.DataType.STRING, 1, None, AccessType.RO, None)
Unit1No = Register(47107, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
- Unit1SoftwareVersion = Register(37814, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1DCDCVersion = Register(37026, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BMSVersion = Register(37036, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ Unit1SoftwareVersion = Register(37814, 15, datatypes.DataType.STRING, 1, None, AccessType.RO, None)
+ Unit1DCDCVersion = Register(37026, 10, datatypes.DataType.STRING, 1, None, AccessType.RO, None)
+ Unit1BMSVersion = Register(37036, 10, datatypes.DataType.STRING, 1, None, AccessType.RO, None)
Unit1RunningStatus = Register(37000, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, mappings.RunningStatus)
Unit1WorkingMode = Register(37006, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, mappings.WorkingMode)
Unit1BusVoltage = Register(37003, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit1BusCurrent = Register(37021, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit1BatterySOC = Register(37004, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit1ChargeAndDischargePower = Register(37001, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit1RemainingChargeDischargeTime = Register(37025, 1, datatypes.DataType.UINT16_BE, 1, 'minutes', AccessType.RO, None)
- Unit1RatedChargePower = Register(37007, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit1RatedDischargePower = Register(37009, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit1CurrentDayChargeCapacity = Register(37015, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit1CurrentDayDischargeCapacity = Register(37017, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit1TotalCharge = Register(37066, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit1TotalDischarge = Register(37068, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1RemainingChargeDischargeTime = Register(37025, 1, datatypes.DataType.UINT16_BE, 1, 'mins', AccessType.RO, None)
+ Unit1RatedChargePower = Register(37007, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RO, None)
+ Unit1RatedDischargePower = Register(37009, 2, datatypes.DataType.UINT32_BE, 1, 'W', AccessType.RO, None)
+ Unit1CurrentDayChargeCapacity = Register(37015, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1CurrentDayDischargeCapacity = Register(37017, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1TotalCharge = Register(37066, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1TotalDischarge = Register(37068, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit1BatteryTemperature = Register(37022, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit1FaultID = Register(37014, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
# Unit 2
Unit2ProductModel = Register(47089, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, mappings.ProductModel)
- Unit2SN = Register(37700, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ Unit2SN = Register(37700, 10, datatypes.DataType.STRING, 1, None, AccessType.RO, None)
Unit2No = Register(47108, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
- Unit2SoftwareVersion = Register(37799, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
+ Unit2SoftwareVersion = Register(37799, 15, datatypes.DataType.STRING, 1, None, AccessType.RO, None)
Unit2RunningStatus = Register(37741, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, mappings.RunningStatus)
Unit2BusVoltage = Register(37750, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit2BusCurrent = Register(37751, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit2BatterySOC = Register(37738, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit2ChargeAndDischargePower = Register(37743, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit2CurrentDayChargeCapacity = Register(37746, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit2CurrentDayDischargeCapacity = Register(37748, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit2TotalCharge = Register(37753, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit2TotalDischarge = Register(37755, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2CurrentDayChargeCapacity = Register(37746, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2CurrentDayDischargeCapacity = Register(37748, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2TotalCharge = Register(37753, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2TotalDischarge = Register(37755, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit2BatteryTemperature = Register(37752, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
# Unit 1 BatteryPack 1
Unit1BatteryPack1SN = Register(38200, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BatteryPack1No = Register(47750, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ Unit1BatteryPack1No = Register(47750, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
Unit1BatteryPack1FirmwareVersion = Register(38210, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BatteryPack1WorkingStatus = Register(38228, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ Unit1BatteryPack1WorkingStatus = Register(38228, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
Unit1BatteryPack1Voltage = Register(38235, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit1BatteryPack1Current = Register(38236, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit1BatteryPack1SOC = Register(38229, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit1BatteryPack1ChargeDischargePower = Register(38233, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit1BatteryPack1TotalCharge = Register(38238, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit1BatteryPack1TotalDischarge = Register(38240, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1BatteryPack1TotalCharge = Register(38238, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1BatteryPack1TotalDischarge = Register(38240, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit1BatteryPack1MinimumTemperature = Register(38453, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit1BatteryPack1MaximumTemperature = Register(38452, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
+ Unit1BatteryPack1SOHCalibrationStatus = Register(37920, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
# Unit 1 BatteryPack 2
Unit1BatteryPack2SN = Register(38242, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BatteryPack2No = Register(47751, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ Unit1BatteryPack2No = Register(47751, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
Unit1BatteryPack2FirmwareVersion = Register(38252, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BatteryPack2WorkingStatus = Register(38270, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ Unit1BatteryPack2WorkingStatus = Register(38270, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
Unit1BatteryPack2Voltage = Register(38277, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit1BatteryPack2Current = Register(38278, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit1BatteryPack2SOC = Register(38271, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit1BatteryPack2ChargeDischargePower = Register(38275, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit1BatteryPack2TotalCharge = Register(38280, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit1BatteryPack2TotalDischarge = Register(38282, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1BatteryPack2TotalCharge = Register(38280, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1BatteryPack2TotalDischarge = Register(38282, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit1BatteryPack2MinimumTemperature = Register(38455, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit1BatteryPack2MaximumTemperature = Register(38454, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
+ Unit1BatteryPack2SOHCalibrationStatus = Register(37921, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
# Unit 1 BatteryPack 3
Unit1BatteryPack3SN = Register(38284, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BatteryPack3No = Register(47752, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ Unit1BatteryPack3No = Register(47752, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
Unit1BatteryPack3FirmwareVersion = Register(38294, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit1BatteryPack3WorkingStatus = Register(38312, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ Unit1BatteryPack3WorkingStatus = Register(38312, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
Unit1BatteryPack3Voltage = Register(38319, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit1BatteryPack3Current = Register(38320, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit1BatteryPack3SOC = Register(38313, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit1BatteryPack3ChargeDischargePower = Register(38317, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit1BatteryPack3TotalCharge = Register(38322, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit1BatteryPack3TotalDischarge = Register(38324, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1BatteryPack3TotalCharge = Register(38322, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit1BatteryPack3TotalDischarge = Register(38324, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit1BatteryPack3MinimumTemperature = Register(38457, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit1BatteryPack3MaximumTemperature = Register(38456, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
+ Unit1BatteryPack3SOHCalibrationStatus = Register(37922, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
# Unit 2 BatteryPack 1
Unit2BatteryPack1SN = Register(38326, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit2BatteryPack1No = Register(47753, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ Unit2BatteryPack1No = Register(47753, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
Unit2BatteryPack1FirmwareVersion = Register(38336, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit2BatteryPack1WorkingStatus = Register(38354, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ Unit2BatteryPack1WorkingStatus = Register(38354, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
Unit2BatteryPack1Voltage = Register(38361, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit2BatteryPack1Current = Register(38362, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit2BatteryPack1SOC = Register(38355, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit2BatteryPack1ChargeDischargePower = Register(38359, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit2BatteryPack1TotalCharge = Register(38364, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit2BatteryPack1TotalDischarge = Register(38366, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2BatteryPack1TotalCharge = Register(38364, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2BatteryPack1TotalDischarge = Register(38366, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit2BatteryPack1MinimumTemperature = Register(38459, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit2BatteryPack1MaximumTemperature = Register(38458, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
+ Unit2BatteryPack1SOHCalibrationStatus = Register(37923, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
# Unit 2 BatteryPack 2
Unit2BatteryPack2SN = Register(38368, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit2BatteryPack2No = Register(47754, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ Unit2BatteryPack2No = Register(47754, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
Unit2BatteryPack2FirmwareVersion = Register(38378, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit2BatteryPack2WorkingStatus = Register(38396, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ Unit2BatteryPack2WorkingStatus = Register(38396, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
Unit2BatteryPack2Voltage = Register(38403, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit2BatteryPack2Current = Register(38404, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit2BatteryPack2SOC = Register(38397, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit2BatteryPack2ChargeDischargePower = Register(38401, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit2BatteryPack2TotalCharge = Register(38406, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit2BatteryPack2TotalDischarge = Register(38408, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2BatteryPack2TotalCharge = Register(38406, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2BatteryPack2TotalDischarge = Register(38408, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit2BatteryPack2MinimumTemperature = Register(38461, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit2BatteryPack2MaximumTemperature = Register(38460, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
+ Unit2BatteryPack2SOHCalibrationStatus = Register(37924, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
# Unit 2 BatteryPack 3
Unit2BatteryPack3SN = Register(38410, 10, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit2BatteryPack3No = Register(47755, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RW, None)
+ Unit2BatteryPack3No = Register(47755, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RW, None)
Unit2BatteryPack3FirmwareVersion = Register(38420, 15, datatypes.DataType.STRING, None, None, AccessType.RO, None)
- Unit2BatteryPack3WorkingStatus = Register(38438, 1, datatypes.DataType.UINT16_BE, 1, None, AccessType.RO, None)
+ Unit2BatteryPack3WorkingStatus = Register(38438, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
Unit2BatteryPack3Voltage = Register(38445, 1, datatypes.DataType.UINT16_BE, 10, 'V', AccessType.RO, None)
Unit2BatteryPack3Current = Register(38446, 1, datatypes.DataType.INT16_BE, 10, 'A', AccessType.RO, None)
Unit2BatteryPack3SOC = Register(38439, 1, datatypes.DataType.UINT16_BE, 10, '%', AccessType.RO, None)
Unit2BatteryPack3ChargeDischargePower = Register(38443, 2, datatypes.DataType.INT32_BE, 1, 'W', AccessType.RO, None)
- Unit2BatteryPack3TotalCharge = Register(38448, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- Unit2BatteryPack3TotalDischarge = Register(38450, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2BatteryPack3TotalCharge = Register(38448, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
+ Unit2BatteryPack3TotalDischarge = Register(38450, 2, datatypes.DataType.UINT32_BE, 100, 'kWh', AccessType.RO, None)
Unit2BatteryPack3MinimumTemperature = Register(38463, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
Unit2BatteryPack3MaximumTemperature = Register(38462, 1, datatypes.DataType.INT16_BE, 10, '°C', AccessType.RO, None)
+ Unit2BatteryPack3SOHCalibrationStatus = Register(37925, 1, datatypes.DataType.UINT16_BE, None, None, AccessType.RO, None)
class MeterEquipmentRegister(Enum):
@@ -335,7 +385,7 @@ class MeterEquipmentRegister(Enum):
GridFrequency = Register(37118, 1, datatypes.DataType.INT16_BE, 100, 'Hz', AccessType.RO, None)
PositiveActiveElectricity = Register(37119, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
ReverseActivePower = Register(37121, 2, datatypes.DataType.INT32_BE, 100, 'kWh', AccessType.RO, None)
- AccumulatedReactivePower = Register(37123, 2, datatypes.DataType.INT32_BE, 100, 'kvar', AccessType.RO, None)
+ AccumulatedReactivePower = Register(37123, 2, datatypes.DataType.INT32_BE, 100, 'kvarh', AccessType.RO, None)
ABLineVoltage = Register(37126, 2, datatypes.DataType.INT32_BE, 10, 'V', AccessType.RO, None)
BCLineVoltage = Register(37128, 2, datatypes.DataType.INT32_BE, 10, 'V', AccessType.RO, None)
CALineVoltage = Register(37130, 2, datatypes.DataType.INT32_BE, 10, 'V', AccessType.RO, None)
diff --git a/tests/sun2000mock.py b/tests/sun2000mock.py
index 0c4de52..851a9be 100644
--- a/tests/sun2000mock.py
+++ b/tests/sun2000mock.py
@@ -34,23 +34,23 @@ def encode(self):
}
-def mock_read_holding_registers(self, address, count, slave):
+def mock_read_holding_registers(self, address, count, device_id):
return MockedResponse(address, count)
-def mock_read_holding_registers_ModbusIOException(self, address, count, slave):
- return ModbusIOException('Requested slave is not available')
+def mock_read_holding_registers_ModbusIOException(self, address, count, device_id):
+ return ModbusIOException('Requested device is not available')
-def mock_read_holding_registers_ConnectionException(self, address, count, slave):
+def mock_read_holding_registers_ConnectionException(self, address, count, device_id):
raise ConnectionException('Connection unexpectedly closed')
-def mock_write_registers_ModbusIOException(self, address, values, slave):
- return ModbusIOException('Requested slave is not available')
+def mock_write_registers_ModbusIOException(self, address, values, device_id):
+ return ModbusIOException('Requested device is not available')
-def mock_write_registers_ConnectionException(self, address, values, slave):
+def mock_write_registers_ConnectionException(self, address, values, device_id):
raise ConnectionException('Connection unexpectedly closed')
diff --git a/tests/test_sun2000_modbus.py b/tests/test_sun2000_modbus.py
index 58af96b..da50b7d 100644
--- a/tests/test_sun2000_modbus.py
+++ b/tests/test_sun2000_modbus.py
@@ -82,14 +82,14 @@ def test_decode_invalid(self):
class TestSun2000(unittest.TestCase):
def setUp(self) -> None:
- self.test_inverter = Sun2000(host='192.168.8.1', port=123, timeout=3, wait=0, slave=1)
+ self.test_inverter = Sun2000(host='192.168.8.1', port=123, timeout=3, wait=0, device_id=1)
def test_init(self):
self.assertEqual(self.test_inverter.inverter.comm_params.host, '192.168.8.1')
self.assertEqual(self.test_inverter.inverter.comm_params.port, 123)
self.assertEqual(self.test_inverter.inverter.comm_params.timeout_connect, 3)
self.assertEqual(self.test_inverter.wait, 0)
- self.assertEqual(self.test_inverter.slave, 1)
+ self.assertEqual(self.test_inverter.device_id, 1)
self.assertEqual(self.test_inverter.isConnected(), False)
@patch(
@@ -131,7 +131,7 @@ def test_read_raw_value_string_from_unavailable_unit(self):
self.test_inverter.connect()
with self.assertRaises(ModbusIOException) as cm:
self.test_inverter.read_raw_value(InverterEquipmentRegister.Model)
- self.assertEqual(str(cm.exception), 'Modbus Error: [Input/Output] Requested slave is not available')
+ self.assertEqual(str(cm.exception), 'Modbus Error: [Input/Output] Requested device is not available')
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers', sun2000mock.mock_read_holding_registers_ConnectionException
@@ -157,10 +157,10 @@ def test_read_raw_value_string_connection_unexpectedly_closed(self):
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_raw_value_without_slave_argument_takes_default(self, mock_read_holding_registers):
+ def test_read_raw_value_without_device_id_argument_takes_default(self, mock_read_holding_registers):
self.test_inverter.connect()
self.test_inverter.read_raw_value(InverterEquipmentRegister.Model)
- mock_read_holding_registers.assert_called_once_with(address=30000, count=15, slave=1)
+ mock_read_holding_registers.assert_called_once_with(address=30000, count=15, device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers'
@@ -171,10 +171,10 @@ def test_read_raw_value_without_slave_argument_takes_default(self, mock_read_hol
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_raw_value_with_slave_argument(self, mock_read_holding_registers):
+ def test_read_raw_value_with_device_id_argument(self, mock_read_holding_registers):
self.test_inverter.connect()
- self.test_inverter.read_raw_value(InverterEquipmentRegister.Model, slave=123)
- mock_read_holding_registers.assert_called_once_with(address=30000, count=15, slave=123)
+ self.test_inverter.read_raw_value(InverterEquipmentRegister.Model, device_id=123)
+ mock_read_holding_registers.assert_called_once_with(address=30000, count=15, device_id=123)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers', sun2000mock.mock_read_holding_registers
@@ -227,10 +227,10 @@ def test_read_raw_value_uint32be(self):
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_without_slave_argument_takes_default(self, mock_read_holding_registers):
+ def test_read_without_device_id_argument_takes_default(self, mock_read_holding_registers):
self.test_inverter.connect()
self.test_inverter.read(InverterEquipmentRegister.RatedPower)
- mock_read_holding_registers.assert_called_once_with(address=30073, count=2, slave=1)
+ mock_read_holding_registers.assert_called_once_with(address=30073, count=2, device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers'
@@ -241,10 +241,10 @@ def test_read_without_slave_argument_takes_default(self, mock_read_holding_regis
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_with_slave_argument(self, mock_read_holding_registers):
+ def test_read_with_device_id_argument(self, mock_read_holding_registers):
self.test_inverter.connect()
- self.test_inverter.read(InverterEquipmentRegister.RatedPower, slave=123)
- mock_read_holding_registers.assert_called_once_with(address=30073, count=2, slave=123)
+ self.test_inverter.read(InverterEquipmentRegister.RatedPower, device_id=123)
+ mock_read_holding_registers.assert_called_once_with(address=30073, count=2, device_id=123)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers', sun2000mock.mock_read_holding_registers
@@ -269,10 +269,10 @@ def test_read_uint32be(self):
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_formatted_without_slave_argument_takes_default(self, mock_read_holding_registers):
+ def test_read_formatted_without_device_id_argument_takes_default(self, mock_read_holding_registers):
self.test_inverter.connect()
self.test_inverter.read_formatted(InverterEquipmentRegister.RatedPower)
- mock_read_holding_registers.assert_called_once_with(address=30073, count=2, slave=1)
+ mock_read_holding_registers.assert_called_once_with(address=30073, count=2, device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers'
@@ -283,10 +283,10 @@ def test_read_formatted_without_slave_argument_takes_default(self, mock_read_hol
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_formatted_with_slave_argument(self, mock_read_holding_registers):
+ def test_read_formatted_with_device_id_argument(self, mock_read_holding_registers):
self.test_inverter.connect()
- self.test_inverter.read_formatted(InverterEquipmentRegister.RatedPower, slave=123)
- mock_read_holding_registers.assert_called_once_with(address=30073, count=2, slave=123)
+ self.test_inverter.read_formatted(InverterEquipmentRegister.RatedPower, device_id=123)
+ mock_read_holding_registers.assert_called_once_with(address=30073, count=2, device_id=123)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers', sun2000mock.mock_read_holding_registers
@@ -396,10 +396,10 @@ def test_read_returns_float(self):
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_range_without_slave_argument_takes_default(self, mock_read_holding_registers):
+ def test_read_range_without_device_id_argument_takes_default(self, mock_read_holding_registers):
self.test_inverter.connect()
self.test_inverter.read_range(30000, quantity=35)
- mock_read_holding_registers.assert_called_once_with(address=30000, count=35, slave=1)
+ mock_read_holding_registers.assert_called_once_with(address=30000, count=35, device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers'
@@ -410,10 +410,10 @@ def test_read_range_without_slave_argument_takes_default(self, mock_read_holding
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_read_range_with_slave_argument(self, mock_read_holding_registers):
+ def test_read_range_with_device_id_argument(self, mock_read_holding_registers):
self.test_inverter.connect()
- self.test_inverter.read_range(30000, quantity=35, slave=123)
- mock_read_holding_registers.assert_called_once_with(address=30000, count=35, slave=123)
+ self.test_inverter.read_range(30000, quantity=35, device_id=123)
+ mock_read_holding_registers.assert_called_once_with(address=30000, count=35, device_id=123)
@patch(
'pymodbus.client.ModbusTcpClient.read_holding_registers', sun2000mock.mock_read_holding_registers
@@ -509,7 +509,7 @@ def test_read_range_from_unavailable_unit2(self):
self.test_inverter.connect()
with self.assertRaises(ModbusIOException) as cm:
self.test_inverter.read_range(30000, quantity=35)
- self.assertEqual(str(cm.exception), 'Modbus Error: [Input/Output] Requested slave is not available')
+ self.assertEqual(str(cm.exception), 'Modbus Error: [Input/Output] Requested device is not available')
@patch(
'pymodbus.client.ModbusTcpClient.connect', sun2000mock.connect_fail
@@ -533,7 +533,7 @@ def test_write_to_unavailable_unit(self):
self.test_inverter.connect()
with self.assertRaises(ModbusIOException) as cm:
self.test_inverter.write(BatteryEquipmentRegister.BackupPowerSOC, 10)
- self.assertEqual(str(cm.exception), 'Modbus Error: [Input/Output] Requested slave is not available')
+ self.assertEqual(str(cm.exception), 'Modbus Error: [Input/Output] Requested device is not available')
@patch(
'pymodbus.client.ModbusTcpClient.connect', sun2000mock.connect_success
@@ -571,10 +571,10 @@ def test_write_uint16be_connection_unexpectedly_closed(self):
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_write_without_slave_argument_takes_default(self, write_registers_mock):
+ def test_write_without_device_id_argument_takes_default(self, write_registers_mock):
self.test_inverter.connect()
self.test_inverter.write(BatteryEquipmentRegister.BackupPowerSOC, 10)
- write_registers_mock.assert_called_once_with(address=47102, values=[10], slave=1)
+ write_registers_mock.assert_called_once_with(address=47102, values=[10], device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'
@@ -585,10 +585,10 @@ def test_write_without_slave_argument_takes_default(self, write_registers_mock):
@patch(
'pymodbus.client.ModbusTcpClient.is_socket_open', sun2000mock.connect_success
)
- def test_write_with_slave_argument(self, write_registers_mock):
+ def test_write_with_device_id_argument(self, write_registers_mock):
self.test_inverter.connect()
- self.test_inverter.write(BatteryEquipmentRegister.BackupPowerSOC, 10, slave=123)
- write_registers_mock.assert_called_once_with(address=47102, values=[10], slave=123)
+ self.test_inverter.write(BatteryEquipmentRegister.BackupPowerSOC, 10, device_id=123)
+ write_registers_mock.assert_called_once_with(address=47102, values=[10], device_id=123)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'
@@ -602,7 +602,7 @@ def test_write_with_slave_argument(self, write_registers_mock):
def test_write_uint16be(self, write_registers_mock):
self.test_inverter.connect()
self.test_inverter.write(BatteryEquipmentRegister.BackupPowerSOC, 10)
- write_registers_mock.assert_called_once_with(address=47102, values=[10], slave=1)
+ write_registers_mock.assert_called_once_with(address=47102, values=[10], device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'
@@ -616,7 +616,7 @@ def test_write_uint16be(self, write_registers_mock):
def test_write_uint32be(self, write_registers_mock):
self.test_inverter.connect()
self.test_inverter.write(InverterEquipmentRegister.FixedActivePowerDeratedInW, 10200)
- write_registers_mock.assert_called_once_with(address=40126, values=[0, 10200], slave=1)
+ write_registers_mock.assert_called_once_with(address=40126, values=[0, 10200], device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'
@@ -630,7 +630,7 @@ def test_write_uint32be(self, write_registers_mock):
def test_write_int16be(self, write_registers_mock):
self.test_inverter.connect()
self.test_inverter.write(BatteryEquipmentRegister.MaximumFeedGridPowerInPercentage, -90)
- write_registers_mock.assert_called_once_with(address=47418, values=[65446], slave=1)
+ write_registers_mock.assert_called_once_with(address=47418, values=[65446], device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'
@@ -643,8 +643,8 @@ def test_write_int16be(self, write_registers_mock):
)
def test_write_int32be(self, write_registers_mock):
self.test_inverter.connect()
- self.test_inverter.write(BatteryEquipmentRegister.MaximumChargeFromGridPower, -10200)
- write_registers_mock.assert_called_once_with(address=47590, values=[65535, 55336], slave=1)
+ self.test_inverter.write(BatteryEquipmentRegister.MaximumFeedGridPowerInW, -10200)
+ write_registers_mock.assert_called_once_with(address=47416, values=[65535, 55336], device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'
@@ -658,7 +658,7 @@ def test_write_int32be(self, write_registers_mock):
def test_write_multidata(self, write_registers_mock):
self.test_inverter.connect()
self.test_inverter.write(InverterEquipmentRegister.CosPhiPPnCharacteristicCurve, b'\x01\x02\x03\x04')
- write_registers_mock.assert_called_once_with(address=40133, values=[258, 772], slave=1)
+ write_registers_mock.assert_called_once_with(address=40133, values=[258, 772], device_id=1)
@patch(
'pymodbus.client.ModbusTcpClient.write_registers'