boneIO 0.3.0.dev3__tar.gz → 0.3.0.dev4__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 (65) hide show
  1. {boneio-0.3.0.dev3/boneio.egg-info → boneio-0.3.0.dev4}/PKG-INFO +2 -2
  2. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/bonecli.py +1 -1
  3. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/output32x5A.yaml +110 -72
  4. boneio-0.3.0.dev4/boneio/helper/config.py +36 -0
  5. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/loader.py +5 -18
  6. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/yaml_util.py +1 -0
  7. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/manager.py +51 -40
  8. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/modbus.py +1 -1
  9. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/mqtt_client.py +22 -7
  10. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/relay/mcp.py +2 -2
  11. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/runner.py +11 -5
  12. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/modbus/__init__.py +13 -12
  13. boneio-0.3.0.dev4/boneio/version.py +2 -0
  14. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4/boneio.egg-info}/PKG-INFO +2 -2
  15. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio.egg-info/SOURCES.txt +1 -0
  16. boneio-0.3.0.dev3/boneio/version.py +0 -2
  17. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/LICENSE +0 -0
  18. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/MANIFEST.in +0 -0
  19. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/README.md +0 -0
  20. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/__init__.py +0 -0
  21. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/const.py +0 -0
  22. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/cover.py +0 -0
  23. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/__init__.py +0 -0
  24. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/adc.yaml +0 -0
  25. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/config.yaml +0 -0
  26. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/cover.yaml +0 -0
  27. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/input.yaml +0 -0
  28. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/example_config/output24x16A.yaml +0 -0
  29. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/fonts/danube__.ttf +0 -0
  30. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/__init__.py +0 -0
  31. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/events.py +0 -0
  32. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/exceptions.py +0 -0
  33. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/gpio.py +0 -0
  34. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/ha_discovery.py +0 -0
  35. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/logger.py +0 -0
  36. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/mqtt.py +0 -0
  37. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/oled.py +0 -0
  38. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/queue.py +0 -0
  39. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/state_manager.py +0 -0
  40. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/stats.py +0 -0
  41. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/helper/timeperiod.py +0 -0
  42. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/input/__init__.py +0 -0
  43. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/input/gpio.py +0 -0
  44. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/oled.py +0 -0
  45. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/relay/__init__.py +0 -0
  46. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/relay/basic.py +0 -0
  47. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/relay/gpio.py +0 -0
  48. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/schema/actions.yaml +0 -0
  49. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/schema/actions_sensor.yaml +0 -0
  50. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/schema/actions_switch.yaml +0 -0
  51. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/schema/schema.yaml +0 -0
  52. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/__init__.py +0 -0
  53. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/adc.py +0 -0
  54. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/gpio.py +0 -0
  55. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/modbus/sdm120.json +0 -0
  56. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/modbus/sdm630.json +0 -0
  57. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/modbus/sofar.json +0 -0
  58. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio/sensor/temp/__init__.py +0 -0
  59. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio.egg-info/dependency_links.txt +0 -0
  60. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio.egg-info/entry_points.txt +0 -0
  61. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio.egg-info/requires.txt +0 -0
  62. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/boneio.egg-info/top_level.txt +0 -0
  63. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/requirements.txt +0 -0
  64. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/setup.cfg +0 -0
  65. {boneio-0.3.0.dev3 → boneio-0.3.0.dev4}/setup.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneio
3
- Version: 0.3.0.dev3
3
+ Version: 0.3.0.dev4
4
4
  Summary: Python App for BoneIO
5
5
  Home-page: https://github.com/boneIO-eu/app_bbb
6
- Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.3.0.dev3.zip
6
+ Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.3.0.dev4.zip
7
7
  License: GNU General Public License v3.0
8
8
  Platform: UNKNOWN
9
9
  Classifier: Programming Language :: Python
@@ -68,7 +68,7 @@ def get_arguments() -> argparse.Namespace:
68
68
 
69
69
  def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = ""):
70
70
  """Run BoneIO."""
71
- _LOGGER.info("BoneIO starting.")
71
+ _LOGGER.info("BoneIO %s starting.", __version__)
72
72
  try:
73
73
  _config = load_config_from_file(config_file=config)
74
74
  if not _config:
@@ -1,160 +1,198 @@
1
- - id: light 1
1
+ # mcp1 - upper left 8 relays
2
+ - id: OUT_01
2
3
  kind: mcp
3
4
  mcp_id: mcp1
4
5
  pin: 0
5
6
  output_type: light
6
- - id: light 2
7
+
8
+ - id: OUT_02
7
9
  kind: mcp
8
10
  mcp_id: mcp1
9
11
  pin: 1
10
12
  output_type: light
11
- - id: light 3
13
+
14
+ - id: OUT_03
12
15
  kind: mcp
13
16
  mcp_id: mcp1
14
17
  pin: 2
15
18
  output_type: light
16
- - id: light 4
19
+
20
+ - id: OUT_04
17
21
  kind: mcp
18
22
  mcp_id: mcp1
19
23
  pin: 3
20
24
  output_type: light
21
- - id: light 5
25
+
26
+ - id: OUT_05
22
27
  kind: mcp
23
28
  mcp_id: mcp1
24
29
  pin: 4
25
30
  output_type: light
26
- - id: light 6
31
+
32
+ - id: OUT_06
27
33
  kind: mcp
