velbus-aio 2023.12.0__tar.gz → 2024.4.1__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.

Potentially problematic release.


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

Files changed (114) hide show
  1. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/MANIFEST.in +1 -1
  2. {velbus-aio-2023.12.0/velbus_aio.egg-info → velbus-aio-2024.4.1}/PKG-INFO +2 -1
  3. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/README.md +1 -0
  4. velbus-aio-2024.4.1/pyproject.toml +204 -0
  5. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1/velbus_aio.egg-info}/PKG-INFO +2 -1
  6. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbus_aio.egg-info/SOURCES.txt +2 -2
  7. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/channels.py +7 -11
  8. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/command_registry.py +15 -1
  9. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/const.py +3 -1
  10. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/controller.py +39 -68
  11. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/handler.py +5 -61
  12. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/helpers.py +2 -1
  13. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/message.py +1 -1
  14. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/__init__.py +1 -0
  15. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/blind_status.py +1 -0
  16. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/bus_active.py +1 -0
  17. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/bus_error_counter_status.py +1 -0
  18. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/bus_error_counter_status_request.py +1 -0
  19. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/bus_off.py +1 -0
  20. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/channel_name_part1.py +15 -0
  21. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/channel_name_part2.py +14 -0
  22. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/channel_name_part3.py +14 -0
  23. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/channel_name_request.py +2 -1
  24. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/clear_led.py +1 -0
  25. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/counter_status.py +1 -0
  26. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/counter_status_request.py +1 -0
  27. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/cover_down.py +1 -0
  28. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/cover_off.py +1 -2
  29. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/cover_position.py +1 -2
  30. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/cover_up.py +1 -0
  31. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/dali_device_settings.py +2 -1
  32. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/dali_device_settings_request.py +2 -1
  33. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/dali_dim_value_status.py +2 -1
  34. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/dimmer_channel_status.py +2 -1
  35. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/dimmer_status.py +1 -0
  36. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/edge_set_custom_color.py +1 -0
  37. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/fast_blinking_led.py +1 -0
  38. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/forced_off.py +1 -0
  39. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/forced_on.py +1 -0
  40. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/interface_status_request.py +1 -0
  41. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/ir_receiver_status.py +1 -0
  42. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/kwh_status.py +1 -0
  43. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/light_value_request.py +1 -0
  44. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/memo_text.py +1 -0
  45. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/memory_data.py +1 -0
  46. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/memory_data_block.py +1 -0
  47. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/memory_dump_request.py +1 -0
  48. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/module_status.py +12 -0
  49. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/module_status_request.py +1 -0
  50. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/module_subtype.py +1 -0
  51. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/module_type.py +1 -0
  52. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/module_type_request.py +1 -0
  53. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/push_button_status.py +1 -0
  54. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/raw.py +1 -0
  55. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/read_data_block_from_memory.py +1 -0
  56. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/read_data_from_memory.py +1 -0
  57. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/realtime_clock_status_request.py +1 -0
  58. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/receive_buffer_full.py +1 -0
  59. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/receive_ready.py +1 -0
  60. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/relay_status.py +1 -0
  61. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/restore_dimmer.py +6 -2
  62. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/select_program.py +1 -0
  63. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/sensor_settings_request.py +1 -0
  64. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/sensor_temp_request.py +1 -0
  65. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/sensor_temperature.py +1 -0
  66. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/set_date.py +5 -10
  67. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/set_daylight_saving.py +3 -6
  68. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/set_dimmer.py +6 -2
  69. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/set_led.py +1 -0
  70. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/set_realtime_clock.py +5 -10
  71. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/set_temperature.py +1 -0
  72. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/slider_status.py +5 -1
  73. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/slow_blinking_led.py +1 -0
  74. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/start_relay_blinking_timer.py +1 -0
  75. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/start_relay_timer.py +1 -0
  76. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/switch_relay_off.py +1 -0
  77. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/switch_relay_on.py +1 -0
  78. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/switch_to_comfort.py +1 -0
  79. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/switch_to_day.py +1 -0
  80. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/switch_to_night.py +1 -0
  81. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/switch_to_safe.py +1 -0
  82. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_sensor_settings_part1.py +1 -0
  83. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_sensor_settings_part2.py +1 -0
  84. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_sensor_settings_part3.py +1 -0
  85. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_sensor_settings_part4.py +1 -0
  86. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_sensor_settings_request.py +1 -0
  87. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_sensor_status.py +1 -0
  88. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_set_cooling.py +1 -0
  89. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/temp_set_heating.py +1 -0
  90. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/update_led_status.py +1 -0
  91. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/very_fast_blinking_led.py +1 -0
  92. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/write_data_to_memory.py +1 -0
  93. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/write_memory_block.py +1 -0
  94. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/write_module_address_and_serial_number.py +1 -0
  95. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/module.py +44 -43
  96. velbus-aio-2024.4.1/velbusaio/protocol.json +10126 -0
  97. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/protocol.py +2 -2
  98. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/raw_message.py +6 -6
  99. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/util.py +4 -0
  100. velbus-aio-2023.12.0/pyproject.toml +0 -65
  101. velbus-aio-2023.12.0/velbusaio/moduleprotocol/protocol.json +0 -26507
  102. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/LICENSE +0 -0
  103. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/requirements.txt +0 -0
  104. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/setup.cfg +0 -0
  105. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/setup.py +0 -0
  106. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbus_aio.egg-info/dependency_links.txt +0 -0
  107. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbus_aio.egg-info/not-zip-safe +0 -0
  108. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbus_aio.egg-info/requires.txt +0 -0
  109. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbus_aio.egg-info/top_level.txt +0 -0
  110. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/__init__.py +0 -0
  111. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/discovery.py +0 -0
  112. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/exceptions.py +0 -0
  113. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/messages/edge_set_color.py +0 -0
  114. {velbus-aio-2023.12.0 → velbus-aio-2024.4.1}/velbusaio/py.typed +0 -0
@@ -2,4 +2,4 @@ include LICENSE
2
2
  include README.md
3
3
  include requirements.txt
4
4
  include velbusaio/py.typed
5
- include velbusaio/moduleprotocol/protocol.json
5
+ include velbusaio/protocol.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: velbus-aio
3
- Version: 2023.12.0
3
+ Version: 2024.4.1
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
@@ -30,6 +30,7 @@ Requires-Dist: pyserial-asyncio>=0.5
30
30
  Requires-Dist: backoff>=1.10.0
31
31
 
32
32
  ![CI](https://github.com/Cereal2nd/velbus-aio/actions/workflows/main.yml/badge.svg)
33
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Cereal2nd/velbus-aio/master.svg)](https://results.pre-commit.ci/latest/github/Cereal2nd/velbus-aio/master)
33
34
 
34
35
  # velbus-aio
35
36
 
@@ -1,4 +1,5 @@
1
1
  ![CI](https://github.com/Cereal2nd/velbus-aio/actions/workflows/main.yml/badge.svg)
2
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Cereal2nd/velbus-aio/master.svg)](https://results.pre-commit.ci/latest/github/Cereal2nd/velbus-aio/master)
2
3
 
3
4
  # velbus-aio
4
5
 
@@ -0,0 +1,204 @@
1
+ [build-system]
2
+ requires = ["setuptools", "wheel"]
3
+
4
+ [project]
5
+ name = "velbus-aio"
6
+ license = {text = "MIT"}
7
+ version = "2024.4.1"
8
+ description = "Open-source home automation platform running on Python 3."
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Maikel Punie", email = "maikel.punie@gmail.com"}
12
+ ]
13
+ keywords = ["home", "velbus", "automation"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Natural Language :: English",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Home Automation",
27
+ "Topic :: Software Development :: Libraries",
28
+ "Topic :: Software Development :: Libraries :: Python Modules",
29
+ ]
30
+ requires-python = ">=3.8.0"
31
+ dependencies = [
32
+ "pyserial>=3.5.0",
33
+ "pyserial-asyncio>=0.5",
34
+ "backoff>=1.10.0",
35
+ ]
36
+
37
+ [project.urls]
38
+ "Source Code" = "https://github.com/Cereal2nd/velbus-aio"
39
+ "Bug Reports" = "https://github.com/Cereal2nd/velbus-aio/issues"
40
+
41
+ [tool.setuptools]
42
+ platforms = ["any"]
43
+ zip-safe = false
44
+ include-package-data = true
45
+
46
+ [tool.setuptools.packages.find]
47
+ exclude = ["tests", "tests.*", "examples"]
48
+
49
+ [tool.bandit]
50
+ exclude_dirs = ["tests"]
51
+ skips = ["B301", "B403", "B323", "B104", "B110"]
52
+
53
+ [tool.bumpver]
54
+ current_version = "2024.4.1"
55
+ version_pattern = "YYYY.MM.INC0"
56
+ commit_message = "bump version {old_version} -> {new_version}"
57
+ commit = true
58
+ tag = true
59
+ push = true
60
+
61
+ [tool.bumpver.file_patterns]
62
+ "pyproject.toml" = [
63
+ '^version = "{version}"',
64
+ '^current_version = "{version}"',
65
+ ]
66
+
67
+ [tool.ruff]
68
+ required-version = ">=0.3.4"
69
+
70
+ [tool.ruff.lint]
71
+ select = [
72
+ "B002", # Python does not support the unary prefix increment
73
+ "B005", # Using .strip() with multi-character strings is misleading
74
+ "B007", # Loop control variable {name} not used within loop body
75
+ "B014", # Exception handler with duplicate exception
76
+ "B015", # Pointless comparison. Did you mean to assign a value? Otherwise, prepend assert or remove it.
77
+ "B018", # Found useless attribute access. Either assign it to a variable or remove it.
78
+ "B023", # Function definition does not bind loop variable {name}
79
+ "B026", # Star-arg unpacking after a keyword argument is strongly discouraged
80
+ "B032", # Possible unintentional type annotation (using :). Did you mean to assign (using =)?
81
+ "B904", # Use raise from to specify exception cause
82
+ "C", # complexity
83
+ "COM818", # Trailing comma on bare tuple prohibited
84
+ "D", # docstrings
85
+ "DTZ003", # Use datetime.now(tz=) instead of datetime.utcnow()
86
+ "DTZ004", # Use datetime.fromtimestamp(ts, tz=) instead of datetime.utcfromtimestamp(ts)
87
+ "E", # pycodestyle
88
+ "F", # pyflakes/autoflake
89
+ "G", # flake8-logging-format
90
+ "I", # isort
91
+ "ISC", # flake8-implicit-str-concat
92
+ "ICN001", # import concentions; {name} should be imported as {asname}
93
+ "LOG", # flake8-logging
94
+ "N804", # First argument of a class method should be named cls
95
+ "N805", # First argument of a method should be named self
96
+ "N815", # Variable {name} in class scope should not be mixedCase
97
+ "PERF", # Perflint
98
+ "PGH004", # Use specific rule codes when using noqa
99
+ "PIE", # flake8-pie
100
+ "PL", # pylint
101
+ "PT", # flake8-pytest-style
102
+ "RET", # flake8-return
103
+ "RSE", # flake8-raise
104
+ "RUF005", # Consider iterable unpacking instead of concatenation
105
+ "RUF006", # Store a reference to the return value of asyncio.create_task
106
+ # "RUF100", # Unused `noqa` directive; temporarily every now and then to clean them up
107
+ "S102", # Use of exec detected
108
+ "S103", # bad-file-permissions
109
+ "S108", # hardcoded-temp-file
110
+ "S306", # suspicious-mktemp-usage
111
+ "S307", # suspicious-eval-usage
112
+ "S313", # suspicious-xmlc-element-tree-usage
113
+ "S314", # suspicious-xml-element-tree-usage
114
+ "S315", # suspicious-xml-expat-reader-usage
115
+ "S316", # suspicious-xml-expat-builder-usage
116
+ "S317", # suspicious-xml-sax-usage
117
+ "S318", # suspicious-xml-mini-dom-usage
118
+ "S319", # suspicious-xml-pull-dom-usage
119
+ "S320", # suspicious-xmle-tree-usage
120
+ "S601", # paramiko-call
121
+ "S602", # subprocess-popen-with-shell-equals-true
122
+ "S604", # call-with-shell-equals-true
123
+ "S608", # hardcoded-sql-expression
124
+ "S609", # unix-command-wildcard-injection
125
+ "SIM", # flake8-simplify
126
+ "T100", # Trace found: {name} used
127
+ "T20", # flake8-print
128
+ "TID251", # Banned imports
129
+ "TRY", # tryceratops
130
+ "UP", # pyupgrade
131
+ "W", # pycodestyle
132
+ ]
133
+ ignore = [
134
+ "D202", # No blank lines allowed after function docstring
135
+ "D203", # 1 blank line required before class docstring
136
+ "D213", # Multi-line docstring summary should start at the second line
137
+ "D406", # Section name should end with a newline
138
+ "D407", # Section name underlining
139
+ "E501", # line too long
140
+ "E731", # do not assign a lambda expression, use a def
141
+
142
+ "PLC1901", # {existing} can be simplified to {replacement} as an empty string is falsey; too many false positives
143
+ "PLR0911", # Too many return statements ({returns} > {max_returns})
144
+ "PLR0912", # Too many branches ({branches} > {max_branches})
145
+ "PLR0913", # Too many arguments to function call ({c_args} > {max_args})
146
+ "PLR0915", # Too many statements ({statements} > {max_statements})
147
+ "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
148
+ "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target
149
+ "PT004", # Fixture {fixture} does not return anything, add leading underscore
150
+ "PT011", # pytest.raises({exception}) is too broad, set the `match` parameter or use a more specific exception
151
+ "PT012", # `pytest.raises()` block should contain a single simple statement
152
+ "PT018", # Assertion should be broken down into multiple parts
153
+ "SIM102", # Use a single if statement instead of nested if statements
154
+ "SIM108", # Use ternary operator {contents} instead of if-else-block
155
+ "SIM115", # Use context handler for opening files
156
+ "TRY003", # Avoid specifying long messages outside the exception class
157
+ "TRY400", # Use `logging.exception` instead of `logging.error`
158
+ "UP006", # keep type annotation style as is
159
+ "UP007", # keep type annotation style as is
160
+ # Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923
161
+ "UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)`
162
+ # Ignored due to incompatible with mypy: https://github.com/python/mypy/issues/15238
163
+ "UP040", # Checks for use of TypeAlias annotation for declaring type aliases.
164
+
165
+ # May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
166
+ "W191",
167
+ "E111",
168
+ "E114",
169
+ "E117",
170
+ "D206",
171
+ "D300",
172
+ "Q",
173
+ "COM812",
174
+ "COM819",
175
+ "ISC001",
176
+
177
+ # Disabled because ruff does not understand type of __all__ generated by a function
178
+ "PLE0605",
179
+
180
+ # temporarily disabled
181
+ "PT019",
182
+ "RET504",
183
+ "RET503",
184
+ "RET502",
185
+ "RET501",
186
+ "TRY002",
187
+ "TRY301"
188
+ ]
189
+
190
+ [tool.ruff.lint.flake8-pytest-style]
191
+ fixture-parentheses = false
192
+ mark-parentheses = false
193
+
194
+ [tool.ruff.lint.flake8-tidy-imports.banned-api]
195
+ "async_timeout".msg = "use asyncio.timeout instead"
196
+ "pytz".msg = "use zoneinfo instead"
197
+
198
+ [tool.ruff.lint.isort]
199
+ force-sort-within-sections = true
200
+ combine-as-imports = true
201
+ split-on-trailing-comma = false
202
+
203
+ [tool.ruff.lint.mccabe]
204
+ max-complexity = 25
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: velbus-aio
3
- Version: 2023.12.0
3
+ Version: 2024.4.1
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
@@ -30,6 +30,7 @@ Requires-Dist: pyserial-asyncio>=0.5
30
30
  Requires-Dist: backoff>=1.10.0
31
31
 
32
32
  ![CI](https://github.com/Cereal2nd/velbus-aio/actions/workflows/main.yml/badge.svg)
33
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Cereal2nd/velbus-aio/master.svg)](https://results.pre-commit.ci/latest/github/Cereal2nd/velbus-aio/master)
33
34
 
34
35
  # velbus-aio
35
36
 
@@ -21,6 +21,7 @@ velbusaio/handler.py
21
21
  velbusaio/helpers.py
22
22
  velbusaio/message.py
23
23
  velbusaio/module.py
24
+ velbusaio/protocol.json
24
25
  velbusaio/protocol.py
25
26
  velbusaio/py.typed
26
27
  velbusaio/raw_message.py
@@ -106,5 +107,4 @@ velbusaio/messages/update_led_status.py
106
107
  velbusaio/messages/very_fast_blinking_led.py
107
108
  velbusaio/messages/write_data_to_memory.py
108
109
  velbusaio/messages/write_memory_block.py
109
- velbusaio/messages/write_module_address_and_serial_number.py
110
- velbusaio/moduleprotocol/protocol.json
110
+ velbusaio/messages/write_module_address_and_serial_number.py
@@ -1,6 +1,7 @@
1
1
  """
2
2
  author: Maikel Punie <maikel.punie@gmail.com>
3
3
  """
4
+
4
5
  from __future__ import annotations
5
6
 
6
7
  import asyncio
@@ -135,17 +136,8 @@ class Channel:
135
136
  if k != "_writer" and k != "_on_status_update" and k != "_name_parts"
136
137
  }
137
138
 
138
- def to_json(self) -> dict:
139
- d = self.__dict__
140
- return {
141
- k: d[k]
142
- for k in d
143
- if k != "_writer"
144
- and k != "_on_status_update"
145
- and k != "_name_parts"
146
- and k != "_module"
147
- and k != "__name__"
148
- }
139
+ def to_cache(self) -> dict:
140
+ return {"name": self._name, "type": type(self).__name__}
149
141
 
150
142
  def __setstate__(self, state):
151
143
  self.__dict__.update(state)
@@ -276,6 +268,10 @@ class Blind(Channel):
276
268
 
277
269
  async def set_position(self, position: int) -> None:
278
270
  # may not be supported by the module
271
+ if position == 100:
272
+ # at least VMB1BLS ignores command 0x1C with position 0x64
273
+ await self.close()
274
+ return
279
275
  cls = commandRegistry.get_command(0x1C, self._module.get_type())
280
276
  msg = cls(self._address)
281
277
  msg.channel = self._num
@@ -1,12 +1,15 @@
1
- """
1
+ """Command registry.
2
+
2
3
  :author: Maikel Punie <maikel.punie@gmail.com> and Thomas Delaet <thomas@delaet.org>
3
4
  """
5
+
4
6
  from __future__ import annotations
5
7
 
6
8
  MODULE_DIRECTORY = {
7
9
  0x01: "VMB8PB",
8
10
  0x02: "VMB1RY",
9
11
  0x03: "VMB1BL",
12
+ 0x04: "VMB4LEDPWM-20",
10
13
  0x05: "VMB6IN",
11
14
  0x07: "VMB1DM",
12
15
  0x08: "VMB4RY",
@@ -68,6 +71,7 @@ MODULE_DIRECTORY = {
68
71
  0x48: "VMB4RYLD-10",
69
72
  0x49: "VMB4RYNO-10",
70
73
  0x4A: "VMB2BLE-10",
74
+ 0x4B: "VMB8DC-20",
71
75
  0x4C: "VMB6PB-20",
72
76
  0x4F: "VMBEL1-20",
73
77
  0x50: "VMBEL2-20",
@@ -84,7 +88,10 @@ MODULE_DIRECTORY = {
84
88
 
85
89
 
86
90
  class CommandRegistry:
91
+ """Command registry class."""
92
+
87
93
  def __init__(self, module_directory: dict) -> None:
94
+ """Init method."""
88
95
  self._module_directory = module_directory
89
96
  self._default_commands = {}
90
97
  self._overrides = {}
@@ -92,6 +99,7 @@ class CommandRegistry:
92
99
  def register_command(
93
100
  self, command_value: int, command_class: type, module_name: str | None = None
94
101
  ) -> None:
102
+ """Register a command."""
95
103
  if command_value < 0 or command_value > 255:
96
104
  raise ValueError("Command_value should be >=0 and <=255")
97
105
  if module_name and module_name not in self._module_directory.values():
@@ -112,6 +120,7 @@ class CommandRegistry:
112
120
  def _register_override(
113
121
  self, command_value: int, command_class: type, module_type: str
114
122
  ) -> None:
123
+ """Register and override."""
115
124
  if module_type not in self._overrides:
116
125
  self._overrides[module_type] = {}
117
126
  if command_value not in self._overrides[module_type]:
@@ -122,12 +131,14 @@ class CommandRegistry:
122
131
  )
123
132
 
124
133
  def _register_default(self, command_value: int, command_class: type) -> None:
134
+ """Register a default command."""
125
135
  if command_value not in self._default_commands:
126
136
  self._default_commands[command_value] = command_class
127
137
  else:
128
138
  raise Exception("double registration in command registry")
129
139
 
130
140
  def has_command(self, command_value: int, module_type: int = 0) -> bool:
141
+ """Find a command."""
131
142
  if module_type in self._overrides:
132
143
  if command_value in self._overrides[module_type]:
133
144
  return True
@@ -136,6 +147,7 @@ class CommandRegistry:
136
147
  return False
137
148
 
138
149
  def get_command(self, command_value: int, module_type: int = 0) -> None | type:
150
+ """Search a command in the registry."""
139
151
  if module_type in self._overrides:
140
152
  if command_value in self._overrides[module_type]:
141
153
  return self._overrides[module_type][command_value]
@@ -148,6 +160,8 @@ commandRegistry = CommandRegistry(MODULE_DIRECTORY)
148
160
 
149
161
 
150
162
  def register(command_value: int, module_types: list[str] | None = None):
163
+ """Register decorator."""
164
+
151
165
  def inner_register(command_class):
152
166
  if module_types:
153
167
  for module_type in module_types:
@@ -1,6 +1,8 @@
1
- """
1
+ """Constant for velbusaio.
2
+
2
3
  Author: Maikel Punie <maikel.punie@gmail.com>
3
4
  """
5
+
4
6
  from __future__ import annotations
5
7
 
6
8
  from typing import Final
@@ -1,14 +1,13 @@
1
- """
2
- Main interface for the velbusaio lib
3
- """
1
+ """Main interface for the velbusaio lib."""
2
+
4
3
  from __future__ import annotations
5
4
 
6
5
  import asyncio
7
6
  import logging
8
7
  import pathlib
9
- import pickle
10
8
  import re
11
9
  import ssl
10
+ import time
12
11
  from urllib.parse import urlparse
13
12
 
14
13
  import serial
@@ -30,15 +29,14 @@ from velbusaio.raw_message import RawMessage
30
29
 
31
30
 
32
31
  class Velbus:
33
- """
34
- A velbus controller
35
- """
32
+ """A velbus controller."""
36
33
 
37
34
  def __init__(
38
35
  self,
39
36
  dsn: str,
40
37
  cache_dir: str = get_cache_dir(),
41
38
  ) -> None:
39
+ """Init the Velbus controller."""
42
40
  self._log = logging.getLogger("velbus")
43
41
 
44
42
  self._protocol = VelbusProtocol(
@@ -59,6 +57,7 @@ class Velbus:
59
57
  pathlib.Path(self._cache_dir).mkdir(parents=True, exist_ok=True)
60
58
 
61
59
  async def _on_message_received(self, msg: RawMessage) -> None:
60
+ """On message received function."""
62
61
  await self._handler.handle(msg)
63
62
 
64
63
  def _on_connection_lost(self, exc: Exception) -> None:
@@ -68,6 +67,7 @@ class Velbus:
68
67
  asyncio.ensure_future(self.connect())
69
68
 
70
69
  def _on_end_of_scan(self) -> None:
70
+ """Notify the scan failure."""
71
71
  self._handler.scan_finished()
72
72
 
73
73
  async def add_module(
@@ -80,31 +80,23 @@ class Velbus:
80
80
  build_year: int | None = None,
81
81
  build_week: int | None = None,
82
82
  ) -> None:
83
- """
84
- Add a found module to the module cache
85
- """
86
- mod = self._load_module_from_cache(self._cache_dir, addr)
87
- if mod is not None:
88
- self._log.info(f"Load module from CACHE: {addr}")
89
- self._modules[addr] = mod
90
- self._modules[addr].initialize(self.send)
91
- await self._modules[addr].load(True)
92
- else:
93
- self._log.info(f"Load NEW module: {typ} @ {addr}")
94
- self._modules[addr] = Module.factory(
95
- addr,
96
- typ,
97
- data,
98
- serial=serial,
99
- build_year=build_year,
100
- build_week=build_week,
101
- memorymap=memorymap,
102
- cache_dir=self._cache_dir,
103
- )
104
- self._modules[addr].initialize(self.send)
105
- await self._modules[addr].load()
83
+ """Add a found module to the module cache."""
84
+ self._log.info(f"Found module: type:{typ} address:{addr}")
85
+ self._modules[addr] = Module.factory(
86
+ addr,
87
+ typ,
88
+ data,
89
+ serial=serial,
90
+ build_year=build_year,
91
+ build_week=build_week,
92
+ memorymap=memorymap,
93
+ cache_dir=self._cache_dir,
94
+ )
95
+ self._modules[addr].initialize(self.send)
96
+ await self._modules[addr].load()
106
97
 
107
98
  async def add_submodules(self, addr: int, subList: dict[int, int]) -> None:
99
+ """Add submodules address to module."""
108
100
  for sub_num, sub_addr in subList.items():
109
101
  if sub_addr == 0xFF:
110
102
  continue
@@ -113,48 +105,30 @@ class Velbus:
113
105
  self._modules[sub_addr] = self._modules[addr]
114
106
  self._modules[addr].cleanupSubChannels()
115
107
 
116
- def _load_module_from_cache(self, cache_dir: str, address: int) -> None | Module:
117
- try:
118
- cfile = pathlib.Path(f"{cache_dir}/{address}.p")
119
- with cfile.open("rb") as fl:
120
- o = pickle.load(fl)
121
- if isinstance(o, Module):
122
- return o
123
- except OSError:
124
- pass
125
- return None
126
-
127
108
  def get_modules(self) -> dict:
128
- """
129
- Return the module cache
130
- """
109
+ """Return the module cache."""
131
110
  return self._modules
132
111
 
133
112
  def get_module(self, addr: str) -> None | Module:
134
- """
135
- Get a module on an address
136
- """
137
- if addr in self._modules.keys():
113
+ """Get a module on an address."""
114
+ if addr in self._modules:
138
115
  return self._modules[addr]
139
116
  return None
140
117
 
141
118
  def get_channels(self, addr: str) -> None | dict:
142
- """
143
- Get the channels for an address
144
- """
119
+ """Get the channels for an address."""
145
120
  if addr in self._modules:
146
121
  return (self._modules[addr]).get_channels()
147
122
  return None
148
123
 
149
124
  async def stop(self) -> None:
125
+ """Stop the controller."""
150
126
  self._closing = True
151
127
  self._auto_reconnect = False
152
128
  self._protocol.close()
153
129
 
154
130
  async def connect(self, test_connect: bool = False) -> None:
155
- """
156
- Connect to the bus and load all the data
157
- """
131
+ """Connect to the bus and load all the data."""
158
132
  auth = None
159
133
  # connect to the bus
160
134
  if ":" in self._dsn:
@@ -181,7 +155,7 @@ class Velbus:
181
155
  )
