boneIO 0.5.1__tar.gz → 0.6.0.dev1__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.
Files changed (79) hide show
  1. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/PKG-INFO +2 -2
  2. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/README.md +1 -1
  3. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/const.py +7 -2
  4. boneIO-0.6.0.dev1/boneio/example_config/led32x4A.yaml +226 -0
  5. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/output32x5A.yaml +3 -3
  6. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/__init__.py +4 -1
  7. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/exceptions.py +3 -0
  8. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/ha_discovery.py +13 -1
  9. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/loader.py +54 -7
  10. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/yaml_util.py +17 -4
  11. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/manager.py +32 -10
  12. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/relay/__init__.py +2 -1
  13. boneIO-0.6.0.dev1/boneio/relay/pca.py +154 -0
  14. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/runner.py +2 -0
  15. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/schema.yaml +38 -1
  16. boneIO-0.6.0.dev1/boneio/sensor/modbus/dts1964_3f.json +236 -0
  17. boneIO-0.6.0.dev1/boneio/sensor/modbus/r4dcb08.json +76 -0
  18. boneIO-0.6.0.dev1/boneio/version.py +2 -0
  19. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/pyproject.toml +2 -1
  20. boneIO-0.5.1/boneio/version.py +0 -2
  21. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/LICENSE +0 -0
  22. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/__init__.py +0 -0
  23. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/bonecli.py +0 -0
  24. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/cover.py +0 -0
  25. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/__init__.py +0 -0
  26. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/adc.yaml +0 -0
  27. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/config.yaml +0 -0
  28. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/cover.yaml +0 -0
  29. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/input.yaml +0 -0
  30. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/example_config/output24x16A.yaml +0 -0
  31. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/fonts/danube__.ttf +0 -0
  32. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/async_updater.py +0 -0
  33. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/config.py +0 -0
  34. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/events.py +0 -0
  35. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/filter.py +0 -0
  36. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/gpio.py +0 -0
  37. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/logger.py +0 -0
  38. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/mqtt.py +0 -0
  39. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/oled.py +0 -0
  40. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/onewire/W1ThermSensor.py +0 -0
  41. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/onewire/__init__.py +0 -0
  42. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/onewire/ds2482.py +0 -0
  43. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/onewire/onewire.py +0 -0
  44. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/queue.py +0 -0
  45. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/state_manager.py +0 -0
  46. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/stats.py +0 -0
  47. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/timeperiod.py +0 -0
  48. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/helper/util.py +0 -0
  49. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/input/__init__.py +0 -0
  50. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/input/gpio.py +0 -0
  51. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/modbus.py +0 -0
  52. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/mqtt_client.py +0 -0
  53. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/oled.py +0 -0
  54. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/relay/basic.py +0 -0
  55. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/relay/gpio.py +0 -0
  56. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/relay/mcp.py +0 -0
  57. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/actions.yaml +0 -0
  58. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/actions_sensor.yaml +0 -0
  59. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/actions_switch.yaml +0 -0
  60. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/filters.yaml +0 -0
  61. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/filters_adc.yaml +0 -0
  62. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/id.yaml +0 -0
  63. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/temp_unit.yaml +0 -0
  64. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/schema/update_interval.yaml +0 -0
  65. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/__init__.py +0 -0
  66. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/adc.py +0 -0
  67. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/gpio.py +0 -0
  68. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/modbus/__init__.py +0 -0
  69. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/modbus/pt100.json +0 -0
  70. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/modbus/sdm120.json +0 -0
  71. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/modbus/sdm630.json +0 -0
  72. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/modbus/sofar.json +0 -0
  73. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/temp/__init__.py +0 -0
  74. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/temp/dallas.py +0 -0
  75. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/temp/lm75.py +0 -0
  76. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/boneio/sensor/temp/mcp9808.py +0 -0
  77. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/tests/32_5_config.yaml +0 -0
  78. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/tests/bandit.yaml +0 -0
  79. {boneIO-0.5.1 → boneIO-0.6.0.dev1}/tests/relay_32_5.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneIO
3
- Version: 0.5.1
3
+ Version: 0.6.0dev1
4
4
  Summary: Python App for BoneIO
5
5
  License: GNU General Public License v3.0
6
6
  Author-email: Paweł Szafer <pszafer@gmail.com>
@@ -17,7 +17,7 @@ boneio run -dd -c config.yaml
17
17
  # Installation instructions
18
18
 
19
19
  ```
20
- sudo apt-get install libopenjp2-7-dev libatlas-base-dev python3-venv
20
+ sudo apt-get install libopenjp2-7-dev libatlas-base-dev python3-venv libjpeg-dev zlib1g-dev
21
21
  mkdir ~/boneio
22
22
  python3 -m venv ~/boneio/venv
23
23
  source ~/boneio/venv/bin/activate
@@ -4,7 +4,7 @@ boneio run -dd -c config.yaml
4
4
  # Installation instructions
5
5
 
6
6
  ```
7
- sudo apt-get install libopenjp2-7-dev libatlas-base-dev python3-venv
7
+ sudo apt-get install libopenjp2-7-dev libatlas-base-dev python3-venv libjpeg-dev zlib1g-dev
8
8
  mkdir ~/boneio
9
9
  python3 -m venv ~/boneio/venv
10
10
  source ~/boneio/venv/bin/activate
@@ -15,19 +15,22 @@ NONE = "none"
15
15
 
16
16
  # MISCELLANEOUS CONSTS
17
17
  RELAY = "relay"
18
+ LED = "led"
18
19
  ON = "ON"
19
20
  OFF = "OFF"
20
21
  STATE = "state"
22
+ BRIGHTNESS = "brightness"
23
+ SET_BRIGHTNESS = "set_brightness"
21
24
  ENABLED = "enabled"
22
25
  OUTPUT = "output"
23
26
  PIN = "pin"
24
27
  ID = "id"
25
28
  KIND = "kind"
26
29
  GPIO = "gpio"
30
+ PCA = "pca"
27
31
  GPIO_MODE = "gpio_mode"
28
32
  ACTIONS = "actions"
29
33
  ACTION = "action"
30
- OUTPUT = "output"
31
34
  SWITCH = "switch"
32
35
  LIGHT = "light"
33
36
  BUTTON = "button"
@@ -97,11 +100,13 @@ OFFLINE = "offline"
97
100
  TOPIC = "topic"
98
101
  TOPIC_PREFIX = "topic_prefix"
99
102
 
100
- # I2C and MCP CONST
103
+ # I2C, PCA and MCP CONST
101
104
  ADDRESS = "address"
102
105
  MCP23017 = "mcp23017"
106
+ PCA9685 = "pca9685"
103
107
  MCP = "mcp"
104
108
  MCP_ID = "mcp_id"
109
+ PCA_ID = "pca_id"
105
110
  INIT_SLEEP = "init_sleep"
106
111
 
107
112
  # SENSOR CONST
