python-qube-heatpump 1.4.2__tar.gz → 1.4.4__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.
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/PKG-INFO +1 -1
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/pyproject.toml +1 -1
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/client.py +52 -28
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/workflows/ci.yml +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/workflows/python-publish.yml +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.gitignore +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/AGENTS.md +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/CLAUDE.md +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/LICENSE +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/README.md +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/pytest.ini +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/__init__.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/const.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/entities/__init__.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/entities/base.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/entities/binary_sensors.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/entities/sensors.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/entities/switches.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/models.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/py.typed +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/tests/conftest.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/tests/test_client.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/tests/test_const.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/tests/test_entities.py +0 -0
- {python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/tests/test_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-qube-heatpump
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.4
|
|
4
4
|
Summary: Async Modbus client for Qube Heat Pumps
|
|
5
5
|
Project-URL: Homepage, https://github.com/MattieGit/python-qube-heatpump
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/MattieGit/python-qube-heatpump/issues
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/client.py
RENAMED
|
@@ -162,18 +162,14 @@ class QubeClient:
|
|
|
162
162
|
# Full 32-bit int: (Reg1 << 16) | Reg0
|
|
163
163
|
# Then pack as >I (Big Endian 32-bit int) and unpack as >f (Big Endian float)?
|
|
164
164
|
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
# So:
|
|
170
|
-
# 32-bit value = (regs[1] << 16) | regs[0]
|
|
171
|
-
# Then interpret that 32-bit integer as a float.
|
|
172
|
-
# To interpret int bits as float in Python: struct.unpack('!f', struct.pack('!I', int_val))[0]
|
|
165
|
+
# Qube uses Big Endian word order (ABCD format):
|
|
166
|
+
# regs[0] = MSW (Most Significant Word)
|
|
167
|
+
# regs[1] = LSW (Least Significant Word)
|
|
168
|
+
# 32-bit value = (regs[0] << 16) | regs[1]
|
|
173
169
|
|
|
174
170
|
if data_type == const.DataType.FLOAT32:
|
|
175
|
-
# Combine 2 registers,
|
|
176
|
-
int_val = (regs[
|
|
171
|
+
# Combine 2 registers, Big Endian Word Order
|
|
172
|
+
int_val = (regs[0] << 16) | regs[1]
|
|
177
173
|
val = struct.unpack(">f", struct.pack(">I", int_val))[0]
|
|
178
174
|
elif data_type == const.DataType.INT16:
|
|
179
175
|
val = regs[0]
|
|
@@ -183,9 +179,11 @@ class QubeClient:
|
|
|
183
179
|
elif data_type == const.DataType.UINT16:
|
|
184
180
|
val = regs[0]
|
|
185
181
|
elif data_type == const.DataType.UINT32:
|
|
186
|
-
|
|
182
|
+
int_val = (regs[0] << 16) | regs[1]
|
|
183
|
+
val = int_val
|
|
187
184
|
elif data_type == const.DataType.INT32:
|
|
188
|
-
|
|
185
|
+
int_val = (regs[0] << 16) | regs[1]
|
|
186
|
+
val = int_val
|
|
189
187
|
if val > 2147483647:
|
|
190
188
|
val -= 4294967296
|
|
191
189
|
else:
|
|
@@ -212,14 +210,23 @@ class QubeClient:
|
|
|
212
210
|
The read value (float, int, or bool depending on entity type).
|
|
213
211
|
"""
|
|
214
212
|
# Determine register count based on data type
|
|
215
|
-
|
|
213
|
+
# Use string comparison to handle potential enum class differences
|
|
214
|
+
data_type_str = entity.data_type.value if entity.data_type else None
|
|
215
|
+
if data_type_str in ("float32", "uint32", "int32"):
|
|
216
216
|
count = 2
|
|
217
217
|
else:
|
|
218
218
|
count = 1
|
|
219
219
|
|
|
220
|
+
_LOGGER.debug(
|
|
221
|
+
"read_entity: key=%s addr=%s input_type=%s data_type=%s count=%s",
|
|
222
|
+
entity.key, entity.address, entity.input_type, data_type_str, count
|
|
223
|
+
)
|
|
224
|
+
|
|
220
225
|
try:
|
|
221
|
-
# Read based on input type
|
|
222
|
-
if entity.input_type
|
|
226
|
+
# Read based on input type (use string comparison for safety)
|
|
227
|
+
input_type_str = entity.input_type.value if entity.input_type else None
|
|
228
|
+
|
|
229
|
+
if input_type_str == "coil":
|
|
223
230
|
result = await self._client.read_coils(
|
|
224
231
|
entity.address, count=1, device_id=self.unit
|
|
225
232
|
)
|
|
@@ -228,7 +235,7 @@ class QubeClient:
|
|
|
228
235
|
return None
|
|
229
236
|
return bool(result.bits[0])
|
|
230
237
|
|
|
231
|
-
if
|
|
238
|
+
if input_type_str == "discrete_input":
|
|
232
239
|
result = await self._client.read_discrete_inputs(
|
|
233
240
|
entity.address, count=1, device_id=self.unit
|
|
234
241
|
)
|
|
@@ -237,11 +244,11 @@ class QubeClient:
|
|
|
237
244
|
return None
|
|
238
245
|
return bool(result.bits[0])
|
|
239
246
|
|
|
240
|
-
if
|
|
247
|
+
if input_type_str == "input":
|
|
241
248
|
result = await self._client.read_input_registers(
|
|
242
249
|
entity.address, count=count, device_id=self.unit
|
|
243
250
|
)
|
|
244
|
-
else: #
|
|
251
|
+
else: # holding
|
|
245
252
|
result = await self._client.read_holding_registers(
|
|
246
253
|
entity.address, count=count, device_id=self.unit
|
|
247
254
|
)
|
|
@@ -253,20 +260,31 @@ class QubeClient:
|
|
|
253
260
|
regs = result.registers
|
|
254
261
|
val: float | int = 0
|
|
255
262
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
263
|
+
_LOGGER.debug(
|
|
264
|
+
"read_entity: key=%s raw_regs=%s", entity.key, regs
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Decode based on data type (use string comparison for safety)
|
|
268
|
+
# Qube uses big endian word order (ABCD): regs[0]=MSW, regs[1]=LSW
|
|
269
|
+
if data_type_str == "float32":
|
|
270
|
+
int_val = (regs[0] << 16) | regs[1]
|
|
259
271
|
val = struct.unpack(">f", struct.pack(">I", int_val))[0]
|
|
260
|
-
|
|
272
|
+
_LOGGER.debug(
|
|
273
|
+
"read_entity: key=%s float32 int_val=%s decoded=%s",
|
|
274
|
+
entity.key, int_val, val
|
|
275
|
+
)
|
|
276
|
+
elif data_type_str == "int16":
|
|
261
277
|
val = regs[0]
|
|
262
278
|
if val > 32767:
|
|
263
279
|
val -= 65536
|
|
264
|
-
elif
|
|
280
|
+
elif data_type_str == "uint16":
|
|
265
281
|
val = regs[0]
|
|
266
|
-
elif
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
282
|
+
elif data_type_str == "uint32":
|
|
283
|
+
int_val = (regs[0] << 16) | regs[1]
|
|
284
|
+
val = int_val
|
|
285
|
+
elif data_type_str == "int32":
|
|
286
|
+
int_val = (regs[0] << 16) | regs[1]
|
|
287
|
+
val = int_val
|
|
270
288
|
if val > 2147483647:
|
|
271
289
|
val -= 4294967296
|
|
272
290
|
|
|
@@ -276,6 +294,11 @@ class QubeClient:
|
|
|
276
294
|
if entity.offset is not None:
|
|
277
295
|
val = val + entity.offset
|
|
278
296
|
|
|
297
|
+
_LOGGER.debug(
|
|
298
|
+
"read_entity: key=%s final_value=%s (scale=%s, offset=%s)",
|
|
299
|
+
entity.key, val, entity.scale, entity.offset
|
|
300
|
+
)
|
|
301
|
+
|
|
279
302
|
return val
|
|
280
303
|
|
|
281
304
|
except Exception as e:
|
|
@@ -425,9 +448,10 @@ class QubeClient:
|
|
|
425
448
|
# Encode based on data type
|
|
426
449
|
if entity.data_type == DataType.FLOAT32:
|
|
427
450
|
# Pack as big-endian float, then split into two registers
|
|
451
|
+
# Big Endian word order: regs[0]=MSW, regs[1]=LSW
|
|
428
452
|
packed = struct.pack(">f", write_value)
|
|
429
453
|
int_val = struct.unpack(">I", packed)[0]
|
|
430
|
-
regs = [int_val & 0xFFFF,
|
|
454
|
+
regs = [(int_val >> 16) & 0xFFFF, int_val & 0xFFFF]
|
|
431
455
|
result = await self._client.write_registers(
|
|
432
456
|
entity.address, regs, device_id=self.unit
|
|
433
457
|
)
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/ISSUE_TEMPLATE/bug_report.yml
RENAMED
|
File without changes
|
|
File without changes
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/ISSUE_TEMPLATE/feature_request.yml
RENAMED
|
File without changes
|
|
File without changes
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/.github/workflows/python-publish.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/entities/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_qube_heatpump-1.4.2 → python_qube_heatpump-1.4.4}/src/python_qube_heatpump/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|