goodwe 0.2.33__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {goodwe-0.2.33/goodwe.egg-info → goodwe-0.3.0}/PKG-INFO +8 -22
  2. {goodwe-0.2.33 → goodwe-0.3.0}/README.md +0 -18
  3. goodwe-0.3.0/VERSION +1 -0
  4. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/__init__.py +3 -3
  5. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/const.py +135 -66
  6. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/dt.py +78 -82
  7. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/es.py +20 -21
  8. goodwe-0.3.0/goodwe/et.py +673 -0
  9. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/exceptions.py +0 -4
  10. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/inverter.py +18 -24
  11. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/model.py +9 -6
  12. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/protocol.py +51 -2
  13. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/sensor.py +142 -94
  14. {goodwe-0.2.33 → goodwe-0.3.0/goodwe.egg-info}/PKG-INFO +8 -22
  15. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe.egg-info/SOURCES.txt +0 -5
  16. {goodwe-0.2.33 → goodwe-0.3.0}/setup.cfg +7 -3
  17. {goodwe-0.2.33 → goodwe-0.3.0}/tests/test_dt.py +104 -174
  18. {goodwe-0.2.33 → goodwe-0.3.0}/tests/test_es.py +19 -28
  19. {goodwe-0.2.33 → goodwe-0.3.0}/tests/test_et.py +316 -278
  20. {goodwe-0.2.33 → goodwe-0.3.0}/tests/test_sensor.py +44 -26
  21. goodwe-0.2.33/VERSION +0 -1
  22. goodwe-0.2.33/goodwe/et.py +0 -677
  23. goodwe-0.2.33/goodwe/goodwe.py +0 -22
  24. goodwe-0.2.33/goodwe/processor.py +0 -37
  25. goodwe-0.2.33/goodwe/xs.py +0 -43
  26. goodwe-0.2.33/tests/test_goodwe.py +0 -8
  27. goodwe-0.2.33/tests/test_processor.py +0 -32
  28. {goodwe-0.2.33 → goodwe-0.3.0}/LICENSE +0 -0
  29. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe/modbus.py +0 -0
  30. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe.egg-info/dependency_links.txt +0 -0
  31. {goodwe-0.2.33 → goodwe-0.3.0}/goodwe.egg-info/top_level.txt +0 -0
  32. {goodwe-0.2.33 → goodwe-0.3.0}/pyproject.toml +0 -0
  33. {goodwe-0.2.33 → goodwe-0.3.0}/tests/test_modbus.py +0 -0
  34. {goodwe-0.2.33 → goodwe-0.3.0}/tests/test_protocol.py +0 -0
@@ -1,20 +1,24 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: goodwe
3
- Version: 0.2.33
3
+ Version: 0.3.0
4
4
  Summary: Read data from GoodWe inverter via local network
5
5
  Home-page: https://github.com/marcelblijleven/goodwe
6
- Author: Marcel Blijleven, Martin Letenay
6
+ Author: Martin Letenay, Marcel Blijleven
7
7
  Author-email: 'marcelblijleven@gmail.com
8
8
  License: MIT
9
9
  Keywords: GoodWe,Solar Panel,Inverter,Photovoltaics,PV
10
- Classifier: Development Status :: 4 - Beta
10
+ Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.7
16
15
  Classifier: Programming Language :: Python :: 3.8
17
16
  Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Python: >=3.8
18
22
  Description-Content-Type: text/markdown
19
23
  License-File: LICENSE
20
24
 
@@ -63,24 +67,6 @@ async def get_runtime_data():
63
67
  asyncio.run(get_runtime_data())
64
68
  ```
65
69
 
66
- or the old way (for XS inverters only), create a processor and inverter instance:
67
-
68
- ```python
69
- import asyncio
70
- from goodwe import GoodWeInverter, GoodWeXSProcessor
71
-
72
-
73
- async def get_data():
74
- ip_address = '192.168.200.100'
75
- processor = GoodWeXSProcessor()
76
- inverter = GoodWeInverter(inverter_address=(ip_address, 8899), processor=processor)
77
- data = await inverter.request_data()
78
- print(f'power is {data.power} at {data.date:%H:%M:%S}')
79
-
80
-
81
- asyncio.run(get_data())
82
- ```
83
-
84
70
  ## References and useful links
85
71
 
86
72
  - https://github.com/mletenay/home-assistant-goodwe-inverter
@@ -43,24 +43,6 @@ async def get_runtime_data():
43
43
  asyncio.run(get_runtime_data())
44
44
  ```
45
45
 
46
- or the old way (for XS inverters only), create a processor and inverter instance:
47
-
48
- ```python
49
- import asyncio
50
- from goodwe import GoodWeInverter, GoodWeXSProcessor
51
-
52
-
53
- async def get_data():
54
- ip_address = '192.168.200.100'
55
- processor = GoodWeXSProcessor()
56
- inverter = GoodWeInverter(inverter_address=(ip_address, 8899), processor=processor)
57
- data = await inverter.request_data()
58
- print(f'power is {data.power} at {data.date:%H:%M:%S}')
59
-
60
-
61
- asyncio.run(get_data())
62
- ```
63
-
64
46
  ## References and useful links
65
47
 
66
48
  - https://github.com/mletenay/home-assistant-goodwe-inverter
goodwe-0.3.0/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
@@ -8,7 +8,6 @@ from .dt import DT
8
8
  from .es import ES
9
9
  from .et import ET
10
10
  from .exceptions import InverterError, RequestFailedException
11
- from .goodwe import GoodWeXSProcessor, AbstractDataProcessor, GoodWeInverter
12
11
  from .inverter import Inverter, OperationMode, Sensor, SensorKind
13
12
  from .model import DT_MODEL_TAGS, ES_MODEL_TAGS, ET_MODEL_TAGS
14
13
  from .protocol import ProtocolCommand, UdpInverterProtocol, Aa55ProtocolCommand
@@ -70,8 +69,9 @@ async def discover(host: str, timeout: int = 1, retries: int = 3) -> Inverter:
70
69
  try:
71
70
  logger.debug("Probing inverter at %s.", host)
72
71
  response = await DISCOVERY_COMMAND.execute(host, timeout, retries)
73
- model_name = response[12:22].decode("ascii").rstrip()
74
- serial_number = response[38:54].decode("ascii")
72
+ response = response.response_data()
73
+ model_name = response[5:15].decode("ascii").rstrip()
74
+ serial_number = response[31:47].decode("ascii")
75
75
 
76
76
  inverter_class: Type[Inverter] | None = None
77
77
  for model_tag in ET_MODEL_TAGS:
@@ -70,97 +70,131 @@ WORK_MODES_ES: Dict[int, str] = {
70
70
  }
71
71
 
72
72
  SAFETY_COUNTRIES: Dict[int, str] = {
73
- 0: "Italy",
74
- 1: "Czechia",
75
- 2: "Germany",
76
- 3: "Spain",
77
- 4: "Greece Mainland",
78
- 5: "Denmark",
79
- 6: "Belgium",
80
- 7: "Romania",
81
- 8: "G98",
82
- 9: "Australia",
83
- 10: "France",
73
+ 0: "IT CEI 0-21",
74
+ 1: "CZ-A1",
75
+ 2: "DE LV with PV",
76
+ 3: "ES-A",
77
+ 4: "GR",
78
+ 5: "DK2",
79
+ 6: "BE",
80
+ 7: "RO-A",
81
+ 8: "GB G98",
82
+ 9: "Australia A",
83
+ 10: "FR mainland",
84
84
  11: "China",
85
- 12: "60Hz Grid Default",
86
- 13: "Poland",
85
+ 12: "60Hz 230Vac Default",
86
+ 13: "PL LV",
87
87
  14: "South Africa",
88
- 15: "AustraliaL",
89
- 16: "Brazil",
88
+ 16: "Brazil 220Vac",
90
89
  17: "Thailand MEA",
91
90
  18: "Thailand PEA",
92
91
  19: "Mauritius",
93
- 20: "Holland",
94
- 21: "G99",
95
- 22: "China Special",
96
- 23: "French 50Hz",
97
- 24: "French 60Hz",
92
+ 20: "NL-A",
93
+ 21: "G98/NI",
94
+ 22: "China Higher",
95
+ 23: "FR island 50Hz",
96
+ 24: "FR island 60Hz",
98
97
  25: "Australia Ergon",
99
98
  26: "Australia Energex",
100
- 27: "Holland 16/20A",
99
+ 27: "NL 16/20A",
101
100
  28: "Korea",
102
- 29: "China Station",
103
- 30: "Austria",
101
+ 29: "China Utility",
102
+ 30: "AT-A",
104
103
  31: "India",
105
- 32: "50Hz Grid Default",
104
+ 32: "50Hz 230Vac Default",
106
105
  33: "Warehouse",
107
106
  34: "Philippines",
108
- 35: "Ireland",
107
+ 35: "IE-16/25A",
109
108
  36: "Taiwan",
110
- 37: "Bulgaria",
109
+ 37: "BG",
111
110
  38: "Barbados",
112
- 39: "China Special High",
113
- 40: "G99",
114
- 41: "Sweden",
115
- 42: "Chile",
116
- 43: "Brazil LV",
117
- 44: "NewZealand",
118
- 45: "IEEE1547 208VAC",
119
- 46: "IEEE1547 220VAC",
120
- 47: "IEEE1547 240VAC",
121
- 48: "60Hz LV Default",
122
- 49: "50Hz LV Default",
123
- 50: "AU_WAPN",
124
- 51: "AU_MicroGrid",
125
- 52: "JP_50Hz",
126
- 53: "JP_60Hz",
111
+ 39: "China Highest",
112
+ 40: "GB G99-A",
113
+ 41: "SE LV",
114
+ 42: "Chile BT",
115
+ 43: "Brazil 127Vac",
116
+ 44: "Newzealand",
117
+ 45: "IEEE1547 208Vac",
118
+ 46: "IEEE1547 220Vac",
119
+ 47: "IEEE1547 240Vac",
120
+ 48: "60Hz 127Vac Default",
121
+ 49: "50Hz 127Vac Default",
122
+ 50: "Australia WAPN",
123
+ 51: "Australia MicroGrid",
124
+ 52: "JP 50Hz",
125
+ 53: "JP 60Hz",
127
126
  54: "India Higher",
128
127
  55: "DEWA LV",
129
128
  56: "DEWA MV",
130
- 57: "Slovakia",
131
- 58: "GreenGrid",
132
- 59: "Hungary",
129
+ 57: "SK",
130
+ 58: "NZ GreenGrid",
131
+ 59: "HU",
133
132
  60: "Sri Lanka",
134
- 61: "Spain Islands",
133
+ 61: "ES island",
135
134
  62: "Ergon30K",
136
135
  63: "Energex30K",
137
- 64: "IEEE1547 230/400V",
136
+ 64: "IEEE1547 230/400Vac",
138
137
  65: "IEC61727 60Hz",
139
- 66: "Switzerland",
140
- 67: "CEI-016",
141
- 68: "AU_Horizon",
142
- 69: "Cyprus",
143
- 70: "AU_SAPN",
144
- 71: "AU_Ausgrid",
145
- 72: "AU_Essential",
146
- 73: "AU_Pwcore&CitiPW",
138
+ 66: "CH",
139
+ 67: "IT CEI 0-16",
140
+ 68: "Australia Horizon",
141
+ 69: "CY",
142
+ 70: "Australia SAPN",
143
+ 71: "Australia Ausgrid",
144
+ 72: "Australia Essential",
145
+ 73: "Australia Victoria",
147
146
  74: "Hong Kong",
148
- 75: "Poland MV",
149
- 76: "Holland MV",
150
- 77: "Sweden MV",
151
- 78: "VDE4110",
152
- 96: "cUSA_208VacDefault",
153
- 97: "cUSA_240VacDefault",
154
- 98: "cUSA_208VacCA_SCE",
155
- 99: "cUSA_240VacCA_SCE",
147
+ 75: "PL MV",
148
+ 76: "NL-B",
149
+ 77: "SE MV",
150
+ 78: "DE MV",
151
+ 79: "DE LV without PV",
152
+ 80: "ES-D",
153
+ 81: "Australia Endeavour",
154
+ 82: "Argentina",
155
+ 83: "Israel LV",
156
+ 84: "IEC61727 50Hz",
157
+ 85: "Australia B",
158
+ 86: "Australia C",
159
+ 87: "Chile MT-A",
160
+ 88: "Chile MT-B",
161
+ 89: "Vietnam",
162
+ 90: "reserve14",
163
+ 91: "Israel-HV",
164
+ 93: "NewZealand:2015",
165
+ 94: "RO-D",
166
+ 96: "US 208Vac Default",
167
+ 97: "US 240Vac Default",
168
+ 98: "US CA 208Vac",
169
+ 99: "US CA 240Vac",
156
170
  100: "cUSA_208VacCA_SDGE",
157
171
  101: "cUSA_240VacCA_SDGE",
158
172
  102: "cUSA_208VacCA_PGE",
159
173
  103: "cUSA_240VacCA_PGE",
160
- 104: "cUSA_208VacHECO_14HO",
161
- 105: "cUSA_240VacHECO_14HO0x69",
162
- 106: "cUSA_208VacHECO_14HM",
163
- 107: "cUSA_240VacHECO_14HM",
174
+ 104: "US HI 208Vac",
175
+ 105: "US HI 240Vac",
176
+ 106: "USA_208VacHECO_14HM",
177
+ 107: "USA_240VacHECO_14HM",
178
+ 108: "US 480Vac",
179
+ 109: "US CA 480Vac",
180
+ 110: "US HI 480Vac",
181
+ 111: "US Kauai 208Vac",
182
+ 112: "US Kauai 240Vac",
183
+ 113: "US Kauai 480Vac",
184
+ 114: "US ISO-NE 208Vac",
185
+ 115: "US ISO-NE 240Vac",
186
+ 116: "US ISO-NE 480Vac",
187
+ 118: "PR 208Vac",
188
+ 119: "PR 240Vac",
189
+ 120: "PR 480Vac",
190
+ 128: "Poland_B",
191
+ 129: "EE",
192
+ 135: "CZ-A2",
193
+ 136: "CZ-B1",
194
+ 146: "Brazil 208Vac",
195
+ 147: "Brazil 230Vac",
196
+ 148: "Brazil 240Vac",
197
+ 149: "Brazil 254Vac",
164
198
  }