@@ -0,0 +1,226 @@
1
+ # pca1 - upper 12 outputs
2
+ - id: PWM_01
3
+ kind: pca
4
+ pca_id: pca1
5
+ pin: 0
6
+ output_type: led
7
+ percentage_default_brightness: 1
8
+
9
+ - id: PWM_02
10
+ kind: pca
11
+ pca_id: pca1
12
+ pin: 1
13
+ output_type: led
14
+ percentage_default_brightness: 1
15
+
16
+ - id: PWM_03
17
+ kind: pca
18
+ pca_id: pca1
19
+ pin: 2
20
+ output_type: led
21
+ percentage_default_brightness: 1
22
+
23
+ - id: PWM_04
24
+ kind: pca
25
+ pca_id: pca1
26
+ pin: 3
27
+ output_type: led
28
+ percentage_default_brightness: 1
29
+
30
+ - id: PWM_05
31
+ kind: pca
32
+ pca_id: pca1
33
+ pin: 4
34
+ output_type: led
35
+ percentage_default_brightness: 1
36
+
37
+ - id: PWM_06
38
+ kind: pca
39
+ pca_id: pca1
40
+ pin: 5
41
+ output_type: led
42
+ percentage_default_brightness: 1
43
+
44
+ - id: PWM_07
45
+ kind: pca
46
+ pca_id: pca1
47
+ pin: 6
48
+ output_type: led
49
+ percentage_default_brightness: 1
50
+
51
+ - id: PWM_08
52
+ kind: pca
53
+ pca_id: pca1
54
+ pin: 7
55
+ output_type: led
56
+ percentage_default_brightness: 1
57
+
58
+ - id: PWM_09
59
+ kind: pca
60
+ pca_id: pca1
61
+ pin: 8
62
+ output_type: led
63
+ percentage_default_brightness: 1
64
+
65
+ - id: PWM_10
66
+ kind: pca
67
+ pca_id: pca1
68
+ pin: 9
69
+ output_type: led
70
+ percentage_default_brightness: 1
71
+
72
+ - id: PWM_11
73
+ kind: pca
74
+ pca_id: pca1
75
+ pin: 10
76
+ output_type: led
77
+ percentage_default_brightness: 1
78
+
79
+ - id: PWM_12
80
+ kind: pca
81
+ pca_id: pca1
82
+ pin: 11
83
+ output_type: led
84
+ percentage_default_brightness: 1
85
+
86
+ - id: PWM_13
87
+ kind: pca
88
+ pca_id: pca1
89
+ pin: 12
90
+ output_type: led
91
+ percentage_default_brightness: 1
92
+
93
+ - id: PWM_14
94
+ kind: pca
95
+ pca_id: pca1
96
+ pin: 13
97
+ output_type: led
98
+ percentage_default_brightness: 1
99
+
100
+ - id: PWM_15
101
+ kind: pca
102
+ pca_id: pca1
103
+ pin: 14
104
+ output_type: led
105
+ percentage_default_brightness: 1
106
+
107
+ - id: PWM_16
108
+ kind: pca
109
+ pca_id: pca1
110
+ pin: 15
111
+ output_type: led
112
+ percentage_default_brightness: 1
113
+
114
+ # pca2 - lower 12 outputs
115
+
116
+ - id: PWM_17
117
+ kind: pca
118
+ pca_id: pca2
119
+ pin: 0
120
+ output_type: led
121
+ percentage_default_brightness: 1
122
+
123
+ - id: PWM_18
124
+ kind: pca
125
+ pca_id: pca2
126
+ pin: 1
127
+ output_type: led
128
+ percentage_default_brightness: 1
129
+
130
+ - id: PWM_19
131
+ kind: pca
132
+ pca_id: pca2
133
+ pin: 2
134
+ output_type: led
135
+ percentage_default_brightness: 1
136
+
137
+ - id: PWM_20
138
+ kind: pca
139
+ pca_id: pca2
140
+ pin: 3
141
+ output_type: led
142
+ percentage_default_brightness: 1
143
+
144
+ - id: PWM_21
145
+ kind: pca
146
+ pca_id: pca2
147
+ pin: 4
148
+ output_type: led
149
+ percentage_default_brightness: 1
150
+
151
+ - id: PWM_22
152
+ kind: pca
153
+ pca_id: pca2
154
+ pin: 5
155
+ output_type: led
156
+ percentage_default_brightness: 1
157
+
158
+ - id: PWM_23
159
+ kind: pca
160
+ pca_id: pca2
161
+ pin: 6
162
+ output_type: led
163
+
164
+ percentage_default_brightness: 1
165
+ - id: PWM_24
166
+ kind: pca
167
+ pca_id: pca2
168
+ pin: 7
169
+ output_type: led
170
+ percentage_default_brightness: 1
171
+
172
+ - id: PWM_25
173
+ kind: pca
174
+ pca_id: pca2
175
+ pin: 8
176
+ output_type: led
177
+ percentage_default_brightness: 1
178
+
179
+ - id: PWM_26
180
+ kind: pca
181
+ pca_id: pca2
182
+ pin: 9
183
+ output_type: led
184
+ percentage_default_brightness: 1
185
+
186
+ - id: PWM_27
187
+ kind: pca
188
+ pca_id: pca2
189
+ pin: 10
190
+ output_type: led
191
+ percentage_default_brightness: 1
192
+
193
+ - id: PWM_28
194
+ kind: pca
195
+ pca_id: pca2
196
+ pin: 11
197
+ output_type: led
198
+ percentage_default_brightness: 1
199
+
200
+ - id: PWM_29
201
+ kind: pca
202
+ pca_id: pca2
203
+ pin: 12
204
+ output_type: led
205
+ percentage_default_brightness: 1
206
+
207
+ - id: PWM_30
208
+ kind: pca
209
+ pca_id: pca2
210
+ pin: 13
211
+ output_type: led
212
+ percentage_default_brightness: 1
213
+
214
+ - id: PWM_31
215
+ kind: pca
216
+ pca_id: pca2
217
+ pin: 14
218
+ output_type: led
219
+ percentage_default_brightness: 1
220
+
221
+ - id: PWM_32
222
+ kind: pca
223
+ pca_id: pca2
224
+ pin: 15
225
+ output_type: led
226
+ percentage_default_brightness: 1
@@ -131,7 +131,7 @@
131
131
  - id: OUT_22
132
132
  kind: mcp
133
133
  mcp_id: mcp1
134
- pin: 13
134
+ pin: 10
135
135
  output_type: light
136
136
 
137
137
  - id: OUT_23
@@ -157,7 +157,7 @@
157
157
  - id: OUT_26
158
158
  kind: mcp
159
159
  mcp_id: mcp2
160
- pin: 9
160
+ pin: 14
161
161
  output_type: light
162
162
 
163
163
  - id: OUT_27
@@ -193,5 +193,5 @@
193
193
  - id: OUT_32
194
194
  kind: mcp
195
195
  mcp_id: mcp2
196
- pin: 15
196
+ pin: 8
197
197
  output_type: light
@@ -1,6 +1,6 @@
1
1
  """Helper dir for BoneIO."""
2
2
 
3
- from boneio.helper.exceptions import GPIOInputException, I2CError
3
+ from boneio.helper.exceptions import GPIOInputException, GPIOOutputException, I2CError
4
4
  from boneio.helper.gpio import (
5
5
  GpioBaseClass,
6
6
  configure_pin,
@@ -19,6 +19,7 @@ from boneio.helper.ha_discovery import (
19
19
  ha_sensor_availabilty_message,
20
20
  ha_sensor_temp_availabilty_message,
21
21
  ha_switch_availabilty_message,
22
+ ha_led_availabilty_message,
22
23
  )
23
24
  from boneio.helper.mqtt import BasicMqtt
24
25
  from boneio.helper.async_updater import AsyncUpdater
@@ -53,7 +54,9 @@ __all__ = [
53
54
  "ha_binary_sensor_availabilty_message",
54
55
  "ha_button_availabilty_message",
55
56
  "ha_input_availabilty_message",
57
+ "ha_led_availabilty_message",
56
58
  "GPIOInputException",
59
+ "GPIOOutputException",
57
60
  "I2CError",
58
61
  "GpioBaseClass",
59
62
  "StateManager",
@@ -8,6 +8,9 @@ class BoneIOException(Exception):
8
8
  class GPIOInputException(BoneIOException):
9
9
  """GPIOInput Exception."""
10
10
 
11
+ class GPIOOutputException(BoneIOException):
12
+ """GPIOInput Exception."""
13
+
11
14
 
12
15
  class I2CError(BoneIOException):
13
16
  """I2C Exception."""
@@ -45,12 +45,24 @@ def ha_availabilty_message(
45
45
  def ha_light_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
46
46
  """Create LIGHT availability topic for HA."""
47
47
  msg = ha_availabilty_message(device_type=RELAY, topic=topic, id=id, **kwargs)
48
- msg["command_topic"] = f"{topic}/cmd/relay/{id}/set"
48
+ msg["command_topic"] = f"{topic}/cmd/{RELAY}/{id}/set"
49
49
  msg["payload_off"] = OFF
50
50
  msg["payload_on"] = ON
51
51
  msg["state_value_template"] = "{{ value_json.state }}"
52
52
  return msg
53
53
 
54
+ def ha_led_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
55
+ """Create LED availability topic for HA."""
56
+ msg = ha_availabilty_message(device_type=RELAY, topic=topic, id=id, **kwargs)
57
+ msg["command_topic"] = f"{topic}/cmd/{RELAY}/{id}/set"
58
+ msg["brightness_state_topic"] = f"{topic}/{RELAY}/{id}"
59
+ msg["brightness_command_topic"] = f"{topic}/cmd/{RELAY}/{id}/set_brightness"
60
+ msg["brightness_scale"] = 65535
61
+ msg["payload_off"] = OFF
62
+ msg["payload_on"] = ON
63
+ msg["state_value_template"] = "{{ value_json.state }}"
64
+ msg["brightness_value_template"] = "{{ value_json.brightness }}"
65
+ return msg
54
66
 
55
67
  def ha_button_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
56
68
  """Create BUTTON availability topic for HA."""
@@ -6,6 +6,7 @@ from collections import namedtuple
6
6
  from typing import TYPE_CHECKING, Any, Callable, Dict, Union
7
7
 
8
8
  from adafruit_mcp230xx.mcp23017 import MCP23017
9
+ from adafruit_pca9685 import PCA9685
9
10
 
10
11
  from boneio.const import (
11
12
  ACTIONS,
@@ -15,6 +16,7 @@ from boneio.const import (
15
16
  DEVICE_CLASS,
16
17
  FILTERS,
17
18
  GPIO,
19
+ PCA,
18
20
  ID,
19
21
  INIT_SLEEP,
20
22
  INPUT,
@@ -23,6 +25,7 @@ from boneio.const import (
23
25
  LM75,
24
26
  MCP,
25
27
  MCP_ID,
28
+ PCA_ID,
26
29
  MCP_TEMP_9808,
27
30
  MODEL,
28
31
  NONE,
@@ -38,6 +41,7 @@ from boneio.const import (
38
41
  from boneio.cover import Cover
39
42
  from boneio.helper import (
40
43
  GPIOInputException,
44
+ GPIOOutputException,
41
45
  I2CError,
42
46
  StateManager,
43
47
  ha_adc_sensor_availabilty_message,
@@ -64,7 +68,7 @@ if TYPE_CHECKING:
64
68
 
65
69
  from busio import I2C
66
70
 
67
- from boneio.relay import GpioRelay, MCPRelay
71
+ from boneio.relay import GpioRelay, MCPRelay, PWMPCA
68
72
  from boneio.sensor import GpioADCSensor, initialize_adc
69
73
  from boneio.sensor.gpio import GpioInputSensor
70
74
 
@@ -167,6 +171,30 @@ def create_mcp23017(
167
171
  return grouped_outputs
168
172
 
169
173
 
174
+ def create_pca9685(
175
+ manager: Manager,
176
+ pca9685: list,
177
+ i2cbusio: I2C,
178
+ ) -> dict:
179
+ """Create MCP23017."""
180
+ grouped_outputs = {}
181
+ for pca in pca9685:
182
+ id = pca[ID] or pca[ADDRESS]
183
+ try:
184
+ manager._pca[id] = PCA9685(i2c_bus=i2cbusio, address=pca[ADDRESS])
185
+ manager._pca[id].frequency = 500
186
+ sleep_time = pca.get(INIT_SLEEP, TimePeriod(seconds=0))
187
+ _LOGGER.debug(
188
+ f"Sleeping for {sleep_time.total_seconds}s while PCA {id} is initializing."
189
+ )
190
+ time.sleep(sleep_time.total_seconds)
191
+ grouped_outputs[id] = {}
192
+ except TimeoutError as err:
193
+ _LOGGER.error("Can't connect to PCA %s. %s", id, err)
194
+ pass
195
+ return grouped_outputs
196
+
197
+
170
198
  def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
171
199
  """Create Modbus sensor for each device."""
172
200
  from boneio.sensor.modbus import ModbusSensor
@@ -197,12 +225,18 @@ def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
197
225
  OutputEntry = namedtuple("OutputEntry", "OutputClass output_kind output_id")
198
226
 
199
227
 
200
- def output_chooser(output_kind: str, mcp_id: str | None):
228
+ def output_chooser(output_kind: str, config):
201
229
  """Get named tuple based on input."""
202
230
  if output_kind == MCP:
203
- return OutputEntry(MCPRelay, MCP, mcp_id)
204
- else:
231
+ output_id = config.pop(MCP_ID, None)
232
+ return OutputEntry(MCPRelay, MCP, output_id)
233
+ elif output_kind == GPIO:
205
234
  return OutputEntry(GpioRelay, GPIO, GPIO)
235
+ elif output_kind == PCA:
236
+ output_id = config.pop(PCA_ID, None)
237
+ return OutputEntry(PWMPCA, PCA, output_id)
238
+ else:
239
+ raise GPIOOutputException(f"""Output type {output_kind} dont exists""")
206
240
 
207
241
 
208
242
  def configure_relay(
@@ -225,9 +259,7 @@ def configure_relay(
225
259
  state_manager.del_attribute(attr_type=RELAY, attribute=relay_id)
226
260
  restored_state = False
227
261
 
228
- output = output_chooser(
229
- output_kind=config.pop(KIND), mcp_id=config.pop(MCP_ID, None)
230
- )
262
+ output = output_chooser(output_kind=config.pop(KIND), config=config)
231
263
 
232
264
  if getattr(output, "output_kind") == MCP:
233
265
  mcp = manager.mcp.get(getattr(output, "output_id"))
@@ -240,6 +272,17 @@ def configure_relay(
240
272
  "mcp_id": getattr(output, "output_id"),
241
273
  "output_type": output_type,
242
274
  }
275
+ elif getattr(output, "output_kind") == PCA:
276
+ pca = manager.pca.get(getattr(output, "output_id"))
277
+ if not pca:
278
+ _LOGGER.error("No such PCA configured!")
279
+ return None
280
+ kwargs = {
281
+ "pin": int(config.pop(PIN)),
282
+ "pca": pca,
283
+ "pca_id": getattr(output, "output_id"),
284
+ "output_type": output_type,
285
+ }
243
286
  elif getattr(output, "output_kind") == GPIO:
244
287
  if GPIO not in manager.grouped_outputs:
245
288
  manager.grouped_outputs[GPIO] = {}
@@ -247,7 +290,11 @@ def configure_relay(
247
290
  "pin": config.pop(PIN),
248
291
  }
249
292
  else:
293
+ _LOGGER.error(
294
+ "Output kind: %s is not configured", getattr(output, "output_kind")
295
+ )
250
296
  return
297
+
251
298
  relay = getattr(output, "OutputClass")(
252
299
  send_message=manager.send_message,
253
300
  topic_prefix=topic_prefix,
@@ -79,6 +79,15 @@ class BoneIOLoader(SafeLoader):
79
79
  mapping.update(loaded_yaml)
80
80
  return mapping
81
81
 
82
+ def construct_include_files(self, node):
83
+ files = os.path.join(self._root, self.construct_scalar(node)).split()
84
+ merged_list = []
85
+ for fname in files:
86
+ loaded_yaml = load_yaml_file(fname.strip())
87
+ if isinstance(loaded_yaml, list):
88
+ merged_list.extend(loaded_yaml)
89
+ return merged_list
90
+
82
91
 
83
92
  BoneIOLoader.add_constructor("!include", BoneIOLoader.include)
84
93
  BoneIOLoader.add_constructor("!secret", BoneIOLoader.construct_secret)
@@ -94,6 +103,9 @@ BoneIOLoader.add_constructor(
94
103
  BoneIOLoader.add_constructor(
95
104
  "!include_dir_merge_named", BoneIOLoader.construct_include_dir_merge_named
96
105
  )
106
+ BoneIOLoader.add_constructor(
107
+ "!include_files", BoneIOLoader.construct_include_files
108
+ )
97
109
 
98
110
 
99
111
  def filter_yaml_files(files):
@@ -218,10 +230,11 @@ class CustomValidator(Validator):
218
230
  return super()._lookup_field(path)
219
231
 
220
232
  def _check_with_output_id_uniqueness(self, field, value):
221
- """Check if outputs ids are unique."""
222
- all_ids = [x[ID] for x in self.document[OUTPUT]]
223
- if len(all_ids) != len(set(all_ids)):
224
- self._error(field, "Output IDs are not unique.")
233
+ """Check if outputs ids are unique if they exists."""
234
+ if self.document[OUTPUT] is not None:
235
+ all_ids = [x[ID] for x in self.document[OUTPUT]]
236
+ if len(all_ids) != len(set(all_ids)):
237
+ self._error(field, "Output IDs are not unique.")
225
238
 
226
239
  def _normalize_coerce_to_bool(self, value):
227
240
  return True
@@ -34,6 +34,9 @@ from boneio.const import (
34
34
  InputTypes,
35
35
  relay_actions,
36
36
  DS2482,
37
+ LIGHT,
38
+ LED,
39
+ SET_BRIGHTNESS,
37
40
  )
38
41
  from boneio.helper import (
39
42
  GPIOInputException,
@@ -43,6 +46,7 @@ from boneio.helper import (
43
46
  ha_button_availabilty_message,
44
47
  ha_light_availabilty_message,
45
48
  ha_switch_availabilty_message,
49
+ ha_led_availabilty_message
46
50
  )
47
51
  from boneio.helper.config import ConfigHelper
48
52
  from boneio.helper.events import EventBus
@@ -53,6 +57,7 @@ from boneio.helper.loader import (
53
57
  configure_relay,
54
58
  create_dallas_sensor,
55
59
  create_mcp23017,
60
+ create_pca9685,
56
61
  create_temp_sensor,
57
62
  )
58
63
  from boneio.helper.logger import configure_logger
@@ -63,10 +68,13 @@ from w1thermsensor.errors import KernelModuleLoadError
63
68
 
64
69
  _LOGGER = logging.getLogger(__name__)
65
70
 
71
+ AVAILABILITY_FUNCTION_CHOOSER = {
72
+ LIGHT: ha_light_availabilty_message,
73
+ LED: ha_led_availabilty_message,
74
+ }
66
75
 
67
76
  class Manager:
68
77
  """Manager to communicate MQTT with GPIO inputs and outputs."""
69
-
70
78
  def __init__(
71
79
  self,
72
80
  send_message: Callable[[str, Union[str, dict], bool], None],
@@ -77,6 +85,7 @@ class Manager:
77
85
  input_pins: List = [],
78
86
  sensors: dict = {},
79
87
  modbus: dict = None,
88
+ pca9685: Optional[List] = None,
80
89
  mcp23017: Optional[List] = None,
81
90
  ds2482: Optional[List] = [],
82
91
  dallas: Optional[dict] = None,
@@ -100,6 +109,7 @@ class Manager:
100
109
  self._input_pins = input_pins
101
110
  self._i2cbusio = I2C(SCL, SDA)
102
111
  self._mcp = {}
112
+ self._pca = {}
103
113
  self._output = {}
104
114
  self._oled = None
105
115
  self._tasks: List[asyncio.Task] = []
@@ -119,6 +129,9 @@ class Manager:
119
129
  self.grouped_outputs = create_mcp23017(
120
130
  manager=self, mcp23017=mcp23017, i2cbusio=self._i2cbusio
121
131
  )
132
+ self.grouped_outputs.update(create_pca9685(
133
+ manager=self, pca9685=pca9685, i2cbusio=self._i2cbusio
134
+ ))
122
135
 
123
136
  self._configure_adc(adc_list=adc_list)
124
137
 
@@ -136,14 +149,13 @@ class Manager:
136
149
  continue
137
150
  self._output[_id] = out
138
151
  if out.output_type != NONE:
139
- self.send_ha_autodiscovery(
140
- id=out.id,
141
- name=out.name,
142
- ha_type=out.output_type,
143
- availability_msg_func=ha_light_availabilty_message
144
- if out.is_light
145
- else ha_switch_availabilty_message,
146
- )
152
+ if out.output_type in AVAILABILITY_FUNCTION_CHOOSER:
153
+ self.send_ha_autodiscovery(
154
+ id=out.id,
155
+ name=out.name,
156
+ ha_type=LIGHT if out.output_type == LED else out.output_type,
157
+ availability_msg_func=AVAILABILITY_FUNCTION_CHOOSER.get(out.output_type, ha_switch_availabilty_message)
158
+ )
147
159
  self._loop.call_soon_threadsafe(
148
160
  self._loop.call_later,
149
161
  0.5,
@@ -404,6 +416,11 @@ class Manager:
404
416
  """Get MCP by it's id."""
405
417
  return self._mcp
406
418
 
419
+ @property
420
+ def pca(self):
421
+ """Get PCA by it's id."""
422
+ return self._pca
423
+
407
424
  def press_callback(
408
425
  self, x: ClickTypes, inpin: str, actions: List, input_type: InputTypes = INPUT
409
426
  ) -> None:
@@ -485,7 +502,6 @@ class Manager:
485
502
  except IndexError:
486
503
  _LOGGER.error("Part of topic is missing. Not invoking command.")
487
504
  return
488
-
489
505
  if msg_type == RELAY and command == "set":
490
506
  target_device = self._output.get(device_id)
491
507
 
@@ -497,6 +513,12 @@ class Manager:
497
513
  _LOGGER.debug("Action not exist %s.", message.upper())
498
514
  else:
499
515
  _LOGGER.debug("Target device not found %s.", device_id)
516
+ elif msg_type == RELAY and command == SET_BRIGHTNESS:
517
+ target_device = self._output.get(device_id)
518
+ if target_device and target_device.output_type != NONE and message is not '':
519
+ target_device.set_brightness(int(message))
520
+ else:
521
+ _LOGGER.debug("Target device not found %s.", device_id)
500
522
  elif msg_type == COVER:
501
523
  cover = self._covers.get(device_id)
502
524
  if not cover:
@@ -1,5 +1,6 @@
1
1
  """Relay module."""
2
2
  from boneio.relay.gpio import GpioRelay
3
3
  from boneio.relay.mcp import MCPRelay
4
+ from boneio.relay.pca import PWMPCA
4
5
 
5
- __all__ = ["MCPRelay", "GpioRelay"]
6
+ __all__ = ["MCPRelay", "GpioRelay", "PWMPCA"]