velbus-aio 2025.4.2__py3-none-any.whl → 2025.5.0__py3-none-any.whl

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.

Potentially problematic release.


This version of velbus-aio might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velbus-aio
3
- Version: 2025.4.2
3
+ Version: 2025.5.0
4
4
  Summary: Open-source home automation platform running on Python 3.
5
5
  Author-email: Maikel Punie <maikel.punie@gmail.com>
6
6
  License: MIT
@@ -1,4 +1,4 @@
1
- velbus_aio-2025.4.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1
+ velbus_aio-2025.5.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
2
2
  velbusaio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  velbusaio/channels.py,sha256=pR-y7Res_MAPSFEM62eLx844HU0EjX7SyyEpJT4YU74,23556
4
4
  velbusaio/command_registry.py,sha256=nlx4__0ASr5WurOYLC-HEqswlg_qm3Y5trs4V8FhnvU,5350
@@ -6,15 +6,15 @@ velbusaio/const.py,sha256=aHClMaMS6NINTCrjeRwLbVzdvS91VgFKM8j61ks5tn0,1862
6
6
  velbusaio/controller.py,sha256=Ohc-18ydnm76-5fOD_b24Aa_uYu6CdkI3ulfhska5og,8887
7
7
  velbusaio/discovery.py,sha256=Px6qoZl4QhF17aMz6JxstCORBpLzZGWEK9h4Vyvg57o,1649
8
8
  velbusaio/exceptions.py,sha256=FHkXaM3dK5Gkk-QGAf9dLE3FPlCU2FRZWUyY-4KRNnA,515
9
- velbusaio/handler.py,sha256=gkRikfrTzekL0hFQSUV0AjVuMoUY1DNONEhbRBKyRko,11901
9
+ velbusaio/handler.py,sha256=DmL6dTbolJUD9yRaeKj1vr29eSx4zkDwVtS8fPeAs8I,11906
10
10
  velbusaio/helpers.py,sha256=iqpoereRH4JY5WAkozIqWvXWyRmhko-J-UGXDylFyEM,2537
11
11
  velbusaio/message.py,sha256=_MRuI4XnMcqeduCDJ3AwhAPL1B8VMstFDnjjLo8QuxM,5018
12
- velbusaio/module.py,sha256=y5uegbCl0vowBqoeagycRjP6FPLDPaGJ4ZJeW22wMqA,37631
12
+ velbusaio/module.py,sha256=pfYaUgMrbhYCWle8byqjYZvMhw2ikE-Ff5uAxKhY59w,37938
13
13
  velbusaio/protocol.py,sha256=RIpdL0vPlL4qE4bC8sEZSD0SRS4tWtR9MdzjTPSd2zs,8002
14
14
  velbusaio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  velbusaio/raw_message.py,sha256=ODoTPVAvyXXQSMXxtQO1U5OxcoQ4W8JJN5fotEDGSTo,4690
16
16
  velbusaio/util.py,sha256=FW6YCiPYWOCgqHDs8-LbzME0h81mqftYVG0qqZ-oo7Y,1568
17
- velbusaio/vlp_reader.py,sha256=mHhp0Le-u8PT0Nk3glZrB7qK4JFR906NyB-nHDlnYC8,1039
17
+ velbusaio/vlp_reader.py,sha256=2oSbBOR2bgaSGnL1JP8TJaHgbY20ZgmCfSivtINuiR8,3997
18
18
  velbusaio/messages/__init__.py,sha256=2Zgrk4VBoSJXKYhwS18gxuiE96jDvnpBBjeYI1yHjqs,6072
19
19
  velbusaio/messages/blind_status.py,sha256=q2CQgcU1ZsXMyjR2co8Eegj0LZRDfRqvpCTVvjovNWA,3432
20
20
  velbusaio/messages/bus_active.py,sha256=AB1mEvbMXRuOaC2CQ7hzKSLmbaJnyFqqXrARi-aSdtg,749
@@ -35,9 +35,9 @@ velbusaio/messages/cover_position.py,sha256=_BgQz3DqZGirXDthj7xq72hxr51FYv2tyrdC
35
35
  velbusaio/messages/cover_up.py,sha256=iFPCWuRhIc54oMQAFz5DZsUW23673_nNHoPFJC_HA_c,2561