28
34
  mcp_id: mcp1
29
35
  pin: 5
30
36
  output_type: light
31
- - id: light 7
37
+
38
+ - id: OUT_07
32
39
  kind: mcp
33
40
  mcp_id: mcp1
34
41
  pin: 6
35
42
  output_type: light
36
- - id: light 8
43
+
44
+ - id: OUT_08
37
45
  kind: mcp
38
46
  mcp_id: mcp1
39
47
  pin: 7
40
48
  output_type: light
41
- - id: light 9
49
+
50
+
51
+ # mcp2 - upper right 8 relays
52
+ - id: OUT_09
53
+ kind: mcp
54
+ mcp_id: mcp2
55
+ pin: 0
56
+ output_type: light
57
+
58
+ - id: OUT_10
59
+ kind: mcp
60
+ mcp_id: mcp2
61
+ pin: 1
62
+ output_type: light
63
+
64
+ - id: OUT_11
65
+ kind: mcp
66
+ mcp_id: mcp2
67
+ pin: 2
68
+ output_type: light
69
+
70
+ - id: OUT_12
71
+ kind: mcp
72
+ mcp_id: mcp2
73
+ pin: 3
74
+ output_type: light
75
+
76
+ - id: OUT_13
77
+ kind: mcp
78
+ mcp_id: mcp2
79
+ pin: 4
80
+ output_type: light
81
+
82
+ - id: OUT_14
83
+ kind: mcp
84
+ mcp_id: mcp2
85
+ pin: 5
86
+ output_type: light
87
+
88
+ - id: OUT_15
89
+ kind: mcp
90
+ mcp_id: mcp2
91
+ pin: 6
92
+ output_type: light
93
+
94
+ - id: OUT_16
95
+ kind: mcp
96
+ mcp_id: mcp2
97
+ pin: 7
98
+ output_type: light
99
+
100
+
101
+ # mcp1 - lower left 8 relays
102
+ - id: OUT_17
42
103
  kind: mcp
43
104
  mcp_id: mcp1
44
105
  pin: 8
45
106
  output_type: light
46
- - id: light 10
107
+
108
+ - id: OUT_18
47
109
  kind: mcp
48
110
  mcp_id: mcp1
49
111
  pin: 9
50
112
  output_type: light
51
- - id: light 11
113
+
114
+ - id: OUT_19
52
115
  kind: mcp
53
116
  mcp_id: mcp1
54
117
  pin: 10
55
118
  output_type: light
56
- - id: light 12
119
+
120
+ - id: OUT_20
57
121
  kind: mcp
58
122
  mcp_id: mcp1
59
123
  pin: 11
60
124
  output_type: light
61
- - id: light 13
125
+
126
+ - id: OUT_21
62
127
  kind: mcp
63
128
  mcp_id: mcp1
64
129
  pin: 12
65
130
  output_type: light
66
- - id: light 14
131
+
132
+ - id: OUT_22
67
133
  kind: mcp
68
134
  mcp_id: mcp1
69
135
  pin: 13
70
136
  output_type: light
71
- - id: light 15
137
+
138
+ - id: OUT_23
72
139
  kind: mcp
73
140
  mcp_id: mcp1
74
141
  pin: 14
75
142
  output_type: light
76
- - id: light 16
143
+
144
+ - id: OUT_24
77
145
  kind: mcp
78
146
  mcp_id: mcp1
79
147
  pin: 15
80
148
  output_type: light
81
- - id: switch 1
82
- kind: mcp
83
- mcp_id: mcp2
84
- pin: 0
85
- output_type: switch
86
- - id: switch 2
87
- kind: mcp
88
- mcp_id: mcp2
89
- pin: 1
90
- output_type: switch
91
- - id: switch 3
92
- kind: mcp
93
- mcp_id: mcp2
94
- pin: 2
95
- output_type: switch
96
- - id: switch 4
97
- kind: mcp
98
- mcp_id: mcp2
99
- pin: 3
100
- output_type: switch
101
- - id: switch 5
102
- kind: mcp
103
- mcp_id: mcp2
104
- pin: 4
105
- output_type: switch
106
- - id: switch 6
107
- kind: mcp
108
- mcp_id: mcp2
109
- pin: 5
110
- output_type: switch
111
- - id: switch 7
112
- kind: mcp
113
- mcp_id: mcp2
114
- pin: 6
115
- output_type: switch
116
- - id: switch 8
117
- kind: mcp
118
- mcp_id: mcp2
119
- pin: 7
120
- output_type: switch
121
- - id: switch 9
149
+
150
+
151
+ # mcp2 - lower right 8 relays
152
+ - id: OUT_25
122
153
  kind: mcp
123
154
  mcp_id: mcp2
124
155
  pin: 8
125
- output_type: switch
126
- - id: switch 10
156
+ output_type: light
157
+
158
+ - id: OUT_26
127
159
  kind: mcp
128
160
  mcp_id: mcp2
129
161
  pin: 9
130
- output_type: switch
131
- - id: switch 11
162
+ output_type: light
163
+
164
+ - id: OUT_27
132
165
  kind: mcp
133
166
  mcp_id: mcp2
134
167
  pin: 10
135
- output_type: switch
136
- - id: switch 12
168
+ output_type: light
169
+
170
+ - id: OUT_28
137
171
  kind: mcp