165
199
 
166
200
  ERROR_CODES: Dict[int, str] = {
@@ -263,3 +297,38 @@ BMS_WARNING_CODES: Dict[int, str] = {
263
297
  1: 'Discharging under-voltage 1',
264
298
  0: 'Charging over-voltage 1',
265
299
  }
300
+
301
+ DERATING_MODE_CODES: Dict[int, str] = {
302
+ 31: '',
303
+ 30: '',
304
+ 29: '',
305
+ 28: '',
306
+ 27: '',
307
+ 26: '',
308
+ 25: '',
309
+ 24: '',
310
+ 23: '',
311
+ 22: '',
312
+ 21: '',
313
+ 20: '',
314
+ 19: '',
315
+ 18: '',
316
+ 17: '',
317
+ 16: '',
318
+ 15: '',
319
+ 14: '',
320
+ 13: '',
321
+ 12: '',
322
+ 11: '',
323
+ 10: 'Power calibration limit power (For ATS)',
324
+ 9: 'Overvoltage derating (For GW)',
325
+ 8: 'Maximum current derating',
326
+ 7: 'Limited power start derating',
327
+ 6: 'DRED derating',
328
+ 5: 'Export power derating',
329
+ 4: 'PU Curve',
330
+ 3: 'Power VS Frequency',
331
+ 2: 'Reactive power derating(PF/QU/FixQ)',
332
+ 1: 'Active power derating',
333
+ 0: 'Overtemperature derating',
334
+ }
@@ -6,7 +6,7 @@ from .exceptions import InverterError
6
6
  from .inverter import Inverter
7
7
  from .inverter import OperationMode
8
8
  from .inverter import SensorKind as Kind
9
- from .model import is_3_mptt, is_single_phase
9
+ from .model import is_3_mppt, is_single_phase
10
10
  from .protocol import ProtocolCommand, ModbusReadCommand, ModbusWriteCommand, ModbusWriteMultiCommand
11
11
  from .sensor import *
12
12
 
@@ -15,21 +15,21 @@ class DT(Inverter):
15
15
  """Class representing inverter of DT/MS/D-NS/XS or GE's GEP(PSB/PSC) families"""
16
16
 
17
17
  __all_sensors: Tuple[Sensor, ...] = (
18
- Timestamp("timestamp", 0, "Timestamp"),
19
- Voltage("vpv1", 6, "PV1 Voltage", Kind.PV),
20
- Current("ipv1", 8, "PV1 Current", Kind.PV),
18
+ Timestamp("timestamp", 30100, "Timestamp"),
19
+ Voltage("vpv1", 30103, "PV1 Voltage", Kind.PV),
20
+ Current("ipv1", 30104, "PV1 Current", Kind.PV),
21
21
  Calculated("ppv1",
22
- lambda data: round(read_voltage(data, 6) * read_current(data, 8)),
22
+ lambda data: round(read_voltage(data, 30103) * read_current(data, 30104)),
23
23
  "PV1 Power", "W", Kind.PV),
24
- Voltage("vpv2", 10, "PV2 Voltage", Kind.PV),
25
- Current("ipv2", 12, "PV2 Current", Kind.PV),
24
+ Voltage("vpv2", 30105, "PV2 Voltage", Kind.PV),
25
+ Current("ipv2", 30106, "PV2 Current", Kind.PV),
26
26
  Calculated("ppv2",
27
- lambda data: round(read_voltage(data, 10) * read_current(data, 12)),
27
+ lambda data: round(read_voltage(data, 30105) * read_current(data, 30106)),
28
28
  "PV2 Power", "W", Kind.PV),
29
- Voltage("vpv3", 14, "PV3 Voltage", Kind.PV),
30
- Current("ipv3", 16, "PV3 Current", Kind.PV),
29
+ Voltage("vpv3", 30107, "PV3 Voltage", Kind.PV),
30
+ Current("ipv3", 30108, "PV3 Current", Kind.PV),
31
31
  Calculated("ppv3",
32
- lambda data: round(read_voltage(data, 14) * read_current(data, 16)),
32
+ lambda data: round(read_voltage(data, 30107) * read_current(data, 30108)),
33
33
  "PV3 Power", "W", Kind.PV),
34
34
  # Voltage("vpv4", 14, "PV4 Voltage", Kind.PV),
35
35
  # Current("ipv4", 16, "PV4 Current", Kind.PV),
@@ -37,72 +37,70 @@ class DT(Inverter):
37
37
  # Current("ipv5", 16, "PV5 Current", Kind.PV),
38
38
  # Voltage("vpv6", 14, "PV6 Voltage", Kind.PV),
39
39
  # Current("ipv6", 16, "PV7 Current", Kind.PV),
40
- Voltage("vline1", 30, "On-grid L1-L2 Voltage", Kind.AC),
41
- Voltage("vline2", 32, "On-grid L2-L3 Voltage", Kind.AC),
42
- Voltage("vline3", 34, "On-grid L3-L1 Voltage", Kind.AC),
43
- Voltage("vgrid1", 36, "On-grid L1 Voltage", Kind.AC),
44
- Voltage("vgrid2", 38, "On-grid L2 Voltage", Kind.AC),
45
- Voltage("vgrid3", 40, "On-grid L3 Voltage", Kind.AC),
46
- Current("igrid1", 42, "On-grid L1 Current", Kind.AC),
47
- Current("igrid2", 44, "On-grid L2 Current", Kind.AC),
48
- Current("igrid3", 46, "On-grid L3 Current", Kind.AC),
49
- Frequency("fgrid1", 48, "On-grid L1 Frequency", Kind.AC),
50
- Frequency("fgrid2", 50, "On-grid L2 Frequency", Kind.AC),
51
- Frequency("fgrid3", 52, "On-grid L3 Frequency", Kind.AC),
40
+ Voltage("vline1", 30115, "On-grid L1-L2 Voltage", Kind.AC),
41
+ Voltage("vline2", 30116, "On-grid L2-L3 Voltage", Kind.AC),
42
+ Voltage("vline3", 30117, "On-grid L3-L1 Voltage", Kind.AC),
43
+ Voltage("vgrid1", 30118, "On-grid L1 Voltage", Kind.AC),
44
+ Voltage("vgrid2", 30119, "On-grid L2 Voltage", Kind.AC),
45
+ Voltage("vgrid3", 30120, "On-grid L3 Voltage", Kind.AC),
46
+ Current("igrid1", 30121, "On-grid L1 Current", Kind.AC),
47
+ Current("igrid2", 30122, "On-grid L2 Current", Kind.AC),
48
+ Current("igrid3", 30123, "On-grid L3 Current", Kind.AC),
49
+ Frequency("fgrid1", 30124, "On-grid L1 Frequency", Kind.AC),
50
+ Frequency("fgrid2", 30125, "On-grid L2 Frequency", Kind.AC),
51
+ Frequency("fgrid3", 30126, "On-grid L3 Frequency", Kind.AC),
52
52
  Calculated("pgrid1",
53
- lambda data: round(read_voltage(data, 36) * read_current(data, 42)),
53
+ lambda data: round(read_voltage(data, 30118) * read_current(data, 30121)),
54
54
  "On-grid L1 Power", "W", Kind.AC),
55
55
  Calculated("pgrid2",
56
- lambda data: round(read_voltage(data, 38) * read_current(data, 44)),
56
+ lambda data: round(read_voltage(data, 30119) * read_current(data, 30122)),
57
57
  "On-grid L2 Power", "W", Kind.AC),
58
58
  Calculated("pgrid3",
59
- lambda data: round(read_voltage(data, 40) * read_current(data, 46)),
59
+ lambda data: round(read_voltage(data, 30120) * read_current(data, 30123)),
60
60
  "On-grid L3 Power", "W", Kind.AC),
61
- Integer("xx54", 54, "Unknown sensor@54"),
62
- Power("ppv", 56, "PV Power", Kind.PV),
63
- Integer("work_mode", 58, "Work Mode code"),
64
- Enum2("work_mode_label", 58, WORK_MODES, "Work Mode"),
65
- Long("error_codes", 60, "Error Codes"),
66
- Integer("warning_code", 64, "Warning code"),
67
- Integer("xx66", 66, "Unknown sensor@66"),
68
- Integer("xx68", 68, "Unknown sensor@68"),
69
- Integer("xx70", 70, "Unknown sensor@70"),
70
- Integer("xx72", 72, "Unknown sensor@72"),
71
- Integer("xx74", 74, "Unknown sensor@74"),
72
- Integer("xx76", 76, "Unknown sensor@76"),
73
- Integer("xx78", 78, "Unknown sensor@78"),
74
- Integer("xx80", 80, "Unknown sensor@80"),
75
- Temp("temperature", 82, "Inverter Temperature", Kind.AC),
76
- Integer("xx84", 84, "Unknown sensor@84"),
77
- Integer("xx86", 86, "Unknown sensor@86"),
78
- Energy("e_day", 88, "Today's PV Generation", Kind.PV),
79
- Energy4("e_total", 90, "Total PV Generation", Kind.PV),
80
- Long("h_total", 94, "Hours Total", "h", Kind.PV),
81
- Integer("safety_country", 98, "Safety Country code", "", Kind.AC),
82
- Enum2("safety_country_label", 98, SAFETY_COUNTRIES, "Safety Country", Kind.AC),
83
- Integer("xx100", 100, "Unknown sensor@100"),
84
- Integer("xx102", 102, "Unknown sensor@102"),
85
- Integer("xx104", 104, "Unknown sensor@104"),
86
- Integer("xx106", 106, "Unknown sensor@106"),
87
- Integer("xx108", 108, "Unknown sensor@108"),
88
- Integer("xx110", 110, "Unknown sensor@110"),
89
- Integer("xx112", 112, "Unknown sensor@112"),
90
- Integer("xx114", 114, "Unknown sensor@114"),
91
- Integer("xx116", 116, "Unknown sensor@116"),
92
- Integer("xx118", 118, "Unknown sensor@118"),
93
- Integer("xx120", 120, "Unknown sensor@120"),
94
- Integer("xx122", 122, "Unknown sensor@122"),
95
- Integer("funbit", 124, "FunBit", "", Kind.PV),
96
- Voltage("vbus", 126, "Bus Voltage", Kind.PV),
97
- Voltage("vnbus", 128, "NBus Voltage", Kind.PV),
98
- Integer("xx130", 130, "Unknown sensor@130"),
99
- Integer("xx132", 132, "Unknown sensor@132"),
100
- Integer("xx134", 134, "Unknown sensor@134"),
101
- Integer("xx136", 136, "Unknown sensor@136"),
102
- Integer("xx138", 138, "Unknown sensor@138"),
103
- Integer("xx140", 140, "Unknown sensor@140"),
104
- Integer("xx142", 142, "Unknown sensor@142"),
105
- Integer("xx144", 144, "Unknown sensor@144"),
61
+ # 30127 reserved
62
+ Power("ppv", 30128, "PV Power", Kind.PV),
63
+ Integer("work_mode", 30129, "Work Mode code"),
64
+ Enum2("work_mode_label", 30129, WORK_MODES, "Work Mode"),
65
+ Long("error_codes", 30130, "Error Codes"),
66
+ Integer("warning_code", 30132, "Warning code"),
67
+ Apparent4("apparent_power", 30133, "Apparent Power", Kind.AC),
68
+ Reactive4("reactive_power", 30135, "Reactive Power", Kind.AC),
69
+ # 30137 reserved
70
+ # 30138 reserved
71
+ # 30139 reserved
72
+ # 30140 reserved
73
+ Temp("temperature", 30141, "Inverter Temperature", Kind.AC),
74
+ # 30142 reserved
75
+ # 30143 reserved
76
+ Energy("e_day", 30144, "Today's PV Generation", Kind.PV),
77
+ Energy4("e_total", 30145, "Total PV Generation", Kind.PV),
78
+ Long("h_total", 30147, "Hours Total", "h", Kind.PV),
79
+ Integer("safety_country", 30149, "Safety Country code", "", Kind.AC),
80
+ Enum2("safety_country_label", 30149, SAFETY_COUNTRIES, "Safety Country", Kind.AC),
81
+ # 30150 reserved
82
+ # 30151 reserved
83
+ # 30152 reserved
84
+ # 30153 reserved
85
+ # 30154 reserved
86
+ # 30155 reserved
87
+ # 30156 reserved
88
+ # 30157 reserved
89
+ # 30158 reserved
90
+ # 30159 reserved
91
+ # 30160 reserved
92
+ # 30161 reserved
93
+ Integer("funbit", 30162, "FunBit", "", Kind.PV),
94
+ Voltage("vbus", 30163, "Bus Voltage", Kind.PV),
95
+ Voltage("vnbus", 30164, "NBus Voltage", Kind.PV),
96
+ Long("derating_mode", 30165, "Derating Mode code"),
97
+ EnumBitmap4("derating_mode_label", 30165, DERATING_MODE_CODES, "Derating Mode"),
98
+ # 30167 reserved
99
+ # 30168 reserved
100
+ # 30169 reserved
101
+ # 30170 reserved
102
+ # 30171 reserved
103
+ # 30172 reserved
106
104
  )
107
105
 
108
106
  # Modbus registers of inverter settings, offsets are modbus register addresses
@@ -137,7 +135,7 @@ class DT(Inverter):
137
135
  @staticmethod
138
136
  def _single_phase_only(s: Sensor) -> bool:
139
137
  """Filter to exclude phase2/3 sensors on single phase inverters"""
140
- return not ((s.id_.endswith('2') or s.id_.endswith('3')) and 'pv' not in s.id_ and not s.id_.startswith('xx'))
138
+ return not ((s.id_.endswith('2') or s.id_.endswith('3')) and 'pv' not in s.id_)
141
139
 
142
140
  @staticmethod
143
141
  def _pv1_pv2_only(s: Sensor) -> bool:
@@ -146,12 +144,12 @@ class DT(Inverter):
146
144
 
147
145
  async def read_device_info(self):
148
146
  response = await self._read_from_socket(self._READ_DEVICE_VERSION_INFO)
149
- response = response[5:-2]
147
+ response = response.response_data()
150
148
  try:
151
149
  self.model_name = response[22:32].decode("ascii").rstrip()
152
150
  except:
153
151
  print("No model name sent from the inverter.")
154
- self.serial_number = response[6:22].decode("ascii")
152
+ self.serial_number = self._decode(response[6:22])
155
153
  self.dsp1_version = read_unsigned_int(response, 66)
156
154
  self.dsp2_version = read_unsigned_int(response, 68)
157
155
  self.arm_version = read_unsigned_int(response, 70)
@@ -164,7 +162,7 @@ class DT(Inverter):
164
162
  else:
165
163
  self._settings.update({s.id_: s for s in self.__settings_three_phase})
166
164
 
167
- if is_3_mptt(self):
165
+ if is_3_mppt(self):
168
166
  # this is 3 PV strings inverter, keep all sensors
169
167
  pass
170
168
  else:
@@ -172,9 +170,9 @@ class DT(Inverter):
172
170
  self._sensors = tuple(filter(self._pv1_pv2_only, self._sensors))
173
171
  pass
174
172
 
175
- async def read_runtime_data(self, include_unknown_sensors: bool = False) -> Dict[str, Any]:
176
- raw_data = await self._read_from_socket(self._READ_DEVICE_RUNNING_DATA)
177
- data = self._map_response(raw_data[5:-2], self._sensors, include_unknown_sensors)
173
+ async def read_runtime_data(self) -> Dict[str, Any]:
174
+ response = await self._read_from_socket(self._READ_DEVICE_RUNNING_DATA)
175
+ data = self._map_response(response, self._sensors)
178
176
  return data
179
177
 
180
178
  async def read_setting(self, setting_id: str) -> Any:
@@ -182,9 +180,8 @@ class DT(Inverter):
182
180
  if not setting:
183
181
  raise ValueError(f'Unknown setting "{setting_id}"')
184
182
  count = (setting.size_ + (setting.size_ % 2)) // 2
185
- raw_data = await self._read_from_socket(ModbusReadCommand(self.comm_addr, setting.offset, count))
186
- with io.BytesIO(raw_data[5:-2]) as buffer:
187
- return setting.read_value(buffer)
183
+ response = await self._read_from_socket(ModbusReadCommand(self.comm_addr, setting.offset, count))
184
+ return setting.read_value(response)
188
185
 
189
186
  async def write_setting(self, setting_id: str, value: Any):
190
187
  setting = self._settings.get(setting_id)
@@ -208,7 +205,6 @@ class DT(Inverter):
208
205
  return await self.read_setting('grid_export_limit')
209
206
 
210
207
  async def set_grid_export_limit(self, export_limit: int) -> None:
211
- setting = self._settings.get('grid_export_limit')
212
208
  if export_limit >= 0:
213
209
  return await self.write_setting('grid_export_limit', export_limit)
214
210