36
36
  velbusaio/messages/dali_device_settings.py,sha256=KzJ7OFkFRPuCXSOThuplM48J_kH0I3RE82ZRCpmiqYA,4870
37
37
  velbusaio/messages/dali_device_settings_request.py,sha256=InTnrwLD7l9gCHXKlJ69FHMXcejtYMUZBtnffx9nDQU,1476
38
- velbusaio/messages/dali_dim_value_status.py,sha256=Kgtfb65HCku4OBm6uaxKFpK3VtlYaTemSjMhZqngqkY,1059
38
+ velbusaio/messages/dali_dim_value_status.py,sha256=MS3bWgBYUsQ9w7jrRRUI8QoQmziTVCYExfweAezT2E0,1089
39
39
  velbusaio/messages/dimmer_channel_status.py,sha256=v3VszfQoPY05Dt3yzyWIlOJTKSXE1IP044x1x_sLHj4,2501
40
- velbusaio/messages/dimmer_status.py,sha256=pWsWXJGWmYGio4FyUktI9aYnIBQkGCQ5ZwaeqnenYsU,2938
40
+ velbusaio/messages/dimmer_status.py,sha256=AikJN-jfdFy8rXrGMSMfrhFcYE1yHlorffxk-bcKCXU,3067
41
41
  velbusaio/messages/edge_set_color.py,sha256=YhxTv-WtDrZ_O67Ro6V-bcHrxj3tyBI1GuzTI5LkIVw,3306
42
42
  velbusaio/messages/edge_set_custom_color.py,sha256=Lz-7prBveqPwuDWv2Mn13X9TAXGBEquw8xz2_y9NtTk,1338
43
43
  velbusaio/messages/fast_blinking_led.py,sha256=_AaG6NcjzG_cBNARogzu56l7DNpGU11XGrDHIkMuKss,909
@@ -54,7 +54,7 @@ velbusaio/messages/memory_dump_request.py,sha256=xrPsdpygD9DUF3lp-BzJacuq1dNkqz2
54
54
  velbusaio/messages/module_status.py,sha256=Y2OQUzijtA27snTEVHlyoOrcaLQbSq_3KHKAVDLGR_o,6662
55
55
  velbusaio/messages/module_status_request.py,sha256=s3h8F6Dpmjcb4hqDQKIzdOgocW1F_st40cctcW7WmQ4,961
56
56
  velbusaio/messages/module_subtype.py,sha256=KG-OC0eW-ZRnP1P8EWmcay6O-no6Mn2cklEjokaIW9M,1487
57
- velbusaio/messages/module_type.py,sha256=pzIs4VmPRpquV-Z6UJg8dpwXp0TTGTLpoBNuqSY1t1I,4221
57
+ velbusaio/messages/module_type.py,sha256=re4DSM0YZF3Jm-rv6cSYoX24gxTZSgM6COmjkjpA6P8,4372
58
58
  velbusaio/messages/module_type_request.py,sha256=fntMYCF1WVwSseCy3zRoZQH6JeGz8JDfTkwHC3AvcB4,754
59
59
  velbusaio/messages/psu_load.py,sha256=001KIz84CbnC54gHxhfAiNbcEMRpVUBzDwQ7T-yxY8s,1232
60
60
  velbusaio/messages/psu_values.py,sha256=Yd_ndU8yIei7CoL2NV6FHCefO5h_gzRsPNUYxGUGP0o,1300
@@ -121,7 +121,7 @@ velbusaio/module_spec/13.json,sha256=reXGXbaTfVVmLekrXHlfzjsV424bb0ozG7q-PxDv27U
121
121
  velbusaio/module_spec/14.json,sha256=ym2T2jCds-lC7QBZr7mqb0L9PlSmQflwpFnlEDxByjk,161
122
122
  velbusaio/module_spec/15.json,sha256=VDkI3bJRZgpfAsCiEzRJls7Hj7spmaKZ6XR8TjyymAQ,2698