138
172
  mcp_id: mcp2
139
173
  pin: 11
140
- output_type: switch
141
- - id: switch 13
174
+ output_type: light
175
+
176
+ - id: OUT_29
142
177
  kind: mcp
143
178
  mcp_id: mcp2
144
179
  pin: 12
145
- output_type: switch
146
- - id: switch 14
180
+ output_type: light
181
+
182
+ - id: OUT_30
147
183
  kind: mcp
148
184
  mcp_id: mcp2
149
185
  pin: 13
150
- output_type: switch
151
- - id: switch 15
186
+ output_type: light
187
+
188
+ - id: OUT_31
152
189
  kind: mcp
153
190
  mcp_id: mcp2
154
191
  pin: 14
155
- output_type: switch
156
- - id: switch 16
192
+ output_type: light
193
+
194
+ - id: OUT_32
157
195
  kind: mcp
158
196
  mcp_id: mcp2
159
197
  pin: 15
160
- output_type: switch
198
+ output_type: light
@@ -0,0 +1,36 @@
1
+ """
2
+ Module to provide basic config options.
3
+ """
4
+ from boneio.const import BONEIO, HOMEASSISTANT
5
+
6
+
7
+ class ConfigHelper:
8
+ def __init__(
9
+ self,
10
+ topic_prefix: str = BONEIO,
11
+ ha_discovery: bool = True,
12
+ ha_discovery_prefix: str = HOMEASSISTANT,
13
+ ):
14
+ self._topic_prefix = topic_prefix
15
+ self._ha_discovery = ha_discovery
16
+ self._ha_discovery_prefix = ha_discovery_prefix
17
+
18
+ @property
19
+ def topic_prefix(self) -> str:
20
+ return self._topic_prefix
21
+
22
+ @property
23
+ def ha_discovery(self) -> bool:
24
+ return self._ha_discovery
25
+
26
+ @property
27
+ def ha_discovery_prefix(self) -> str:
28
+ return self._ha_discovery_prefix
29
+
30
+ @property
31
+ def cmd_topic_prefix(self) -> str:
32
+ return f"{self.topic_prefix}/cmd/"
33
+
34
+ @property
35
+ def subscribe_topic(self) -> str:
36
+ return f"{self.cmd_topic_prefix}+/+/#"
@@ -46,6 +46,7 @@ from boneio.helper import (
46
46
  from boneio.helper.ha_discovery import ha_cover_availabilty_message
47
47
  from boneio.helper.timeperiod import TimePeriod
48
48
  from boneio.input.gpio import GpioInputButton
49
+ from boneio.helper.config import ConfigHelper
49
50
 
50
51
  # Typing imports that create a circular dependency
51
52
  if TYPE_CHECKING:
@@ -59,9 +60,7 @@ from busio import I2C
59
60
  _LOGGER = logging.getLogger(__name__)
60
61
 
61
62
 
62
- def create_adc(
63
- manager: Manager, topic_prefix: str, ha_discovery_prefix: str, adc_list: list = []
64
- ):
63
+ def create_adc(manager: Manager, topic_prefix: str, adc_list: list = []):
65
64
  """Create ADC sensor."""
66
65
 
67
66
  initialize_adc()
@@ -85,7 +84,6 @@ def create_adc(
85
84
  id=id,
86
85
  name=name,
87
86
  ha_type=SENSOR,
88
- ha_discovery_prefix=ha_discovery_prefix,
89
87
  availability_msg_func=ha_adc_sensor_availabilty_message,
90
88
  )
91
89
  manager.append_task(asyncio.create_task(adc.send_state()))
@@ -97,11 +95,9 @@ def create_adc(
97
95
  def create_temp_sensor(
98
96
  manager: Manager,
99
97
  topic_prefix: str,
100
- ha_discovery_prefix: str,
101
98
  sensor_type: str,
102
99
  i2cbusio: I2C,
103
100
  temp_def: dict = {},
104
- temp_sensors: list = [],
105
101
  ):
106
102
  """Create LM sensor in manager."""
107
103
  if sensor_type == LM75:
@@ -125,11 +121,10 @@ def create_temp_sensor(
125
121
  id=id,
126
122
  name=name,
127
123
  ha_type=SENSOR,
128
- ha_discovery_prefix=ha_discovery_prefix,
129
124
  availability_msg_func=ha_sensor_temp_availabilty_message,
130
125
  )
131
126
  manager.append_task(asyncio.create_task(temp_sensor.send_state()))
132
- temp_sensors.append(temp_sensor)
127
+ return temp_sensor
133
128
  except I2CError as err:
134
129
  _LOGGER.error("Can't configure Temp sensor. %s", err)
135
130
  pass
@@ -160,9 +155,7 @@ def create_mcp23017(
160
155
 
161
156
  def create_modbus_sensors(
162
157
  manager: Manager,
163
- topic_prefix: str,
164
- ha_discovery: bool,
165
- ha_discovery_prefix: str,
158
+ config_helper: ConfigHelper,
166
159
  modbus: Modbus,
167
160
  sensors,
168
161
  ) -> None:
@@ -180,9 +173,7 @@ def create_modbus_sensors(
180
173
  name=name,
181
174
  model=sensor[MODEL],
182
175
  send_message=manager.send_message,
183
- topic_prefix=topic_prefix,
184
- ha_discovery=ha_discovery,
185
- ha_discovery_prefix=ha_discovery_prefix,
176
+ config_helper=config_helper,
186
177
  update_interval=sensor.get(UPDATE_INTERVAL, TimePeriod(seconds=60)),
187
178
  )
188
179
  manager.append_task(asyncio.create_task(sdm.send_state()))
@@ -289,7 +280,6 @@ def configure_input(
289
280
  pin: str,
290
281
  press_callback: Callable,
291
282
  send_ha_autodiscovery: Callable,
292
- ha_discovery_prefix: str,
293
283
  ) -> str:
294
284
  """Configure input sensor or button."""
295
285
  try:
@@ -309,7 +299,6 @@ def configure_input(
309
299
  id=pin,
310
300
  name=gpio.get(ID, pin),
311
301
  ha_type=getattr(input, "ha_type"),
312
- ha_discovery_prefix=ha_discovery_prefix,
313
302
  availability_msg_func=getattr(input, "availability_msg_f"),
314
303
  )
315
304
  return pin
@@ -322,7 +311,6 @@ def configure_cover(
322
311
  manager: Manager,
323
312
  cover_id: str,
324
313
  state_manager: StateManager,
325
- ha_discovery_prefix: str,
326
314
  send_ha_autodiscovery: Callable,
327
315
  config: dict,
328
316
  **kwargs,
@@ -352,7 +340,6 @@ def configure_cover(
352
340
  name=cover.name,
353
341
  ha_type=COVER,
354
342
  device_class=config.get(DEVICE_CLASS),
355
- ha_discovery_prefix=ha_discovery_prefix,
356
343
  availability_msg_func=ha_cover_availabilty_message,
357
344
  )
358
345
  return cover
@@ -263,6 +263,7 @@ class CustomValidator(Validator):
263
263
  "milliseconds": "milliseconds",
264
264
  "s": "seconds",
265
265
  "sec": "seconds",
266
+ "secs": "seconds",
266
267
  "seconds": "seconds",
267
268
  "min": "minutes",
268
269
  "minutes": "minutes",
@@ -7,11 +7,9 @@ from busio import I2C
7
7
 
8
8
  from boneio.const import (
9
9
  ACTION,
10
- BONEIO,
11
10
  BUTTON,
12
11
  CLOSE,
13
12
  COVER,
14
- HOMEASSISTANT,
15
13
  ID,
16
14
  INPUT,
17
15
  LM75,
@@ -44,6 +42,8 @@ from boneio.helper import (
44
42
  ha_button_availabilty_message,
45
43
  host_stats,
46
44
  )
45
+
46
+ from boneio.helper.config import ConfigHelper
47
47
  from boneio.helper.events import EventBus
48
48
  from boneio.helper.loader import (
49
49
  configure_cover,
@@ -68,14 +68,12 @@ class Manager:
68
68
  self,
69
69
  send_message: Callable[[str, Union[str, dict], bool], None],
70
70
  state_manager: StateManager,
71
+ config_helper: ConfigHelper,
71
72
  config_file_path: str,
72
73
  relay_pins: List = [],
73
74
  input_pins: List = [],
74
75
  sensors: dict = {},
75
- topic_prefix: str = BONEIO,
76
76
  modbus: dict = None,
77
- ha_discovery: bool = True,
78
- ha_discovery_prefix: str = HOMEASSISTANT,
79
77
  mcp23017: Optional[List] = None,
80
78
  oled: dict = {},
81
79
  adc_list: Optional[List] = None,
@@ -83,17 +81,16 @@ class Manager:
83
81
  ) -> None:
84
82
  """Initialize the manager."""
85
83
  _LOGGER.info("Initializing manager module.")
84
+
86
85
  self._loop = asyncio.get_event_loop()
86
+ self._config_helper = config_helper
87
87
  self._host_data = None
88
- self._ha_discovery = ha_discovery
89
88
  self._config_file_path = config_file_path
90
89
  self._state_manager = state_manager
91
90
  self._event_bus = EventBus(self._loop)
91
+ self._autodiscovery_messages = []
92
92
 
93
93
  self.send_message = send_message
94
- self._topic_prefix = topic_prefix
95
- self._command_topic_prefix = f"{topic_prefix}/cmd/"
96
- self.subscribe_topic = f"{self._command_topic_prefix}+/+/#"
97
94
  self._input_pins = input_pins
98
95
  self._i2cbusio = I2C(SCL, SDA)
99
96
  self._mcp = {}
@@ -108,26 +105,25 @@ class Manager:
108
105
 
109
106
  for sensor_type in (LM75, MCP_TEMP_9808):
110
107
  if sensors.get(sensor_type):
111
- create_temp_sensor(
112
- manager=self,
113
- topic_prefix=topic_prefix,
114
- ha_discovery_prefix=ha_discovery_prefix,
115
- sensor_type=sensor_type,
116
- temp_def=sensors.get(sensor_type),
117
- i2cbusio=self._i2cbusio,
118
- temp_sensors=self._temp_sensors,
119
- )
108
+ for temp_def in sensors.get(sensor_type):
109
+ temp_sensor = create_temp_sensor(
110
+ manager=self,
111
+ topic_prefix=self._config_helper.topic_prefix,
112
+ sensor_type=sensor_type,
113
+ temp_def=temp_def,
114
+ i2cbusio=self._i2cbusio,
115
+ )
116
+ if temp_sensor:
117
+ self._temp_sensors.append(temp_sensor)
120
118
 
121
119
  if sensors.get(MODBUS) and self._modbus:
122
120
  from boneio.helper.loader import create_modbus_sensors
123
121
 
124
122
  create_modbus_sensors(
125
123
  manager=self,
126
- topic_prefix=topic_prefix,
127
- ha_discovery=ha_discovery,
128
- ha_discovery_prefix=ha_discovery_prefix,
129
124
  sensors=sensors.get(MODBUS),
130
125
  modbus=self._modbus,
126
+ config_helper=self._config_helper,
131
127
  )
132
128
 
133
129
  self.grouped_outputs = create_mcp23017(
@@ -139,9 +135,8 @@ class Manager:
139
135
 
140
136
  create_adc(
141
137
  manager=self,
142
- topic_prefix=topic_prefix,
138
+ topic_prefix=self._config_helper.topic_prefix,
143
139
  adc_list=adc_list,
144
- ha_discovery_prefix=ha_discovery_prefix,
145
140
  )
146
141
 
147
142
  for _config in relay_pins:
@@ -149,7 +144,7 @@ class Manager:
149
144
  out = configure_relay(
150
145
  manager=self,
151
146
  state_manager=self._state_manager,
152
- topic_prefix=topic_prefix,
147
+ topic_prefix=self._config_helper.topic_prefix,
153
148
  relay_id=_id,
154
149
  relay_callback=self._relay_callback,
155
150
  config=_config,
@@ -162,7 +157,6 @@ class Manager:
162
157
  id=out.id,
163
158
  name=out.name,
164
159
  ha_type=out.output_type,
165
- ha_discovery_prefix=ha_discovery_prefix,
166
160
  availability_msg_func=ha_light_availabilty_message
167
161
  if out.is_light
168
162
  else ha_switch_availabilty_message,
@@ -194,9 +188,8 @@ class Manager:
194
188
  open_time=_config.get("open_time"),
195
189
  close_time=_config.get("close_time"),
196
190
  event_bus=self._event_bus,
197
- ha_discovery_prefix=ha_discovery_prefix,
198
191
  send_ha_autodiscovery=self.send_ha_autodiscovery,
199
- topic_prefix=topic_prefix,
192
+ topic_prefix=self._config_helper.topic_prefix,
200
193
  )
201
194
 
202
195
  _LOGGER.info("Initializing inputs. This will take a while.")
@@ -211,7 +204,6 @@ class Manager:
211
204
  gpio=gpio,
212
205
  pin=pin,
213
206
  press_callback=self.press_callback,
214
- ha_discovery_prefix=ha_discovery_prefix,
215
207
  send_ha_autodiscovery=self.send_ha_autodiscovery,
216
208
  )
217
209
  )
@@ -235,14 +227,15 @@ class Manager:
235
227
  )
236
228
  except (GPIOInputException, I2CError) as err:
237
229
  _LOGGER.error("Can't configure OLED display. %s", err)
238
- self.prepare_button(ha_discovery_prefix=ha_discovery_prefix)
230
+ self.prepare_button()
239
231
 
240
232
  _LOGGER.info("BoneIO manager is ready.")
241
233
 
242
234
  async def reconnect_callback(self) -> None:
243
235
  """Function to invoke when connection to MQTT is (re-)established."""
244
236
  _LOGGER.info("Sending online state.")
245
- self.send_message(topic=f"{self._topic_prefix}/{STATE}", payload=ONLINE)
237
+ topic = f"{self._config_helper.topic_prefix}/{STATE}"
238
+ self.send_message(topic=topic, payload=ONLINE, retain=True)
246
239
 
247
240
  def _relay_callback(
248
241
  self, relay_type: str, relay_id: str, restore_state: bool
@@ -275,13 +268,12 @@ class Manager:
275
268
  """Add task to run with asyncio loop."""
276
269
  self._tasks.append(task)
277
270
 
278
- def prepare_button(self, ha_discovery_prefix: str) -> None:
271
+ def prepare_button(self) -> None:
279
272
  """Prepare buttons for reload."""
280
273
  self.send_ha_autodiscovery(
281
274
  id="Logger",
282
275
  name="Logger",
283
276
  ha_type=BUTTON,
284
- ha_discovery_prefix=ha_discovery_prefix,
285
277
  availability_msg_func=ha_button_availabilty_message,
286
278
  )
287
279
 
@@ -295,7 +287,7 @@ class Manager:
295
287
  ) -> None:
296
288
  """Press callback to use in input gpio.
297
289
  If relay input map is provided also toggle action on relay or cover or mqtt."""
298
- topic = f"{self._topic_prefix}/{input_type}/{inpin}"
290
+ topic = f"{self._config_helper.topic_prefix}/{input_type}/{inpin}"
299
291
  self.send_message(topic=topic, payload=x)
300
292
  for action_definition in actions:
301
293
  _LOGGER.debug("Executing action %s", action_definition)
@@ -328,41 +320,60 @@ class Manager:
328
320
  self,
329
321
  id: str,
330
322
  name: str,
331
- ha_discovery_prefix: str,
332
323
  ha_type: str,
333
324
  availability_msg_func: Callable,
334
325
  topic_prefix: str = None,
335
326
  **kwargs,
336
327
  ) -> None:
337
328
  """Send HA autodiscovery information for each relay."""
338
- if not self._ha_discovery:
329
+ if not self._config_helper.ha_discovery:
339
330
  return
340
- if not topic_prefix:
341
- topic_prefix = self._topic_prefix
331
+ topic_prefix = topic_prefix or self._config_helper.topic_prefix
342
332
  msg = availability_msg_func(topic=topic_prefix, id=id, name=name, **kwargs)
343
- topic = f"{ha_discovery_prefix}/{ha_type}/{topic_prefix}/{id}/config"
333
+ topic = f"{self._config_helper.ha_discovery_prefix}/{ha_type}/{topic_prefix}/{id}/config"
344
334
  _LOGGER.debug("Sending HA discovery for %s, %s.", ha_type, name)
335
+ self._autodiscovery_messages.append({"topic": topic, "payload": msg})
345
336
  self.send_message(topic=topic, payload=msg, retain=True)
346
337
 
338
+ def resend_autodiscovery(self):
339
+ for msg in self._autodiscovery_messages:
340
+ self.send_message(**msg, retain=True)
341
+
347
342
  async def receive_message(self, topic: str, message: str) -> None:
348
343
  """Callback for receiving action from Mqtt."""
349
- assert topic.startswith(self._command_topic_prefix)
350
- topic_parts_raw = topic[len(self._command_topic_prefix) :].split("/")
344
+ _LOGGER.debug("Processing topic %s with message %s.", topic, message)
345
+ if topic.startswith(f"{self._config_helper.ha_discovery_prefix}/status"):
346
+ if message == ONLINE:
347
+ self.resend_autodiscovery()
348
+ return
349
+ assert topic.startswith(self._config_helper.cmd_topic_prefix)
350
+ topic_parts_raw = topic[len(self._config_helper.cmd_topic_prefix) :].split("/")
351
351
  topic_parts = deque(topic_parts_raw)
352
352
  try:
353
353
  msg_type = topic_parts.popleft()
354
354
  device_id = topic_parts.popleft()
355
355
  command = topic_parts.pop()
356
+ _LOGGER.debug(
357
+ "Divide topic to: msg_type: %s, device_id: %s, command: %s",
358
+ msg_type,
359
+ device_id,
360
+ command,
361
+ )
356
362
  except IndexError:
357
363
  _LOGGER.error("Part of topic is missing. Not invoking command.")
358
364
  return
359
365
 
360
366
  if msg_type == RELAY and command == "set":
361
367
  target_device = self._output.get(device_id)
368
+
362
369
  if target_device and target_device.output_type != NONE:
363
370
  action_from_msg = relay_actions.get(message.upper())
364
371
  if action_from_msg:
365
372
  getattr(target_device, action_from_msg)()
373
+ else:
374
+ _LOGGER.debug("Action not exist %s.", message.upper())
375
+ else:
376
+ _LOGGER.debug("Target device not found %s.", device_id)
366
377
  elif msg_type == COVER:
367
378
  cover = self._covers.get(device_id)
368
379
  if not cover:
@@ -69,7 +69,7 @@ class Modbus:
69
69
 
70
70
  async def read_single_register(
71
71
  self, unit: int, address: int, count: int = 2, method: str = "input"
72
- ) -> float:
72
+ ) -> float | None:
73
73
  """Call sync. pymodbus."""
74
74
  async with self._lock:
75
75
  if not self._pymodbus_connect():
@@ -7,16 +7,17 @@ import json
7
7
  import logging
8
8
  import uuid
9
9
  from contextlib import AsyncExitStack
10
- from typing import Any, Callable, Optional, Set, Union
10
+ from typing import Any, Callable, Optional, Set, Tuple, Union
11
11
 
12
12
  import paho.mqtt.client as mqtt
13
- from asyncio_mqtt import Client as AsyncioClient
13
+ from asyncio_mqtt import Client as AsyncioClient, Will
14
14
  from asyncio_mqtt import MqttError
15
15
  from paho.mqtt.properties import Properties
16
16
  from paho.mqtt.subscribeoptions import SubscribeOptions
17
17
 
18
- from boneio.const import PAHO
18
+ from boneio.const import PAHO, STATE, ONLINE
19
19
  from boneio.helper import UniqueQueue
20
+ from boneio.helper.config import ConfigHelper
20
21
 
21
22
  _LOGGER = logging.getLogger(__name__)
22
23
 
@@ -27,12 +28,14 @@ class MQTTClient:
27
28
  def __init__(
28
29
  self,
29
30
  host: str,
31
+ config_helper: ConfigHelper,
30
32
  port: int = 1883,
31
33
  **client_options: Any,
32
34
  ) -> None:
33
35
  """Set up client."""
34
36
  self.host = host
35
37
  self.port = port
38
+ self._config_helper = config_helper
36
39
  client_options["client_id"] = mqtt.base62(uuid.uuid4().int, padding=22)
37
40
  client_options["logger"] = logging.getLogger(PAHO)
38
41
  client_options["clean_session"] = True
@@ -49,6 +52,12 @@ class MQTTClient:
49
52
  self.asyncio_client = AsyncioClient(
50
53
  self.host,
51
54
  self.port,
55
+ will=Will(
56
+ topic=f"{self._config_helper.topic_prefix}/{STATE}",
57
+ payload=ONLINE,
58
+ qos=0,
59
+ retain=False,
60
+ ),
52
61
  **self.client_options,
53
62
  )
54
63
 
@@ -76,7 +85,7 @@ class MQTTClient:
76
85
 
77
86
  async def subscribe( # pylint:disable=too-many-arguments
78
87
  self,
79
- topic: str,
88
+ topics: Tuple[str, str],
80
89
  qos: int = 0,
81
90
  options: Optional[SubscribeOptions] = None,
82
91
  properties: Optional[Properties] = None,
@@ -86,13 +95,17 @@ class MQTTClient:
86
95
 
87
96
  Can raise asyncio_mqtt.MqttError.
88
97
  """
89
- params: dict = {"qos": qos, "timeout": timeout}
98
+ args = []
99
+ for topic in topics:
100
+ args.append((topic, qos))
101
+ params: dict = {"qos": qos}
90
102
  if options:
91
103
  params["options"] = options
92
104
  if properties:
93
105
  params["properties"] = properties
94
106
 
95
- await self.asyncio_client.subscribe(topic, **params)
107
+ # e.g. subscribe([("my/topic", SubscribeOptions(qos=0), ("another/topic", SubscribeOptions(qos=2)])
108
+ await self.asyncio_client.subscribe(topic=args, **params, timeout=timeout)
96
109
 
97
110
  async def unsubscribe(
98
111
  self, topic: str, properties: Optional[Properties] = None, timeout: float = 10.0
@@ -169,7 +182,9 @@ class MQTTClient:
169
182
  tasks.add(reconnect_task)
170
183
  tasks.add(messages_task)
171
184
 
172
- await self.subscribe(manager.subscribe_topic)
185
+ await self.subscribe(
186
+ topics=(self._config_helper.subscribe_topic, "homeassistant/status")
187
+ )
173
188
 
174
189
  # Wait for everything to complete (or fail due to, e.g., network errors).
175
190
  await asyncio.gather(*tasks)
@@ -1,7 +1,7 @@
1
1
  """MCP23017 Relay module."""
2
2
 
3
3
  import logging
4
- from adafruit_mcp230xx.mcp23017 import MCP23017
4
+ from adafruit_mcp230xx.mcp23017 import MCP23017, DigitalInOut
5
5
  from boneio.helper import callback
6
6
  from boneio.relay.basic import BasicRelay
7
7
  from boneio.const import SWITCH, NONE
@@ -23,7 +23,7 @@ class MCPRelay(BasicRelay):
23
23
  **kwargs
24
24
  ) -> None:
25
25
  """Initialize MCP relay."""
26
- self._pin = mcp.get_pin(pin)
26
+ self._pin: DigitalInOut = mcp.get_pin(pin)
27
27
  self._pin.switch_to_output(value=True)
28
28
  if output_type == NONE:
29
29
  """Just in case to not restore state of covers etc."""
@@ -26,6 +26,7 @@ _LOGGER = logging.getLogger(__name__)
26
26
  from boneio.helper import StateManager
27
27
  from boneio.manager import Manager
28
28
  from boneio.mqtt_client import MQTTClient
29
+ from boneio.helper.config import ConfigHelper
29
30
 
30
31
 
31
32
  async def async_run(
@@ -36,27 +37,32 @@ async def async_run(
36
37
  ):
37
38
  """Run BoneIO."""
38
39
 
40
+ _config_helper = ConfigHelper(
41
+ topic_prefix=config[MQTT].pop(TOPIC_PREFIX),
42
+ ha_discovery=config[MQTT][HA_DISCOVERY].pop(ENABLED),
43
+ ha_discovery_prefix=config[MQTT][HA_DISCOVERY].pop(TOPIC_PREFIX),
44
+ )
45
+
39
46
  client = MQTTClient(
40
47
  host=config[MQTT][HOST],
41
48
  username=config[MQTT].get(USERNAME, mqttusername),
42
49
  password=config[MQTT].get(PASSWORD, mqttpassword),
43
50
  port=config[MQTT].get(PORT, 1883),
51
+ config_helper=_config_helper,
44
52
  )
45
53
 
46
54
  manager = Manager(
47
55
  send_message=client.send_message,
48
- topic_prefix=config[MQTT][TOPIC_PREFIX],
49
56
  relay_pins=config.get(OUTPUT, []),
50
57
  input_pins=config.get(INPUT, []),
51
58
  config_file_path=config_file,
52
59
  state_manager=StateManager(
53
60
  state_file=f"{os.path.split(config_file)[0]}state.json"
54
61
  ),
55
- ha_discovery=config[MQTT][HA_DISCOVERY][ENABLED],
56
- ha_discovery_prefix=config[MQTT][HA_DISCOVERY][TOPIC_PREFIX],
62
+ config_helper=_config_helper,
57
63
  sensors={
58
- LM75: config.get(LM75),
59
- MCP_TEMP_9808: config.get(MCP_TEMP_9808),
64
+ LM75: config.get(LM75, []),
65
+ MCP_TEMP_9808: config.get(MCP_TEMP_9808, []),
60
66
  MODBUS: config.get("modbus_sensors"),
61
67
  },
62
68
  mcp23017=config.get(MCP23017, []),
@@ -1,3 +1,4 @@
1
+ from distutils.command.config import config
1
2
  import logging
2
3
  import asyncio
3
4
  from datetime import datetime
@@ -20,6 +21,7 @@ from boneio.const import (
20
21
  from boneio.helper import BasicMqtt
21
22
  from boneio.helper.ha_discovery import modbus_sensor_availabilty_message
22
23
  from boneio.helper.timeperiod import TimePeriod
24
+ from boneio.helper.config import ConfigHelper
23
25
 
24
26
  _LOGGER = logging.getLogger(__name__)
25
27
 
@@ -93,25 +95,24 @@ class ModbusSensor(BasicMqtt):
93
95
  modbus,
94
96
  address: str,
95
97
  model: str,
96
- ha_discovery_prefix: str,
97
- topic_prefix: str,
98
- ha_discovery: bool = False,
98
+ config_helper: ConfigHelper,
99
99
  id: str = DefaultName,
100
100
  update_interval: TimePeriod = TimePeriod(seconds=60),
101
101
  **kwargs,
102
102
  ):
103
103
  """Initialize Modbus sensor class."""
104
104
  super().__init__(
105
- id=id or address, topic_type=SENSOR, topic_prefix=topic_prefix, **kwargs
105
+ id=id or address,
106
+ topic_type=SENSOR,
107
+ topic_prefix=self._config_helper.topic_prefix,
108
+ **kwargs,
106
109
  )
107
- self._topic_prefix = topic_prefix
110
+ self._config_helper = config_helper
108
111
  self._modbus = modbus
109
112
  self._db = open_json(model=model)
110
113
  self._model = self._db[MODEL]
111
114
  self._address = address
112
- self._ha_discovery = ha_discovery
113
115
  self._discovery_sent = False
114
- self._ha_discovery_prefix = ha_discovery_prefix
115
116
  self._update_interval = update_interval
116
117
 
117
118
  def _send_ha_autodiscovery(
@@ -121,11 +122,11 @@ class ModbusSensor(BasicMqtt):
121
122
  _LOGGER.debug("Sending HA discovery for sensor %s %s.", sdm_name, sensor_id)
122
123
  self._send_message(
123
124
  topic=(
124
- f"{self._ha_discovery_prefix}/{SENSOR}/{self._topic_prefix}{id}"
125
+ f"{self._config_helper.ha_discovery_prefix}/{SENSOR}/{self._config_helper.topic_prefix}{id}"
125
126
  f"/{id}{sensor_id.replace('_', '').replace(' ', '').lower()}/config"
126
127
  ),
127
128
  payload=modbus_sensor_availabilty_message(
128
- topic=self._topic_prefix,
129
+ topic=self._config_helper.topic_prefix,
129
130
  id=id,
130
131
  name=sdm_name,
131
132
  model=self._model,
@@ -166,7 +167,7 @@ class ModbusSensor(BasicMqtt):
166
167
  if (
167
168
  not self._discovery_sent
168
169
  or (datetime.now() - self._discovery_sent).seconds > 3600
169
- ) and self._ha_discovery:
170
+ ) and self._config_helper.topic_prefix:
170
171
  self._discovery_sent = False
171
172
  first_register_base = self._db[REGISTERS_BASE][0]
172
173
  register_method = first_register_base.get("register_type", "input")
@@ -201,7 +202,7 @@ class ModbusSensor(BasicMqtt):
201
202
  _LOGGER.info("Sending online payload about device.")
202
203
  payload_online = ONLINE
203
204
  self._send_message(
204
- topic=f"{self._topic_prefix}/{self._id}{STATE}",
205
+ topic=f"{self._config_helper.topic_prefix}/{self._id}{STATE}",
205
206
  payload=payload_online,
206
207
  )
207
208
  if not values:
@@ -212,7 +213,7 @@ class ModbusSensor(BasicMqtt):
212
213
  # Let's assume device is offline.
213
214
  payload_online = OFFLINE
214
215
  self._send_message(
215
- topic=f"{self._topic_prefix}/{self._id}{STATE}",
216
+ topic=f"{self._config_helper.topic_prefix}/{self._id}{STATE}",
216
217
  payload=payload_online,
217
218
  )
218
219
  _LOGGER.warn(
@@ -0,0 +1,2 @@
1
+ # flake8: noqa
2
+ __version__ = "0.3.0.dev4"
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneio
3
- Version: 0.3.0.dev3
3
+ Version: 0.3.0.dev4
4
4
  Summary: Python App for BoneIO
5
5
  Home-page: https://github.com/boneIO-eu/app_bbb
6
- Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.3.0.dev3.zip
6
+ Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.3.0.dev4.zip
7
7
  License: GNU General Public License v3.0
8
8
  Platform: UNKNOWN
9
9
  Classifier: Programming Language :: Python
@@ -28,6 +28,7 @@ boneio/example_config/output24x16A.yaml
28
28
  boneio/example_config/output32x5A.yaml
29
29
  boneio/fonts/danube__.ttf
30
30
  boneio/helper/__init__.py
31
+ boneio/helper/config.py
31
32
  boneio/helper/events.py
32
33
  boneio/helper/exceptions.py
33
34
  boneio/helper/gpio.py
@@ -1,2 +0,0 @@
1
- # flake8: noqa
2
- __version__ = "0.3.0.dev3"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes