Skip to content

Commit

Permalink
Fix DT inverter test
Browse files Browse the repository at this point in the history
  • Loading branch information
mletenay committed Dec 27, 2024
1 parent 8ba238d commit ab01a89
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 62 deletions.
92 changes: 41 additions & 51 deletions goodwe/dt.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class DT(Inverter):
Integer("warning_code", 30132, "Warning code"),
Apparent4("apparent_power", 30133, "Apparent Power", Kind.AC),
Reactive4("reactive_power", 30135, "Reactive Power", Kind.AC),
# 30137 reserved
PowerS("total_input_power", 30138, "Total Input Power", Kind.PV),
Decimal("power_factor", 30139, 1000, "Power Factor", "", Kind.GRID),
# 30140 inverter efficiency
Expand All @@ -97,7 +98,7 @@ class DT(Inverter):
# 30159 reserved
# 30160 reserved
# 30161 reserved
Integer("functionbit", 30162, "FunctionBit", "", Kind.PV),
Integer("funbit", 30162, "FunctionBit", "", Kind.PV),
Voltage("vbus", 30163, "Bus Voltage", Kind.PV),
Voltage("vnbus", 30164, "NBus Voltage", Kind.PV),
Long("derating_mode", 30165, "Derating Mode code"),
Expand All @@ -117,9 +118,6 @@ class DT(Inverter):
Energy4W("meter_e_total_exp", 30197, "Meter Total Energy (export)", Kind.GRID),
Energy4W("meter_e_total_imp", 30199, "Meter Total Energy (import)", Kind.GRID),
Integer("meter_comm_status", 30209, "Meter Communication Status"), # 1 OK, 0 NotOK



)

# Modbus registers of inverter settings, offsets are modbus register addresses
Expand Down Expand Up @@ -150,8 +148,9 @@ class DT(Inverter):
)

def __init__(self, host: str, port: int, comm_addr: int = 0, timeout: int = 1, retries: int = 3):
super().__init__(host, port, comm_addr if comm_addr else 0xf7, timeout, retries)
self._READ_DEVICE_VERSION_INFO: ProtocolCommand = self._read_command(0x7531, 0x0063)
super().__init__(host, port, comm_addr if comm_addr else 0x7f, timeout, retries)
self._READ_DEVICE_VERSION_INFO: ProtocolCommand = self._read_command(0x7531, 0x0028)
self._READ_METER_VERSION_INFO: ProtocolCommand = self._read_command(0x756f, 0x0014)
self._READ_DEVICE_MODEL: ProtocolCommand = self._read_command(0x9CED, 0x0008)
self._READ_RUNNING_DATA: ProtocolCommand = self._read_command(0x7594, 0x0049)
self._READ_METER_DATA: ProtocolCommand = self._read_command(0x75f3, 0xF)
Expand All @@ -171,55 +170,46 @@ def _pv1_pv2_only(s: Sensor) -> bool:
"""Filter to exclude sensors on < 3 PV inverters"""
return not s.id_.endswith('pv3')

async def read_device_info(self) -> dict[str, Any]:
device_info = {}

async def read_device_info(self):
response = await self._read_from_socket(self._READ_DEVICE_VERSION_INFO)
response = response.response_data()
try:
response = await self._read_from_socket(self._READ_DEVICE_VERSION_INFO)
response = response.response_data()
self.model_name = response[22:32].decode("ascii").rstrip('\x00').strip()
except Exception as e:
self.model_name = response[22:32].decode("ascii").rstrip()
except:
try:
response2 = await self._read_from_socket(self._READ_DEVICE_MODEL)
response2 = response2.response_data()
self.model_name = response2[0:16].decode("ascii").rstrip('\x00').strip()
except Exception as e:
print(f"No model name sent from the inverter. Error: {e}")
self.model_name = "Unknown"