123
123
  velbusaio/module_spec/16.json,sha256=9sdbNwyQQRkGsd477Oyu279tRcSydQC0bGwSQrhnVTU,3459
124
- velbusaio/module_spec/17.json,sha256=WeWeIV6euBGkPq7jBv5rbSykZwhDP6nPzrfk7rrYz-w,3490
124
+ velbusaio/module_spec/17.json,sha256=bLZ7JDt58vZUxPT6JY1xYeWWb1-jHkOhpBRUghjkQSA,3714
125
125
  velbusaio/module_spec/18.json,sha256=ylZ7_86DYCkHxk40ZqsGYEkLeUslZ_-b_ftUihfJ2bQ,3484
126
126
  velbusaio/module_spec/1A.json,sha256=dvIxgufmgIhZhsBuVEa27KmukJyvnFciorqpxwRNWFM,2581
127
127
  velbusaio/module_spec/1B.json,sha256=JbHvdmoRnsqyqhCItsTOP-UK_Yz_ha1Km9CXDe68YVc,3159
@@ -184,7 +184,7 @@ velbusaio/module_spec/5C.json,sha256=yw_XlccuFp-buRL_NXThwQLwblVRa0diLpUDm9Exrg0
184
184
  velbusaio/module_spec/5F.json,sha256=ebSwLMUW5A4LCRGOrF-vwxSVvrWZMNUWz10Xrmz7SwM,1259
185
185
  velbusaio/module_spec/60.json,sha256=Teih3jAybl5AELjY3gFbZrFN0RIMSU1yuvdsYZlMvTo,74
186
186
  velbusaio/module_spec/broadcast.json,sha256=L2Sc9FhZ7NOuu7K5g5jAhvUQGDP6a2CKrg-uWh_v-sA,2250
187
- velbus_aio-2025.4.2.dist-info/METADATA,sha256=WSJ0-GV-TmG0ZqKE5t87kTenc4-PSzEEO-j1kn9QWmw,4562
188
- velbus_aio-2025.4.2.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
189
- velbus_aio-2025.4.2.dist-info/top_level.txt,sha256=W0-lSOwD23mm8FqaIe9vY20fKicBMIdUVjF-zmfxRnY,15
190
- velbus_aio-2025.4.2.dist-info/RECORD,,
187
+ velbus_aio-2025.5.0.dist-info/METADATA,sha256=-oLAazmVHGSg3lWfQHYa6dKIZ2JKt3qtqG5EKT1B1Lo,4562
188
+ velbus_aio-2025.5.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
189
+ velbus_aio-2025.5.0.dist-info/top_level.txt,sha256=W0-lSOwD23mm8FqaIe9vY20fKicBMIdUVjF-zmfxRnY,15
190
+ velbus_aio-2025.5.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.1)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
velbusaio/handler.py CHANGED
@@ -139,7 +139,7 @@ class PacketHandler:
139
139
  if module is not None:
140
140
  try:
141
141
  self._log.debug(
142
- f"Module {module._address} detected: start loading"
142
+ f"Module {module.get_address()} detected: start loading"
143
143
  )
