goodwe 0.3.1__tar.gz → 0.3.2__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.
- {goodwe-0.3.1/goodwe.egg-info → goodwe-0.3.2}/PKG-INFO +1 -1
- goodwe-0.3.2/VERSION +1 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/es.py +3 -3
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/et.py +26 -26
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/sensor.py +87 -31
- {goodwe-0.3.1 → goodwe-0.3.2/goodwe.egg-info}/PKG-INFO +1 -1
- {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_dt.py +9 -9
- {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_et.py +3 -3
- {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_sensor.py +33 -1
- goodwe-0.3.1/VERSION +0 -1
- {goodwe-0.3.1 → goodwe-0.3.2}/LICENSE +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/README.md +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/__init__.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/const.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/dt.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/exceptions.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/inverter.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/modbus.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/model.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe/protocol.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe.egg-info/SOURCES.txt +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe.egg-info/dependency_links.txt +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/goodwe.egg-info/top_level.txt +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/pyproject.toml +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/setup.cfg +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_es.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_modbus.py +0 -0
- {goodwe-0.3.1 → goodwe-0.3.2}/tests/test_protocol.py +0 -0
goodwe-0.3.2/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.2
|
|
@@ -67,7 +67,7 @@ class ES(Inverter):
|
|
|
67
67
|
Voltage("vgrid", 34, "On-grid Voltage", Kind.AC),
|
|
68
68
|
Current("igrid", 36, "On-grid Current", Kind.AC),
|
|
69
69
|
Calculated("pgrid",
|
|
70
|
-
lambda data: abs(
|
|
70
|
+
lambda data: abs(read_bytes2_signed(data, 38)) * (-1 if read_byte(data, 80) == 2 else 1),
|
|
71
71
|
"On-grid Export Power", "W", Kind.AC),
|
|
72
72
|
Frequency("fgrid", 40, "On-grid Frequency", Kind.AC),
|
|
73
73
|
Byte("grid_mode", 42, "Work Mode code", "", Kind.GRID),
|
|
@@ -87,7 +87,7 @@ class ES(Inverter):
|
|
|
87
87
|
Energy("e_day", 67, "Today's PV Generation", Kind.PV),
|
|
88
88
|
Energy("e_load_day", 69, "Today's Load", Kind.AC),
|
|
89
89
|
Energy4("e_load_total", 71, "Total Load", Kind.AC),
|
|
90
|
-
|
|
90
|
+
PowerS("total_power", 75, "Total Power", Kind.AC), # modbus 0x52c
|
|
91
91
|
Byte("effective_work_mode", 77, "Effective Work Mode code"),
|
|
92
92
|
Integer("effective_relay_control", 78, "Effective Relay Control", "", None),
|
|
93
93
|
Byte("grid_in_out", 80, "On-grid Mode code", "", Kind.GRID),
|
|
@@ -121,7 +121,7 @@ class ES(Inverter):
|
|
|
121
121
|
round(read_voltage(data, 5) * read_current(data, 7)) +
|
|
122
122
|
(abs(round(read_voltage(data, 10) * read_current(data, 18))) *
|
|
123
123
|
(-1 if read_byte(data, 30) == 3 else 1)) -
|
|
124
|
-
(abs(
|
|
124
|
+
(abs(read_bytes2_signed(data, 38)) * (-1 if read_byte(data, 80) == 2 else 1)),
|
|
125
125
|
"House Consumption", "W", Kind.AC),
|
|
126
126
|
)
|
|
127
127
|
|
|
@@ -52,23 +52,23 @@ class ET(Inverter):
|
|
|
52
52
|
Current("igrid", 35122, "On-grid L1 Current", Kind.AC),
|
|
53
53
|
Frequency("fgrid", 35123, "On-grid L1 Frequency", Kind.AC),
|
|
54
54
|
# 35124 reserved
|
|
55
|
-
|
|
55
|
+
PowerS("pgrid", 35125, "On-grid L1 Power", Kind.AC),
|
|
56
56
|
Voltage("vgrid2", 35126, "On-grid L2 Voltage", Kind.AC),
|
|
57
57
|
Current("igrid2", 35127, "On-grid L2 Current", Kind.AC),
|
|
58
58
|
Frequency("fgrid2", 35128, "On-grid L2 Frequency", Kind.AC),
|
|
59
59
|
# 35129 reserved
|
|
60
|
-
|
|
60
|
+
PowerS("pgrid2", 35130, "On-grid L2 Power", Kind.AC),
|
|
61
61
|
Voltage("vgrid3", 35131, "On-grid L3 Voltage", Kind.AC),
|
|
62
62
|
Current("igrid3", 35132, "On-grid L3 Current", Kind.AC),
|
|
63
63
|
Frequency("fgrid3", 35133, "On-grid L3 Frequency", Kind.AC),
|
|
64
64
|
# 35134 reserved
|
|
65
|
-
|
|
65
|
+
PowerS("pgrid3", 35135, "On-grid L3 Power", Kind.AC),
|
|
66
66
|
Integer("grid_mode", 35136, "Grid Mode code", "", Kind.PV),
|
|
67
67
|
Enum2("grid_mode_label", 35136, GRID_MODES, "Grid Mode", Kind.PV),
|
|
68
68
|
# 35137 reserved
|
|
69
|
-
|
|
69
|
+
PowerS("total_inverter_power", 35138, "Total Power", Kind.AC),
|
|
70
70
|
# 35139 reserved
|
|
71
|
-
|
|
71
|
+
PowerS("active_power", 35140, "Active Power", Kind.GRID),
|
|
72
72
|
Calculated("grid_in_out",
|
|
73
73
|
lambda data: read_grid_mode(data, 35140),
|
|
74
74
|
"On-grid Mode code", "", Kind.GRID),
|
|
@@ -84,29 +84,29 @@ class ET(Inverter):
|
|
|
84
84
|
Frequency("backup_f1", 35147, "Back-up L1 Frequency", Kind.UPS),
|
|
85
85
|
Integer("load_mode1", 35148, "Load Mode L1"),
|
|
86
86
|
# 35149 reserved
|
|
87
|
-
|
|
87
|
+
PowerS("backup_p1", 35150, "Back-up L1 Power", Kind.UPS),
|
|
88
88
|
Voltage("backup_v2", 35151, "Back-up L2 Voltage", Kind.UPS),
|
|
89
89
|
Current("backup_i2", 35152, "Back-up L2 Current", Kind.UPS),
|
|
90
90
|
Frequency("backup_f2", 35153, "Back-up L2 Frequency", Kind.UPS),
|
|
91
91
|
Integer("load_mode2", 35154, "Load Mode L2"),
|
|
92
92
|
# 35155 reserved
|
|
93
|
-
|
|
93
|
+
PowerS("backup_p2", 35156, "Back-up L2 Power", Kind.UPS),
|
|
94
94
|
Voltage("backup_v3", 35157, "Back-up L3 Voltage", Kind.UPS),
|
|
95
95
|
Current("backup_i3", 35158, "Back-up L3 Current", Kind.UPS),
|
|
96
96
|
Frequency("backup_f3", 35159, "Back-up L3 Frequency", Kind.UPS),
|
|
97
97
|
Integer("load_mode3", 35160, "Load Mode L3"),
|
|
98
98
|
# 35161 reserved
|
|
99
|
-
|
|
99
|
+
PowerS("backup_p3", 35162, "Back-up L3 Power", Kind.UPS),
|
|
100
100
|
# 35163 reserved
|
|
101
|
-
|
|
101
|
+
PowerS("load_p1", 35164, "Load L1", Kind.AC),
|
|
102
102
|
# 35165 reserved
|
|
103
|
-
|
|
103
|
+
PowerS("load_p2", 35166, "Load L2", Kind.AC),
|
|
104
104
|
# 35167 reserved
|
|
105
|
-
|
|
105
|
+
PowerS("load_p3", 35168, "Load L3", Kind.AC),
|
|
106
106
|
# 35169 reserved
|
|
107
|
-
|
|
107
|
+
PowerS("backup_ptotal", 35170, "Back-up Load", Kind.UPS),
|
|
108
108
|
# 35171 reserved
|
|
109
|
-
|
|
109
|
+
PowerS("load_ptotal", 35172, "Load", Kind.AC),
|
|
110
110
|
Integer("ups_load", 35173, "Ups Load", "%", Kind.UPS),
|
|
111
111
|
Temp("temperature_air", 35174, "Inverter Temperature (Air)", Kind.AC),
|
|
112
112
|
Temp("temperature_module", 35175, "Inverter Temperature (Module)"),
|
|
@@ -115,8 +115,8 @@ class ET(Inverter):
|
|
|
115
115
|
Voltage("bus_voltage", 35178, "Bus Voltage", None),
|
|
116
116
|
Voltage("nbus_voltage", 35179, "NBus Voltage", None),
|
|
117
117
|
Voltage("vbattery1", 35180, "Battery Voltage", Kind.BAT),
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
CurrentS("ibattery1", 35181, "Battery Current", Kind.BAT),
|
|
119
|
+
Power4S("pbattery1", 35182, "Battery Power", Kind.BAT),
|
|
120
120
|
Integer("battery_mode", 35184, "Battery Mode code", "", Kind.BAT),
|
|
121
121
|
Enum2("battery_mode_label", 35184, BATTERY_MODES, "Battery Mode", Kind.BAT),
|
|
122
122
|
Integer("warning_code", 35185, "Warning code"),
|
|
@@ -149,8 +149,8 @@ class ET(Inverter):
|
|
|
149
149
|
read_bytes4(data, 35109) +
|
|
150
150
|
read_bytes4(data, 35113) +
|
|
151
151
|
read_bytes4(data, 35117) +
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
read_bytes4_signed(data, 35182) -
|
|
153
|
+
read_bytes2_signed(data, 35140),
|
|
154
154
|
"House Consumption", "W", Kind.AC),
|
|
155
155
|
)
|
|
156
156
|
|
|
@@ -226,10 +226,10 @@ class ET(Inverter):
|
|
|
226
226
|
Integer("manufacture_code", 36002, "Manufacture Code"),
|
|
227
227
|
Integer("meter_test_status", 36003, "Meter Test Status"), # 1: correct,2: reverse,3: incorrect,0: not checked
|
|
228
228
|
Integer("meter_comm_status", 36004, "Meter Communication Status"), # 1 OK, 0 NotOK
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
PowerS("active_power1", 36005, "Active Power L1", Kind.GRID),
|
|
230
|
+
PowerS("active_power2", 36006, "Active Power L2", Kind.GRID),
|
|
231
|
+
PowerS("active_power3", 36007, "Active Power L3", Kind.GRID),
|
|
232
|
+
PowerS("active_power_total", 36008, "Active Power Total", Kind.GRID),
|
|
233
233
|
Reactive("reactive_power_total", 36009, "Reactive Power Total", Kind.GRID),
|
|
234
234
|
Decimal("meter_power_factor1", 36010, 1000, "Meter Power Factor L1", "", Kind.GRID),
|
|
235
235
|
Decimal("meter_power_factor2", 36011, 1000, "Meter Power Factor L2", "", Kind.GRID),
|
|
@@ -238,10 +238,10 @@ class ET(Inverter):
|
|
|
238
238
|
Frequency("meter_freq", 36014, "Meter Frequency", Kind.GRID),
|
|
239
239
|
Float("meter_e_total_exp", 36015, 1000, "Meter Total Energy (export)", "kWh", Kind.GRID),
|
|
240
240
|
Float("meter_e_total_imp", 36017, 1000, "Meter Total Energy (import)", "kWh", Kind.GRID),
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
241
|
+
Power4S("meter_active_power1", 36019, "Meter Active Power L1", Kind.GRID),
|
|
242
|
+
Power4S("meter_active_power2", 36021, "Meter Active Power L2", Kind.GRID),
|
|
243
|
+
Power4S("meter_active_power3", 36023, "Meter Active Power L3", Kind.GRID),
|
|
244
|
+
Power4S("meter_active_power_total", 36025, "Meter Active Power Total", Kind.GRID),
|
|
245
245
|
Reactive4("meter_reactive_power1", 36027, "Meter Reactive Power L1", Kind.GRID),
|
|
246
246
|
Reactive4("meter_reactive_power2", 36029, "Meter Reactive Power L2", Kind.GRID),
|
|
247
247
|
Reactive4("meter_reactive_power3", 36031, "Meter Reactive Power L2", Kind.GRID),
|
|
@@ -253,7 +253,7 @@ class ET(Inverter):
|
|
|
253
253
|
Integer("meter_type", 36043, "Meter Type", "", Kind.GRID), # (0: Single phase, 1: 3P3W, 2: 3P4W, 3: HomeKit)
|
|
254
254
|
Integer("meter_sw_version", 36044, "Meter Software Version", "", Kind.GRID),
|
|
255
255
|
# Sensors added in some ARM fw update, read when flag _has_meter_extended is on
|
|
256
|
-
|
|
256
|
+
Power4S("meter2_active_power", 36045, "Meter 2 Active Power", Kind.GRID),
|
|
257
257
|
Float("meter2_e_total_exp", 36047, 1000, "Meter 2 Total Energy (export)", "kWh", Kind.GRID),
|
|
258
258
|
Float("meter2_e_total_imp", 36049, 1000, "Meter 2 Total Energy (import)", "kWh", Kind.GRID),
|
|
259
259
|
Integer("meter2_comm_status", 36051, "Meter 2 Communication Status"),
|
|
@@ -83,7 +83,7 @@ class ScheduleType(IntEnum):
|
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
class Voltage(Sensor):
|
|
86
|
-
"""Sensor representing voltage [V] value encoded in 2 bytes"""
|
|
86
|
+
"""Sensor representing voltage [V] value encoded in 2 (unsigned) bytes"""
|
|
87
87
|
|
|
88
88
|
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
89
89
|
super().__init__(id_, offset, name, 2, "V", kind)
|
|
@@ -96,7 +96,7 @@ class Voltage(Sensor):
|
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
class Current(Sensor):
|
|
99
|
-
"""Sensor representing current [A] value encoded in 2 bytes"""
|
|
99
|
+
"""Sensor representing current [A] value encoded in 2 (unsigned) bytes"""
|
|
100
100
|
|
|
101
101
|
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
102
102
|
super().__init__(id_, offset, name, 2, "A", kind)
|
|
@@ -108,6 +108,19 @@ class Current(Sensor):
|
|
|
108
108
|
return encode_current(value)
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
class CurrentS(Sensor):
|
|
112
|
+
"""Sensor representing current [A] value encoded in 2 (signed) bytes"""
|
|
113
|
+
|
|
114
|
+
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
115
|
+
super().__init__(id_, offset, name, 2, "A", kind)
|
|
116
|
+
|
|
117
|
+
def read_value(self, data: ProtocolResponse):
|
|
118
|
+
return read_current_signed(data)
|
|
119
|
+
|
|
120
|
+
def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
|
|
121
|
+
return encode_current_signed(value)
|
|
122
|
+
|
|
123
|
+
|
|
111
124
|
class Frequency(Sensor):
|
|
112
125
|
"""Sensor representing frequency [Hz] value encoded in 2 bytes"""
|
|
113
126
|
|
|
@@ -119,7 +132,7 @@ class Frequency(Sensor):
|
|
|
119
132
|
|
|
120
133
|
|
|
121
134
|
class Power(Sensor):
|
|
122
|
-
"""Sensor representing power [W] value encoded in 2 bytes"""
|
|
135
|
+
"""Sensor representing power [W] value encoded in 2 (unsigned) bytes"""
|
|
123
136
|
|
|
124
137
|
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
125
138
|
super().__init__(id_, offset, name, 2, "W", kind)
|
|
@@ -128,8 +141,18 @@ class Power(Sensor):
|
|
|
128
141
|
return read_bytes2(data)
|
|
129
142
|
|
|
130
143
|
|
|
144
|
+
class PowerS(Sensor):
|
|
145
|
+
"""Sensor representing power [W] value encoded in 2 (signed) bytes"""
|
|
146
|
+
|
|
147
|
+
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
148
|
+
super().__init__(id_, offset, name, 2, "W", kind)
|
|
149
|
+
|
|
150
|
+
def read_value(self, data: ProtocolResponse):
|
|
151
|
+
return read_bytes2_signed(data)
|
|
152
|
+
|
|
153
|
+
|
|
131
154
|
class Power4(Sensor):
|
|
132
|
-
"""Sensor representing power [W] value encoded in 4 bytes"""
|
|
155
|
+
"""Sensor representing power [W] value encoded in 4 (unsigned) bytes"""
|
|
133
156
|
|
|
134
157
|
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
135
158
|
super().__init__(id_, offset, name, 4, "W", kind)
|
|
@@ -138,6 +161,16 @@ class Power4(Sensor):
|
|
|
138
161
|
return read_bytes4(data)
|
|
139
162
|
|
|
140
163
|
|
|
164
|
+
class Power4S(Sensor):
|
|
165
|
+
"""Sensor representing power [W] value encoded in 4 (signed) bytes"""
|
|
166
|
+
|
|
167
|
+
def __init__(self, id_: str, offset: int, name: str, kind: Optional[SensorKind]):
|
|
168
|
+
super().__init__(id_, offset, name, 4, "W", kind)
|
|
169
|
+
|
|
170
|
+
def read_value(self, data: ProtocolResponse):
|
|
171
|
+
return read_bytes4_signed(data)
|
|
172
|
+
|
|
173
|
+
|
|
141
174
|
class Energy(Sensor):
|
|
142
175
|
"""Sensor representing energy [kWh] value encoded in 2 bytes"""
|
|
143
176
|
|
|
@@ -146,10 +179,7 @@ class Energy(Sensor):
|
|
|
146
179
|
|
|
147
180
|
def read_value(self, data: ProtocolResponse):
|
|
148
181
|
value = read_bytes2(data)
|
|
149
|
-
|
|
150
|
-
return None
|
|
151
|
-
else:
|
|
152
|
-
return float(value) / 10
|
|
182
|
+
return float(value) / 10
|
|
153
183
|
|
|
154
184
|
|
|
155
185
|
class Energy4(Sensor):
|
|
@@ -160,10 +190,7 @@ class Energy4(Sensor):
|
|
|
160
190
|
|
|
161
191
|
def read_value(self, data: ProtocolResponse):
|
|
162
192
|
value = read_bytes4(data)
|
|
163
|
-
|
|
164
|
-
return None
|
|
165
|
-
else:
|
|
166
|
-
return float(value) / 10
|
|
193
|
+
return float(value) / 10
|
|
167
194
|
|
|
168
195
|
|
|
169
196
|
class Apparent(Sensor):
|
|
@@ -173,7 +200,7 @@ class Apparent(Sensor):
|
|
|
173
200
|
super().__init__(id_, offset, name, 2, "VA", kind)
|
|
174
201
|
|
|
175
202
|
def read_value(self, data: ProtocolResponse):
|
|
176
|
-
return
|
|
203
|
+
return read_bytes2_signed(data)
|
|
177
204
|
|
|
178
205
|
|
|
179
206
|
class Apparent4(Sensor):
|
|
@@ -183,7 +210,7 @@ class Apparent4(Sensor):
|
|
|
183
210
|
super().__init__(id_, offset, name, 2, "VA", kind)
|
|
184
211
|
|
|
185
212
|
def read_value(self, data: ProtocolResponse):
|
|
186
|
-
return
|
|
213
|
+
return read_bytes4_signed(data)
|
|
187
214
|
|
|
188
215
|
|
|
189
216
|
class Reactive(Sensor):
|
|
@@ -193,7 +220,7 @@ class Reactive(Sensor):
|
|
|
193
220
|
super().__init__(id_, offset, name, 2, "var", kind)
|
|
194
221
|
|
|
195
222
|
def read_value(self, data: ProtocolResponse):
|
|
196
|
-
return
|
|
223
|
+
return read_bytes2_signed(data)
|
|
197
224
|
|
|
198
225
|
|
|
199
226
|
class Reactive4(Sensor):
|
|
@@ -203,7 +230,7 @@ class Reactive4(Sensor):
|
|
|
203
230
|
super().__init__(id_, offset, name, 2, "var", kind)
|
|
204
231
|
|
|
205
232
|
def read_value(self, data: ProtocolResponse):
|
|
206
|
-
return
|
|
233
|
+
return read_bytes4_signed(data)
|
|
207
234
|
|
|
208
235
|
|
|
209
236
|
class Temp(Sensor):
|
|
@@ -277,7 +304,7 @@ class Integer(Sensor):
|
|
|
277
304
|
super().__init__(id_, offset, name, 2, unit, kind)
|
|
278
305
|
|
|
279
306
|
def read_value(self, data: ProtocolResponse):
|
|
280
|
-
return
|
|
307
|
+
return read_bytes2_signed(data)
|
|
281
308
|
|
|
282
309
|
def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
|
|
283
310
|
return int.to_bytes(int(value), length=2, byteorder="big", signed=True)
|
|
@@ -290,7 +317,7 @@ class Long(Sensor):
|
|
|
290
317
|
super().__init__(id_, offset, name, 4, unit, kind)
|
|
291
318
|
|
|
292
319
|
def read_value(self, data: ProtocolResponse):
|
|
293
|
-
return
|
|
320
|
+
return read_bytes4_signed(data)
|
|
294
321
|
|
|
295
322
|
def encode_value(self, value: Any, register_value: bytes = None) -> bytes:
|
|
296
323
|
return int.to_bytes(int(value), length=4, byteorder="big", signed=True)
|
|
@@ -390,7 +417,7 @@ class EnumBitmap4(Sensor):
|
|
|
390
417
|
raise NotImplementedError()
|
|
391
418
|
|
|
392
419
|
def read(self, data: ProtocolResponse):
|
|
393
|
-
bits =
|
|
420
|
+
bits = read_bytes4_signed(data, self.offset)
|
|
394
421
|
return decode_bitmap(bits if bits != -1 else 0, self._labels)
|
|
395
422
|
|
|
396
423
|
|
|
@@ -483,7 +510,7 @@ class EcoModeV1(Sensor, EcoMode):
|
|
|
483
510
|
self.end_m = read_byte(data)
|
|
484
511
|
if self.end_m < 0 or self.end_m > 59:
|
|
485
512
|
raise ValueError(f"{self.id_}: end_m value {self.end_m} out of range.")
|
|
486
|
-
self.power =
|
|
513
|
+
self.power = read_bytes2_signed(data) # negative=charge, positive=discharge
|
|
487
514
|
if self.power < -100 or self.power > 100:
|
|
488
515
|
raise ValueError(f"{self.id_}: power value {self.power} out of range.")
|
|
489
516
|
self.on_off = read_byte(data)
|
|
@@ -592,13 +619,13 @@ class Schedule(Sensor, EcoMode):
|
|
|
592
619
|
self.days = decode_day_of_week(self.day_bits)
|
|
593
620
|
if self.day_bits < 0:
|
|
594
621
|
raise ValueError(f"{self.id_}: day_bits value {self.day_bits} out of range.")
|
|
595
|
-
self.power =
|
|
622
|
+
self.power = read_bytes2_signed(data) # negative=charge, positive=discharge
|
|
596
623
|
if not self.schedule_type.is_in_range(self.power):
|
|
597
624
|
raise ValueError(f"{self.id_}: power value {self.power} out of range.")
|
|
598
|
-
self.soc =
|
|
625
|
+
self.soc = read_bytes2_signed(data)
|
|
599
626
|
if self.soc < 0 or self.soc > 100:
|
|
600
627
|
raise ValueError(f"{self.id_}: SoC value {self.soc} out of range.")
|
|
601
|
-
self.month_bits =
|
|
628
|
+
self.month_bits = read_bytes2_signed(data)
|
|
602
629
|
self.months = decode_months(self.month_bits)
|
|
603
630
|
return self
|
|
604
631
|
|
|
@@ -704,6 +731,14 @@ def read_byte(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
|
704
731
|
|
|
705
732
|
|
|
706
733
|
def read_bytes2(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
734
|
+
"""Retrieve 2 byte (unsigned int) value from buffer"""
|
|
735
|
+
if offset is not None:
|
|
736
|
+
buffer.seek(offset)
|
|
737
|
+
value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
|
|
738
|
+
return value if value != 0xffff else 0
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
def read_bytes2_signed(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
707
742
|
"""Retrieve 2 byte (signed int) value from buffer"""
|
|
708
743
|
if offset is not None:
|
|
709
744
|
buffer.seek(offset)
|
|
@@ -711,6 +746,14 @@ def read_bytes2(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
|
711
746
|
|
|
712
747
|
|
|
713
748
|
def read_bytes4(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
749
|
+
"""Retrieve 4 byte (unsigned int) value from buffer"""
|
|
750
|
+
if offset is not None:
|
|
751
|
+
buffer.seek(offset)
|
|
752
|
+
value = int.from_bytes(buffer.read(4), byteorder="big", signed=False)
|
|
753
|
+
return value if value != 0xffffffff else 0
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def read_bytes4_signed(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
714
757
|
"""Retrieve 4 byte (signed int) value from buffer"""
|
|
715
758
|
if offset is not None:
|
|
716
759
|
buffer.seek(offset)
|
|
@@ -736,20 +779,28 @@ def read_float4(buffer: ProtocolResponse, offset: int = None) -> float:
|
|
|
736
779
|
|
|
737
780
|
|
|
738
781
|
def read_voltage(buffer: ProtocolResponse, offset: int = None) -> float:
|
|
739
|
-
"""Retrieve voltage [V] value (2 bytes) from buffer"""
|
|
782
|
+
"""Retrieve voltage [V] value (2 unsigned bytes) from buffer"""
|
|
740
783
|
if offset is not None:
|
|
741
784
|
buffer.seek(offset)
|
|
742
|
-
value = int.from_bytes(buffer.read(2), byteorder="big", signed=
|
|
743
|
-
return float(value) / 10
|
|
785
|
+
value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
|
|
786
|
+
return float(value) / 10 if value != 0xffff else 0
|
|
744
787
|
|
|
745
788
|
|
|
746
789
|
def encode_voltage(value: Any) -> bytes:
|
|
747
|
-
"""Encode voltage value to raw (2 bytes) payload"""
|
|
748
|
-
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=
|
|
790
|
+
"""Encode voltage value to raw (2 unsigned bytes) payload"""
|
|
791
|
+
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=False)
|
|
749
792
|
|
|
750
793
|
|
|
751
794
|
def read_current(buffer: ProtocolResponse, offset: int = None) -> float:
|
|
752
|
-
"""Retrieve current [A] value (2 bytes) from buffer"""
|
|
795
|
+
"""Retrieve current [A] value (2 unsigned bytes) from buffer"""
|
|
796
|
+
if offset is not None:
|
|
797
|
+
buffer.seek(offset)
|
|
798
|
+
value = int.from_bytes(buffer.read(2), byteorder="big", signed=False)
|
|
799
|
+
return float(value) / 10 if value != 0xffff else 0
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def read_current_signed(buffer: ProtocolResponse, offset: int = None) -> float:
|
|
803
|
+
"""Retrieve current [A] value (2 signed bytes) from buffer"""
|
|
753
804
|
if offset is not None:
|
|
754
805
|
buffer.seek(offset)
|
|
755
806
|
value = int.from_bytes(buffer.read(2), byteorder="big", signed=True)
|
|
@@ -757,7 +808,12 @@ def read_current(buffer: ProtocolResponse, offset: int = None) -> float:
|
|
|
757
808
|
|
|
758
809
|
|
|
759
810
|
def encode_current(value: Any) -> bytes:
|
|
760
|
-
"""Encode current value to raw (2 bytes) payload"""
|
|
811
|
+
"""Encode current value to raw (2 unsigned bytes) payload"""
|
|
812
|
+
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=False)
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
def encode_current_signed(value: Any) -> bytes:
|
|
816
|
+
"""Encode current value to raw (2 signed bytes) payload"""
|
|
761
817
|
return int.to_bytes(int(value * 10), length=2, byteorder="big", signed=True)
|
|
762
818
|
|
|
763
819
|
|
|
@@ -809,7 +865,7 @@ def encode_datetime(value: Any) -> bytes:
|
|
|
809
865
|
|
|
810
866
|
def read_grid_mode(buffer: ProtocolResponse, offset: int = None) -> int:
|
|
811
867
|
"""Retrieve 'grid mode' sign value from buffer"""
|
|
812
|
-
value =
|
|
868
|
+
value = read_bytes2_signed(buffer, offset)
|
|
813
869
|
if value < -90:
|
|
814
870
|
return 2
|
|
815
871
|
elif value >= 90:
|
|
@@ -64,9 +64,9 @@ class GW6000_DT_Test(DtMock):
|
|
|
64
64
|
self.assertSensor('vpv3', None, 'V', data)
|
|
65
65
|
self.assertSensor('ipv3', None, 'A', data)
|
|
66
66
|
self.assertSensor('ppv3', None, 'W', data)
|
|
67
|
-
self.assertSensor('vline1',
|
|
68
|
-
self.assertSensor('vline2',
|
|
69
|
-
self.assertSensor('vline3',
|
|
67
|
+
self.assertSensor('vline1', 0, 'V', data)
|
|
68
|
+
self.assertSensor('vline2', 0, 'V', data)
|
|
69
|
+
self.assertSensor('vline3', 0, 'V', data)
|
|
70
70
|
self.assertSensor('vgrid1', 225.6, 'V', data)
|
|
71
71
|
self.assertSensor('vgrid2', 229.7, 'V', data)
|
|
72
72
|
self.assertSensor('vgrid3', 231.0, 'V', data)
|
|
@@ -167,8 +167,8 @@ class GW8K_DT_Test(DtMock):
|
|
|
167
167
|
self.assertSensor("apparent_power", 0, "VA", data),
|
|
168
168
|
self.assertSensor("reactive_power", 0, "var", data),
|
|
169
169
|
self.assertSensor('temperature', 45.3, 'C', data)
|
|
170
|
-
self.assertSensor('e_day',
|
|
171
|
-
self.assertSensor('e_total',
|
|
170
|
+
self.assertSensor('e_day', 0.0, 'kWh', data)
|
|
171
|
+
self.assertSensor('e_total', 0.0, 'kWh', data)
|
|
172
172
|
self.assertSensor('h_total', -1, 'h', data)
|
|
173
173
|
self.assertSensor('safety_country', 32, '', data)
|
|
174
174
|
self.assertSensor('safety_country_label', '50Hz 230Vac Default', '', data)
|
|
@@ -208,7 +208,7 @@ class GW5000D_NS_Test(DtMock):
|
|
|
208
208
|
self.assertSensor('vpv2', 291.8, 'V', data)
|
|
209
209
|
self.assertSensor('ipv2', 0, 'A', data)
|
|
210
210
|
self.assertSensor('ppv2', 0, 'W', data)
|
|
211
|
-
self.assertSensor('vline1',
|
|
211
|
+
self.assertSensor('vline1', 0, 'V', data)
|
|
212
212
|
self.assertSensor('vgrid1', 240.5, 'V', data)
|
|
213
213
|
self.assertSensor('igrid1', 0.0, 'A', data)
|
|
214
214
|
self.assertSensor('fgrid1', 49.97, 'Hz', data)
|
|
@@ -228,7 +228,7 @@ class GW5000D_NS_Test(DtMock):
|
|
|
228
228
|
self.assertSensor('safety_country_label', 'Australia Victoria', '', data)
|
|
229
229
|
self.assertSensor('funbit', 2400, '', data)
|
|
230
230
|
self.assertSensor('vbus', 291.7, 'V', data)
|
|
231
|
-
self.assertSensor('vnbus',
|
|
231
|
+
self.assertSensor('vnbus', 0, 'V', data)
|
|
232
232
|
self.assertSensor('derating_mode', -1, '', data)
|
|
233
233
|
self.assertSensor('derating_mode_label', '', '', data)
|
|
234
234
|
|
|
@@ -274,7 +274,7 @@ class GW5000_MS_Test(DtMock):
|
|
|
274
274
|
self.assertSensor('vpv3', 143.2, 'V', data)
|
|
275
275
|
self.assertSensor('ipv3', 0.4, 'A', data)
|
|
276
276
|
self.assertSensor('ppv3', 57, 'W', data)
|
|
277
|
-
self.assertSensor('vline1',
|
|
277
|
+
self.assertSensor('vline1', 0, 'V', data)
|
|
278
278
|
self.assertSensor('vgrid1', 240.1, 'V', data)
|
|
279
279
|
self.assertSensor('igrid1', 0.9, 'A', data)
|
|
280
280
|
self.assertSensor('fgrid1', 49.98, 'Hz', data)
|
|
@@ -294,7 +294,7 @@ class GW5000_MS_Test(DtMock):
|
|
|
294
294
|
self.assertSensor('safety_country_label', 'Australia Victoria', '', data)
|
|
295
295
|
self.assertSensor('funbit', 2384, '', data)
|
|
296
296
|
self.assertSensor('vbus', 393.9, 'V', data)
|
|
297
|
-
self.assertSensor('vnbus',
|
|
297
|
+
self.assertSensor('vnbus', 0, 'V', data)
|
|
298
298
|
self.assertSensor('derating_mode', -1, '', data)
|
|
299
299
|
self.assertSensor('derating_mode_label', '', '', data)
|
|
300
300
|
|
|
@@ -438,7 +438,7 @@ class GW6000_EH_Test(EtMock):
|
|
|
438
438
|
self.assertSensor('temperature', 38.6, 'C', data)
|
|
439
439
|
self.assertSensor('function_bit', 256, '', data)
|
|
440
440
|
self.assertSensor('bus_voltage', 380.6, 'V', data)
|
|
441
|
-
self.assertSensor('nbus_voltage',
|
|
441
|
+
self.assertSensor('nbus_voltage', 0, 'V', data)
|
|
442
442
|
self.assertSensor('vbattery1', 0.0, 'V', data)
|
|
443
443
|
self.assertSensor('ibattery1', 0.1, 'A', data)
|
|
444
444
|
self.assertSensor('pbattery1', 0, 'W', data)
|
|
@@ -469,7 +469,7 @@ class GW6000_EH_Test(EtMock):
|
|
|
469
469
|
self.assertSensor('diagnose_result_label',
|
|
470
470
|
'Battery voltage low, Battery SOC low, Battery SOC in back, Discharge Driver On, Self-use load light, Battery Disconnected, Self-use off, Export power limit set, PF value set, Real power limit set',
|
|
471
471
|
'', data)
|
|
472
|
-
self.assertSensor('house_consumption',
|
|
472
|
+
self.assertSensor('house_consumption', 1712, 'W', data)
|
|
473
473
|
|
|
474
474
|
|
|
475
475
|
class GEH10_1U_10_Test(EtMock):
|
|
@@ -539,7 +539,7 @@ class GEH10_1U_10_Test(EtMock):
|
|
|
539
539
|
self.assertSensor('temperature', 67.0, 'C', data)
|
|
540
540
|
self.assertSensor('function_bit', 257, '', data)
|
|
541
541
|
self.assertSensor('bus_voltage', 458.4, 'V', data)
|
|
542
|
-
self.assertSensor('nbus_voltage',
|
|
542
|
+
self.assertSensor('nbus_voltage', 0, 'V', data)
|
|
543
543
|
self.assertSensor('vbattery1', 406.1, 'V', data)
|
|
544
544
|
self.assertSensor('ibattery1', -3.8, 'A', data)
|
|
545
545
|
self.assertSensor('pbattery1', -1566, 'W', data)
|
|
@@ -78,6 +78,12 @@ class TestUtils(TestCase):
|
|
|
78
78
|
self.assertEqual(803.6, testee.read(data))
|
|
79
79
|
self.assertEqual("1f64", testee.encode_value(803.6).hex())
|
|
80
80
|
|
|
81
|
+
data = MockResponse("a000")
|
|
82
|
+
self.assertEqual(4096.0, testee.read(data))
|
|
83
|
+
|
|
84
|
+
data = MockResponse("ffff")
|
|
85
|
+
self.assertEqual(0, testee.read(data))
|
|
86
|
+
|
|
81
87
|
def test_current(self):
|
|
82
88
|
testee = Current("", 0, "", None)
|
|
83
89
|
|
|
@@ -85,6 +91,20 @@ class TestUtils(TestCase):
|
|
|
85
91
|
self.assertEqual(4.9, testee.read(data))
|
|
86
92
|
self.assertEqual("0031", testee.encode_value(4.9).hex())
|
|
87
93
|
|
|
94
|
+
data = MockResponse("ff9e")
|
|
95
|
+
self.assertEqual(6543.8, testee.read(data))
|
|
96
|
+
self.assertEqual("ff9e", testee.encode_value(6543.8).hex())
|
|
97
|
+
|
|
98
|
+
data = MockResponse("ffff")
|
|
99
|
+
self.assertEqual(0, testee.read(data))
|
|
100
|
+
|
|
101
|
+
def test_current_signed(self):
|
|
102
|
+
testee = CurrentS("", 0, "", None)
|
|
103
|
+
|
|
104
|
+
data = MockResponse("0031")
|
|
105
|
+
self.assertEqual(4.9, testee.read(data))
|
|
106
|
+
self.assertEqual("0031", testee.encode_value(4.9).hex())
|
|
107
|
+
|
|
88
108
|
data = MockResponse("ff9e")
|
|
89
109
|
self.assertEqual(-9.8, testee.read(data))
|
|
90
110
|
self.assertEqual("ff9e", testee.encode_value(-9.8).hex())
|
|
@@ -95,6 +115,18 @@ class TestUtils(TestCase):
|
|
|
95
115
|
data = MockResponse("0000069f")
|
|
96
116
|
self.assertEqual(1695, testee.read(data))
|
|
97
117
|
|
|
118
|
+
data = MockResponse("fffffffd")
|
|
119
|
+
self.assertEqual(4294967293, testee.read(data))
|
|
120
|
+
|
|
121
|
+
data = MockResponse("ffffffff")
|
|
122
|
+
self.assertEqual(0, testee.read(data))
|
|
123
|
+
|
|
124
|
+
def test_power4_signed(self):
|
|
125
|
+
testee = Power4S("", 0, "", None)
|
|
126
|
+
|
|
127
|
+
data = MockResponse("0000069f")
|
|
128
|
+
self.assertEqual(1695, testee.read(data))
|
|
129
|
+
|
|
98
130
|
data = MockResponse("fffffffd")
|
|
99
131
|
self.assertEqual(-3, testee.read(data))
|
|
100
132
|
|
|
@@ -110,7 +142,7 @@ class TestUtils(TestCase):
|
|
|
110
142
|
data = MockResponse("00020972")
|
|
111
143
|
self.assertEqual(13349.0, testee.read(data))
|
|
112
144
|
data = MockResponse("ffffffff")
|
|
113
|
-
self.
|
|
145
|
+
self.assertEqual(0.0, testee.read(data))
|
|
114
146
|
|
|
115
147
|
def test_timestamp(self):
|
|
116
148
|
testee = Timestamp("", 0, "", None)
|
goodwe-0.3.1/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.3.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|