aiocomfoconnect 0.2.1__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.
@@ -1,17 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiocomfoconnect
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: aiocomfoconnect is an asyncio Python 3 library for communicating with a Zehnder ComfoAir Q350/450/600 ventilation system
5
5
  License-File: LICENSE
6
6
  Author: Michaël Arnauts
7
7
  Author-email: michael.arnauts@gmail.com
8
- Requires-Python: >=3.10,<4.0
8
+ Requires-Python: >=3.13,<4.0
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
10
  Classifier: Programming Language :: Python :: 3.13
14
11
  Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Programming Language :: Python :: 3.15
15
13
  Requires-Dist: aiohttp (>=3.8.0,<4.0.0)
16
14
  Requires-Dist: protobuf (>=6.31,<8)
17
15
  Project-URL: Homepage, https://github.com/michaelarnauts/aiocomfoconnect
@@ -24,7 +22,7 @@ Description-Content-Type: text/markdown
24
22
 
25
23
  The [home-assistant-comfoconnect](https://github.com/michaelarnauts/home-assistant-comfoconnect) is using this library.
26
24
 
27
- It's compatible with Python 3.10 and higher.
25
+ It's compatible with Python 3.13 and higher.
28
26
 
29
27
  ## Installation
30
28
 
@@ -65,7 +63,7 @@ $ python -m aiocomfoconnect get-property --host 192.168.1.213 1 1 8 9 # Unit 0x
65
63
  - `async register_sensor(sensor)`: Register a sensor.
66
64
  - `async deregister_sensor(sensor)`: Deregister a sensor.
67
65
  - `async get_mode()`: Get the ventilation mode.
68
- - `async set_mode(mode)`: Set the ventilation mode. (auto / manual)
66
+ - `async set_mode(mode)`: Set the ventilation mode. (auto / manual) Selecting `auto` also cancels the temporary fan-speed override and returns control to the unit's schedule.
69
67
  - `async get_comfocool_mode()`: Get Comfocool mode
70
68
  - `async set_comfocool_mode()`: Set Comfocool mode. (auto / off)
71
69
  - `async get_speed()`: Get the ventilation speed.
@@ -5,7 +5,7 @@
5
5
 
6
6
  The [home-assistant-comfoconnect](https://github.com/michaelarnauts/home-assistant-comfoconnect) is using this library.
7
7
 
8
- It's compatible with Python 3.10 and higher.
8
+ It's compatible with Python 3.13 and higher.
9
9
 
10
10
  ## Installation
11
11
 
@@ -46,7 +46,7 @@ $ python -m aiocomfoconnect get-property --host 192.168.1.213 1 1 8 9 # Unit 0x
46
46
  - `async register_sensor(sensor)`: Register a sensor.
47
47
  - `async deregister_sensor(sensor)`: Deregister a sensor.
48
48
  - `async get_mode()`: Get the ventilation mode.
49
- - `async set_mode(mode)`: Set the ventilation mode. (auto / manual)
49
+ - `async set_mode(mode)`: Set the ventilation mode. (auto / manual) Selecting `auto` also cancels the temporary fan-speed override and returns control to the unit's schedule.
50
50
  - `async get_comfocool_mode()`: Get Comfocool mode
51
51
  - `async set_comfocool_mode()`: Set Comfocool mode. (auto / off)
52
52
  - `async get_speed()`: Get the ventilation speed.
@@ -13,7 +13,7 @@ from typing import Awaitable, Callable, Dict, Iterator, Optional, Set
13
13
  from google.protobuf.message import DecodeError
14
14
  from google.protobuf.message import Message as ProtobufMessage
15
15
 
16
- from .const import VENTILATION_UNIT_PRODUCT_IDS
16
+ from .const import VENTILATION_UNIT_PRODUCT_IDS, PdoType
17
17
  from .exceptions import (
18
18
  AioComfoConnectNotConnected,
19
19
  AioComfoConnectNotReachable,
@@ -134,6 +134,7 @@ class Bridge:
134
134
  self._ventilation_node_found: Optional[asyncio.Event] = None
135
135
 
136
136
  self.__sensor_callback_fn: Optional[Callable[[int, int], None]] = None
137
+ self._sensor_pdo_types: Dict[int, int] = {}
137
138
  self.__alarm_callback_fn: Optional[Callable[[int, ProtobufMessage], None]] = None
138
139
 
139
140
  self._loop: Optional[asyncio.AbstractEventLoop] = loop
@@ -424,7 +425,9 @@ class Bridge:
424
425
  # pylint: disable=no-member
425
426
  if message.cmd.type == zehnder_pb2.GatewayOperation.CnRpdoNotificationType:
426
427
  if self.__sensor_callback_fn:
427
- self.__sensor_callback_fn(message.msg.pdid, int.from_bytes(message.msg.data, byteorder="little", signed=True))
428
+ pdo_type = self._sensor_pdo_types.get(message.msg.pdid)
429
+ signed = pdo_type not in (PdoType.TYPE_CN_UINT8, PdoType.TYPE_CN_UINT16, PdoType.TYPE_CN_UINT32)
430
+ self.__sensor_callback_fn(message.msg.pdid, int.from_bytes(message.msg.data, byteorder="little", signed=signed))
428
431
  else:
429
432
  _LOGGER.info("Unhandled CnRpdoNotificationType since no callback is registered.")
430
433
 
@@ -572,6 +575,8 @@ class Bridge:
572
575
  def cmd_rpdo_request(self, pdid: int, pdo_type: int = 1, zone: int = 1, timeout=None) -> Awaitable[Message]:
573
576
  """Register a RPDO request."""
574
577
  _LOGGER.debug("CnRpdoRequest")
578
+ # Notifications can arrive before the subscription acknowledgement.
579
+ self._sensor_pdo_types[pdid] = pdo_type
575
580
  # pylint: disable=no-member
576
581
  return self._send(
577
582
  zehnder_pb2.CnRpdoRequest,
@@ -301,9 +301,14 @@ class ComfoConnect(Bridge):
301
301
 
302
302
  self._sensors_values[sensor_id] = sensor_value
303
303
 
304
- # Don't emit sensor values until we have received all the initial values.
304
+ # The bridge sends invalid (zero) values right after we subscribe to a sensor, so we hold them back.
305
+ # A non-zero value is a real value, so we can release the hold and emit it right away.
305
306
  if sensor_id in self._sensor_holds:
306
- return
307
+ if not sensor_value:
308
+ return
309
+
310
+ _LOGGER.debug("Got a valid value for sensor %s, releasing the hold", sensor_id)
311
+ self._sensor_holds.pop(sensor_id).cancel()
307
312
 
308
313
  if sensor.value_fn:
309
314
  val = sensor.value_fn(sensor_value)
@@ -335,9 +340,10 @@ class ComfoConnect(Bridge):
335
340
  return VentilationMode.MANUAL if mode == 1 else VentilationMode.AUTO
336
341
 
337
342
  async def set_mode(self, mode: Literal["auto", "manual"]):
338
- """Set the ventilation mode (auto / manual)."""
343
+ """Set ventilation mode, cancelling the temporary speed override for auto."""
339
344
  if mode == VentilationMode.AUTO:
340
345
  await self.cmd_rmi_request(bytes([0x85, UNIT_SCHEDULE, SUBUNIT_08, 0x01]))
346
+ await self.cmd_rmi_request(bytes([0x85, UNIT_SCHEDULE, SUBUNIT_01, 0x01]))
341
347
  elif mode == VentilationMode.MANUAL:
342
348
  await self.cmd_rmi_request(bytes([0x84, UNIT_SCHEDULE, SUBUNIT_08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01]))
343
349
  else:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "aiocomfoconnect"
3
- version = "0.2.1"
3
+ version = "0.3.0"
4
4
  description = "aiocomfoconnect is an asyncio Python 3 library for communicating with a Zehnder ComfoAir Q350/450/600 ventilation system"
5
5
  authors = ["Michaël Arnauts <michael.arnauts@gmail.com>"]
6
6
  readme = "README.md"
@@ -10,7 +10,7 @@ homepage = "https://github.com/michaelarnauts/aiocomfoconnect"
10
10
  aiocomfoconnect = "aiocomfoconnect.__main__:main_cli"
11
11
 
12
12
  [tool.poetry.dependencies]
13
- python = "^3.10"
13
+ python = "^3.13"
14
14
  aiohttp = "^3.8.0"
15
15
  protobuf = ">=6.31,<8"
16
16
 
@@ -20,8 +20,8 @@ dpkt = "^1.9.8"
20
20
  black = "^24.4.0"
21
21
  isort = "^5.10.1"
22
22
  pylint = "^3.2"
23
- pytest = "^8.2.0"
24
- pytest-asyncio = "^0.23.0"
23
+ pytest = "^8.4"
24
+ pytest-asyncio = "^1.4.0"
25
25
 
26
26
  [build-system]
27
27
  requires = ["poetry-core"]
@@ -31,7 +31,7 @@ build-backend = "poetry.core.masonry.api"
31
31
  profile = "black"
32
32
 
33
33
  [tool.black]
34
- target-version = ["py310"]
34
+ target-version = ["py313"]
35
35
  line-length = 180
36
36
 
37
37
  [tool.pylint.MAIN]
File without changes