144
144
  await asyncio.wait_for(
145
145
  module.load(from_cache=True),
@@ -10,7 +10,7 @@ from velbusaio.message import Message
10
10
  COMMAND_CODE = 0xA5
11
11
 
12
12
 
13
- @register(COMMAND_CODE, ["VMBDALI", "VMBDALI-20"])
13
+ @register(COMMAND_CODE, ["VMBDALI", "VMBDALI-20", "VMB8DC-20", "VMB4LEDPWM-20"])
14
14
  class DimValueStatus(Message):
15
15
  """
16
16
  send by: VMBDALI
@@ -25,7 +25,18 @@ LED_FAST_BLINKING = 1 << 5
25
25
  LED_VERY_FAST_BLINKING = 1 << 4
26
26
 
27
27
 
28
- @register(COMMAND_CODE, ["VMB1DM", "VMBDME", "VMB1LED"])
28
+ @register(
29
+ COMMAND_CODE,
30
+ [
31
+ "VMB1DM",
32
+ "VMBDME",
33
+ "VMB1LED",
34
+ "VMBDALI",
35
+ "VMBDALI-20",
36
+ "VMB8DC-20",
37
+ "VMB4LEDPWM-20",
38
+ ],
39
+ )
29
40
  class DimmerStatusMessage(Message):
30
41
  """
31
42
  sent by: VMBDME
@@ -6,7 +6,7 @@ from __future__ import annotations
6
6
 
7
7
  import struct
8
8
 
9
- from velbusaio.command_registry import register
9
+ from velbusaio.command_registry import MODULE_DIRECTORY, register
10
10
  from velbusaio.message import Message
11
11
 
12
12
  COMMAND_CODE = 0xFF
@@ -110,11 +110,15 @@ class ModuleTypeMessage(Message):
110
110
  self.build_week = 0
111
111
  self.set_defaults(address)
112
112
 
113
- def module_name(self) -> str:
113
+ def module_type_name(self) -> str:
114
114
  """
115
115
  :return: str
116
116
  """
117
- return "Unknown"
117
+ return (
118
+ MODULE_DIRECTORY[self.module_type]
119
+ if self.module_type in MODULE_DIRECTORY
120
+ else "Unknown"
121
+ )
118
122
 
119
123
  def populate(self, priority, address, rtr, data) -> None:
120
124
  """
velbusaio/module.py CHANGED
@@ -243,6 +243,9 @@ class Module:
243
243
  d["channels"][num] = chan.to_cache()
244
244
  return d
245
245
 
246
+ def get_address(self) -> int:
247
+ return self._address
248
+
246
249
  def get_addresses(self) -> list:
247
250
  """
248
251
  Get all addresses for this module
@@ -550,6 +553,10 @@ class Module:
550
553
  await self._update_channel(
551
554
  message.channel, {"power": message.power, "energy": message.energy}
552
555
  )
556
+ elif isinstance(message, DimValueStatus):
557
+ for offset, dim_value in enumerate(message.dim_values):
558
+ channel = message.channel + offset
559
+ await self._update_channel(channel, {"state": dim_value})
553
560
 
554
561
  async def _update_channel(self, channel: int, updates: dict):
555
562
  try:
@@ -113,7 +113,17 @@
113
113
  "03FE": { "ModuleName": "62" },
114
114
  "03FF": { "ModuleName": "64:Save" }
115
115
  },
116
- "ModuleName": "03C0-03FF"
116
+ "ModuleName": "03C0-03FF",
117
+ "Channels": {
118
+ "01": "0000-000F",
119
+ "02": "0010-001F",
120
+ "03": "0020-002F",
121
+ "04": "0030-003F",
122
+ "05": "0040-004F",
123
+ "06": "0050-005F",
124
+ "07": "0060-006F",
125
+ "08": "0070-007F"
126
+ }
117
127
  },
118
128
  "Type": "VMB6PBN"
119
129
  }
velbusaio/vlp_reader.py CHANGED
@@ -1,33 +1,113 @@
1
+ import importlib.resources
2
+ import json
3
+ import logging
4
+ import sys
5
+
6
+ from aiofile import async_open
1
7
  from bs4 import BeautifulSoup
2
8
 
9
+ from velbusaio.command_registry import MODULE_DIRECTORY
10
+ from velbusaio.helpers import h2
11
+
3
12
 
4
13
  class vlpFile:
5
14
 
6
15
  def __init__(self, file_path) -> None:
7
16
  self._file_path = file_path
8
- self._soup = None
9
17
  self._modules = {}
10
- self._read()
11
- self._parse()
12
- print(self._modules)
18
+ self._log = logging.getLogger("velbus-vlpFile")
19
+
20
+ def get(self) -> dict:
21
+ return self._modules
13
22
 
14
- def _read(self) -> None:
23
+ async def read(self) -> None:
15
24
  with open(self._file_path) as file:
16
25
  xml_content = file.read()