182
156
 
183
157
  except (ConnectionRefusedError, OSError) as err:
184
- raise VelbusConnectionFailed() from err
158
+ raise VelbusConnectionFailed from err
185
159
  else:
186
160
  # serial port
187
161
  try:
@@ -197,7 +171,7 @@ class Velbus:
197
171
  rtscts=1,
198
172
  )
199
173
  except (FileNotFoundError, serial.SerialException) as err:
200
- raise VelbusConnectionFailed() from err
174
+ raise VelbusConnectionFailed from err
201
175
  if test_connect:
202
176
  return
203
177
  # if auth is required send the auth key
@@ -208,6 +182,7 @@ class Velbus:
208
182
  await self.scan()
209
183
 
210
184
  async def scan(self) -> None:
185
+ """Scan the bus."""
211
186
  self._handler.scan_started()
212
187
  for addr in range(1, 256):
213
188
  msg = ModuleTypeRequestMessage(addr)
@@ -229,9 +204,7 @@ class Velbus:
229
204
  )
230
205
 
231
206
  async def _check_if_modules_are_loaded(self) -> None:
232
- """
233
- Task to wait until modules are loaded
234
- """
207
+ """Task to wait until modules are loaded."""
235
208
  while True:
236
209
  mods_loaded = 0
237
210
  for mod in (self.get_modules()).values():