try:
# Modbus registers from 30001 - 30099
self.serial_number = self._decode(response[6:22]) # 30004 - 30012
self.meter_serial_number = self._decode(response[148:162]) #30075 - 30082
self.dsp1_version = read_unsigned_int(response, 66) # 30034
self.dsp2_version = read_unsigned_int(response, 68) # 30035
self.arm_version = read_unsigned_int(response, 70) # 30036
self.dsp_svn_version = read_unsigned_int(response, 72) # 35037
self.arm_svn_version = read_unsigned_int(response, 74) # 35038
self.meter_software_version = read_unsigned_int(response, 124) #30063
self.firmware = f"{self.dsp1_version}.{self.dsp2_version}.{self.arm_version:02x}"

device_info['model_name'] = self.model_name
device_info['serial_number'] = self.serial_number
device_info['meter_serial_number'] = self.meter_serial_number
device_info['meter_software_version'] = self.meter_software_version

if is_single_phase(self):
self._sensors = tuple(filter(self._single_phase_only, self.__all_sensors))
self._settings.update({s.id_: s for s in self.__settings_single_phase})
else:
self._settings.update({s.id_: s for s in self.__settings_three_phase})

if is_3_mppt(self):
pass
else:
self._sensors = tuple(filter(self._pv1_pv2_only, self._sensors))
response = await self._read_from_socket(self._READ_DEVICE_MODEL)
response = response.response_data()
self.model_name = response[0:16].decode("ascii").rstrip('\x00').strip()
except InverterError as e:
logger.debug("No model name sent from the inverter.")

# Modbus registers from 30001 - 30040
self.serial_number = self._decode(response[6:22]) # 30004 - 30012
self.dsp1_version = read_unsigned_int(response, 66) # 30034
self.dsp2_version = read_unsigned_int(response, 68) # 30035
self.arm_version = read_unsigned_int(response, 70) # 30036
self.dsp_svn_version = read_unsigned_int(response, 72) # 35037
self.arm_svn_version = read_unsigned_int(response, 74) # 35038
self.firmware = f"{self.dsp1_version}.{self.dsp2_version}.{self.arm_version:02x}"

if is_single_phase(self):
self._sensors = tuple(filter(self._single_phase_only, self.__all_sensors))
self._settings.update({s.id_: s for s in self.__settings_single_phase})
else:
self._settings.update({s.id_: s for s in self.__settings_three_phase})

except Exception as e:
print(f"Error reading device info: {e}")
device_info['error'] = str(e)
if is_3_mppt(self):
pass
else:
self._sensors = tuple(filter(self._pv1_pv2_only, self._sensors))

return device_info
try:
response = await self._read_from_socket(self._READ_METER_VERSION_INFO)
response = response.response_data()
self.meter_software_version = read_unsigned_int(response, 0) # 30063
self.meter_serial_number = self._decode(response[24:38]) # 30075 - 30082
except InverterError as e:
logger.debug("Could not read meter version info.")

async def read_runtime_data(self) -> dict[str, Any]:
response = await self._read_from_socket(self._READ_RUNNING_DATA)
Expand Down
41 changes: 30 additions & 11 deletions tests/test_dt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def __init__(self, methodName='runTest', port=8899):
DT.__init__(self, "localhost", port)
self.sensor_map = {s.id_: s for s in self.sensors()}
self._mock_responses = {}
self.mock_response(self._READ_METER_VERSION_INFO, ILLEGAL_DATA_ADDRESS)
self.mock_response(self._READ_DEVICE_MODEL, ILLEGAL_DATA_ADDRESS)

def mock_response(self, command: ProtocolCommand, filename: str):
self._mock_responses[command] = filename
Expand Down Expand Up @@ -59,7 +61,7 @@ def __init__(self, methodName='runTest'):
def test_GW6000_DT_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(42, len(data))
self.assertEqual(45, len(data))

self.sensor_map = {s.id_: s for s in self.sensors()}