17
- self._soup = BeautifulSoup(xml_content, "xml")
18
-
19
- def _parse(self) -> None:
20
- for module in self._soup.find_all("Module"):
21
- self._parse_module(module)
22
-
23
- def _parse_module(self, module) -> None:
24
- mod_info = {}
25
- mod_info["name"] = module.find("Caption").get_text()
26
- mod_info["addresses"] = module["address"]
27
- mod_info["build"] = module["build"]
28
- mod_info["serial"] = module["serial"]
29
- mod_info["build"] = module["build"]
30
- mod_info["type"] = module["type"]
31
- memory = module.find("Memory")
32
- mod_info["memory"] = memory.get_text()
33
- self._modules[mod_info["addresses"]] = mod_info
26
+ _soup = BeautifulSoup(xml_content, "xml")
27
+ for module in _soup.find_all("Module"):
28
+ self._modules[module["address"]] = vlpModule(
29
+ module.find("Caption").get_text(),
30
+ module["address"],
31
+ module["build"],
32
+ module["serial"],
33
+ module["type"],
34
+ module.find("Memory").get_text(),
35
+ )
36
+ await self._modules[module["address"]].load_module_spec()
37
+ print(self._modules[module["address"]].get_channel_name(1))
38
+ print(self._modules[module["address"]].get_channel_name(2))
39
+ print(self._modules[module["address"]].get_channel_name(3))
40
+ print(self._modules[module["address"]].get_channel_name(4))
41
+ print(self._modules[module["address"]].get_channel_name(5))
42
+ print(self._modules[module["address"]].get_channel_name(10))
43
+
44
+
45
+ class vlpModule:
46
+
47
+ def __init__(self, name, addresses, build, serial, type, memory) -> None:
48
+ self._name = name
49
+ self._addresses = addresses
50
+ self._build = build
51
+ self._serial = serial
52
+ self._type = type
53
+ self._memory = memory
54
+ self._spec = {}
55
+ self._type_id = next(
56
+ (key for key, value in MODULE_DIRECTORY.items() if value == self._type),
57
+ None,
58
+ )
59
+ self._log = logging.getLogger("velbus-vlpFile")
60
+
61
+ def get(self) -> dict:
62
+ return {
63
+ "name": self._name,
64
+ "addresses": self._addresses,
65
+ "build": self._build,
66
+ "serial": self._serial,
67
+ "type": self._type,
68
+ "memory": self._memory,
69
+ }
70
+
71
+ def get_name(self) -> str:
72
+ return self._name
73
+
74
+ def get_channel_name(self, chan: int) -> str | None:
75
+ self._log.debug(f"get_channel_name: {chan}")
76
+ if "Memory" not in self._spec:
77
+ self._log.debug(" => no Memory locations found")
78
+ return None
79
+ if "Channels" not in self._spec["Memory"]:
80
+ self._log.debug(" => no Channels Memory locations found")
81
+ return None
82
+ if h2(chan) not in self._spec["Memory"]["Channels"]:
83
+ self._log.debug(f" => no chan {chan} Memory locations found")
84
+ return None
85
+ byte_data = bytes.fromhex(
86
+ self._read_from_memory(self._spec["Memory"]["Channels"][h2(chan)]).replace(
87
+ "FF", ""
88
+ )
89
+ )
90
+ return byte_data.decode("ascii")
91
+
92
+ async def load_module_spec(self) -> None:
93
+ if sys.version_info >= (3, 13):
94
+ with importlib.resources.path(
95
+ __name__, f"module_spec/{h2(self._type_id)}.json"
96
+ ) as fspath:
97
+ async with async_open(fspath) as protocol_file:
98
+ self._spec = json.loads(await protocol_file.read())
99
+ else:
100
+ async with async_open(
101
+ str(
102
+ importlib.resources.files(__name__.split(".")[0]).joinpath(
103
+ f"module_spec/{h2(self._type)}.json"
104
+ )
105
+ )
106
+ ) as protocol_file:
107
+ self._spec = json.loads(await protocol_file.read())
108
+
109
+ def _read_from_memory(self, address_range) -> str | None:
110
+ start_str, end_str = address_range.split("-")
111
+ start = int(start_str, 16) * 2
112
+ end = (int(end_str, 16) + 1) * 2
113
+ return self._memory[start:end]