@@ -246,9 +219,7 @@ class Velbus:
246
219
  await asyncio.sleep(15)
247
220
 
248
221
  async def send(self, msg: Message) -> None:
249
- """
250
- Send a packet
251
- """
222
+ """Send a packet."""
252
223
  await self._protocol.send_message(
253
224
  RawMessage(
254
225
  priority=msg.priority,
@@ -259,6 +230,7 @@ class Velbus:
259
230
  )
260
231
 
261
232
  def get_all(self, class_name: str) -> list[Channel]:
233
+ """Get all channels."""
262
234
  lst = []
263
235
  for addr, mod in (self.get_modules()).items():
264
236
  if addr in self._submodules:
@@ -269,9 +241,8 @@ class Velbus:
269
241
  return lst
270
242
 
271
243
  async def sync_clock(self) -> None:
272
- """
273
- This will send all the needed messages to sync the clock
274
- """
275
- await self.send(SetRealtimeClock())
276
- await self.send(SetDate())
277
- await self.send(SetDaylightSaving())
244
+ """Will send all the needed messages to sync the clock."""
245
+ lclt = time.localtime()
246
+ await self.send(SetRealtimeClock(wday=lclt[6], hour=lclt[3], min=lclt[4]))
247
+ await self.send(SetDate(day=lclt[2], mon=lclt[1], year=lclt[0]))
248
+ await self.send(SetDaylightSaving(ds=not lclt[8]))