Expand Down Expand Up @@ -93,8 +95,10 @@ def test_GW6000_DT_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor("apparent_power", -1, "VA", data),
self.assertSensor("reactive_power", -1, "var", data),
self.assertSensor('total_input_power', -1, 'W', data)
self.assertSensor("power_factor", 0.0, "", data),
self.assertSensor('temperature', 41.3, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', 6.0, 'kWh', data)
self.assertSensor('e_total', 13350.2, 'kWh', data)
self.assertSensor('h_total', 8451, 'h', data)
Expand All @@ -105,22 +109,23 @@ def test_GW6000_DT_runtime_data(self):
self.assertSensor('vnbus', 305.4, 'V', data)
self.assertSensor('derating_mode', 0, '', data)
self.assertSensor('derating_mode_label', '', '', data)
self.assertSensor('rssi', 100, '', data)

self.assertFalse(self.sensor_map, f"Some sensors were not tested {self.sensor_map}")

def test_GW6000_DT_setting(self):
self.assertEqual(8, len(self.settings()))
self.assertEqual(12, len(self.settings()))
settings = {s.id_: s for s in self.settings()}
self.assertEqual('Timestamp', type(settings.get("time")).__name__)
self.assertEqual('Integer', type(settings.get("grid_export")).__name__)
self.assertEqual('Integer', type(settings.get("grid_export_limit")).__name__)

def test_GW6000_DT_read_setting(self):
self.loop.run_until_complete(self.read_setting('shadow_scan'))
self.loop.run_until_complete(self.read_setting('shadow_scan_pv1'))
self.assertEqual('7f039d8600014051', self.request.hex())

def test_GW6000_DT_write_setting(self):
self.loop.run_until_complete(self.write_setting('shadow_scan', 1))
self.loop.run_until_complete(self.write_setting('shadow_scan_pv1', 1))
self.assertEqual('7f069d8600018c51', self.request.hex())


Expand All @@ -146,7 +151,7 @@ def test_GW8K_DT_device_info(self):
def test_GW8K_DT_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(42, len(data))
self.assertEqual(45, len(data))

self.assertSensor('timestamp', datetime.strptime('2021-08-24 16:43:27', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 275.5, 'V', data)
Expand Down Expand Up @@ -178,8 +183,10 @@ def test_GW8K_DT_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor("apparent_power", 0, "VA", data),
self.assertSensor("reactive_power", 0, "var", data),
self.assertSensor('total_input_power', 0, 'W', data)
self.assertSensor("power_factor", 0.0, "", data),
self.assertSensor('temperature', 45.3, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', None, 'kWh', data)
self.assertSensor('e_total', None, 'kWh', data)
self.assertSensor('h_total', 0, 'h', data)
Expand Down Expand Up @@ -213,7 +220,7 @@ def __init__(self, methodName='runTest'):
def test_GW5000D_NS_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(32, len(data))
self.assertEqual(35, len(data))

self.assertSensor('timestamp', datetime.strptime('2021-09-06 06:56:01', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 224.4, 'V', data)
Expand All @@ -235,8 +242,10 @@ def test_GW5000D_NS_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor("apparent_power", -1, "VA", data),
self.assertSensor("reactive_power", -1, "var", data),
self.assertSensor('total_input_power', -1, 'W', data)
self.assertSensor("power_factor", -0.001, "", data),
self.assertSensor('temperature', 1.4, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', 0, 'kWh', data)
self.assertSensor('e_total', 881.7, 'kWh', data)
self.assertSensor('h_total', 955, 'h', data)
Expand Down Expand Up @@ -281,7 +290,7 @@ def test_GW6000_MS_device_info(self):
def test_GW5000_MS_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(35, len(data))
self.assertEqual(38, len(data))

self.assertSensor('timestamp', datetime.strptime('2021-10-15 09:03:12', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 319.6, 'V', data)
Expand All @@ -306,8 +315,10 @@ def test_GW5000_MS_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor("apparent_power", -1, "VA", data),
self.assertSensor("reactive_power", -1, "var", data),
self.assertSensor('total_input_power', -1, 'W', data)
self.assertSensor("power_factor", -0.001, "", data),
self.assertSensor('temperature', 10.7, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', 0.4, 'kWh', data)
self.assertSensor('e_total', 6.8, 'kWh', data)
self.assertSensor('h_total', 7, 'h', data)
Expand Down Expand Up @@ -342,7 +353,7 @@ def test_GW10K_MS_30_device_info(self):
def test_GW10K_MS_30_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(35, len(data))
self.assertEqual(38, len(data))

self.assertSensor('timestamp', datetime.strptime('2024-01-09 22:08:20', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 0.0, 'V', data)
Expand All @@ -367,8 +378,10 @@ def test_GW10K_MS_30_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor("apparent_power", 0, "VA", data),
self.assertSensor("reactive_power", 0, "var", data),
self.assertSensor('total_input_power', 0, 'W', data)
self.assertSensor("power_factor", 0.0, "", data),
self.assertSensor('temperature', 24.3, 'C', data)
self.assertSensor('temperature_heatsink', 0.0, 'C', data)
self.assertSensor('e_day', 71.8, 'kWh', data)
self.assertSensor('e_total', 3433.4, 'kWh', data)
self.assertSensor('h_total', 971, 'h', data)
Expand All @@ -391,7 +404,7 @@ def __init__(self, methodName='runTest'):
def test_GW10K_MS_TCP_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(42, len(data))
self.assertEqual(45, len(data))

self.assertSensor('timestamp', datetime.strptime('2024-06-02 09:07:17', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 400.6, 'V', data)
Expand Down Expand Up @@ -423,8 +436,10 @@ def test_GW10K_MS_TCP_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor('apparent_power', 5957, 'VA', data)
self.assertSensor('reactive_power', -6, 'var', data)
self.assertSensor('total_input_power', -1, 'W', data)
self.assertSensor("power_factor", 0.999, "", data),
self.assertSensor('temperature', 36.0, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', 4.3, 'kWh', data)
self.assertSensor('e_total', 998.2, 'kWh', data)
self.assertSensor('h_total', 246, 'h', data)
Expand Down Expand Up @@ -459,7 +474,7 @@ def test_GW20KAU_DT_device_info(self):
def test_GW20KAU_DT_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(42, len(data))
self.assertEqual(45, len(data))

self.assertSensor('timestamp', datetime.strptime('2022-10-21 19:23:42', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 390.5, 'V', data)
Expand Down Expand Up @@ -491,8 +506,10 @@ def test_GW20KAU_DT_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor("apparent_power", 0, "VA", data),
self.assertSensor("reactive_power", 205, "var", data),
self.assertSensor('total_input_power', 0, 'W', data)
self.assertSensor("power_factor", 0.999, "", data),
self.assertSensor('temperature', 36.4, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', 19.8, 'kWh', data)
self.assertSensor('e_total', 4304.8, 'kWh', data)
self.assertSensor('h_total', 1139, 'h', data)
Expand Down Expand Up @@ -527,7 +544,7 @@ def test_GW20KAU_DT_device_info(self):
def test_GW20KAU_DT_runtime_data(self):
self.loop.run_until_complete(self.read_device_info())
data = self.loop.run_until_complete(self.read_runtime_data())
self.assertEqual(42, len(data))
self.assertEqual(45, len(data))

self.assertSensor('timestamp', datetime.strptime('2024-05-20 10:35:55', '%Y-%m-%d %H:%M:%S'), '', data)
self.assertSensor('vpv1', 540.0, 'V', data)
Expand Down Expand Up @@ -559,8 +576,10 @@ def test_GW20KAU_DT_runtime_data(self):
self.assertSensor('warning_code', 0, '', data)
self.assertSensor('apparent_power', 0, 'VA', data)
self.assertSensor('reactive_power', 0, 'var', data)
self.assertSensor('total_input_power', 0, 'W', data)
self.assertSensor("power_factor", 0.0, "", data),
self.assertSensor('temperature', 45.7, 'C', data)
self.assertSensor('temperature_heatsink', None, 'C', data)
self.assertSensor('e_day', 29.3, 'kWh', data)
self.assertSensor('e_total', 29984.4, 'kWh', data)
self.assertSensor('h_total', 8357, 'h', data)
Expand Down

0 comments on commit ab01a89

Please sign in to comment.