boneIO 0.1.2__tar.gz → 0.1.4__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 (50) hide show
  1. {boneio-0.1.2/boneio.egg-info → boneio-0.1.4}/PKG-INFO +2 -2
  2. {boneio-0.1.2 → boneio-0.1.4}/boneio/bonecli.py +3 -7
  3. {boneio-0.1.2 → boneio-0.1.4}/boneio/const.py +4 -0
  4. {boneio-0.1.2 → boneio-0.1.4}/boneio/example_config/input.yaml +95 -91
  5. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/__init__.py +10 -1
  6. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/gpio.py +9 -7
  7. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/ha_discovery.py +21 -20
  8. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/stats.py +2 -1
  9. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/yaml.py +18 -0
  10. {boneio-0.1.2 → boneio-0.1.4}/boneio/manager.py +38 -23
  11. {boneio-0.1.2 → boneio-0.1.4}/boneio/oled.py +33 -8
  12. {boneio-0.1.2 → boneio-0.1.4}/boneio/relay/basic.py +13 -7
  13. {boneio-0.1.2 → boneio-0.1.4}/boneio/relay/mcp.py +5 -5
  14. {boneio-0.1.2 → boneio-0.1.4}/boneio/schema.yaml +24 -5
  15. {boneio-0.1.2 → boneio-0.1.4}/boneio/sensor/sdm630.py +13 -8
  16. boneio-0.1.4/boneio/version.py +2 -0
  17. {boneio-0.1.2 → boneio-0.1.4/boneio.egg-info}/PKG-INFO +2 -2
  18. boneio-0.1.2/boneio/version.py +0 -2
  19. {boneio-0.1.2 → boneio-0.1.4}/LICENSE +0 -0
  20. {boneio-0.1.2 → boneio-0.1.4}/MANIFEST.in +0 -0
  21. {boneio-0.1.2 → boneio-0.1.4}/README.md +0 -0
  22. {boneio-0.1.2 → boneio-0.1.4}/boneio/__init__.py +0 -0
  23. {boneio-0.1.2 → boneio-0.1.4}/boneio/example_config/__init__.py +0 -0
  24. {boneio-0.1.2 → boneio-0.1.4}/boneio/example_config/adc.yaml +0 -0
  25. {boneio-0.1.2 → boneio-0.1.4}/boneio/example_config/config.yaml +0 -0
  26. {boneio-0.1.2 → boneio-0.1.4}/boneio/example_config/output24x16A.yaml +0 -0
  27. {boneio-0.1.2 → boneio-0.1.4}/boneio/example_config/output32x5A.yaml +0 -0
  28. {boneio-0.1.2 → boneio-0.1.4}/boneio/fonts/danube__.ttf +0 -0
  29. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/exceptions.py +0 -0
  30. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/mqtt.py +0 -0
  31. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/oled.py +0 -0
  32. {boneio-0.1.2 → boneio-0.1.4}/boneio/helper/queue.py +0 -0
  33. {boneio-0.1.2 → boneio-0.1.4}/boneio/input/__init__.py +0 -0
  34. {boneio-0.1.2 → boneio-0.1.4}/boneio/input/gpio.py +0 -0
  35. {boneio-0.1.2 → boneio-0.1.4}/boneio/modbus.py +0 -0
  36. {boneio-0.1.2 → boneio-0.1.4}/boneio/mqtt_client.py +0 -0
  37. {boneio-0.1.2 → boneio-0.1.4}/boneio/relay/__init__.py +0 -0
  38. {boneio-0.1.2 → boneio-0.1.4}/boneio/relay/gpio.py +0 -0
  39. {boneio-0.1.2 → boneio-0.1.4}/boneio/sensor/__init__.py +0 -0
  40. {boneio-0.1.2 → boneio-0.1.4}/boneio/sensor/adc.py +0 -0
  41. {boneio-0.1.2 → boneio-0.1.4}/boneio/sensor/gpio.py +0 -0
  42. {boneio-0.1.2 → boneio-0.1.4}/boneio/sensor/temp/__init__.py +0 -0
  43. {boneio-0.1.2 → boneio-0.1.4}/boneio.egg-info/SOURCES.txt +0 -0
  44. {boneio-0.1.2 → boneio-0.1.4}/boneio.egg-info/dependency_links.txt +0 -0
  45. {boneio-0.1.2 → boneio-0.1.4}/boneio.egg-info/entry_points.txt +0 -0
  46. {boneio-0.1.2 → boneio-0.1.4}/boneio.egg-info/requires.txt +0 -0
  47. {boneio-0.1.2 → boneio-0.1.4}/boneio.egg-info/top_level.txt +0 -0
  48. {boneio-0.1.2 → boneio-0.1.4}/requirements.txt +0 -0
  49. {boneio-0.1.2 → boneio-0.1.4}/setup.cfg +0 -0
  50. {boneio-0.1.2 → boneio-0.1.4}/setup.py +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneio
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Python App for BoneIO
5
5
  Home-page: https://github.com/boneIO-eu/app_bbb
6
6
  License: GNU General Public License v3.0
7
- Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.1.2.zip
7
+ Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.1.4.zip
8
8
  Platform: UNKNOWN
9
9
  Classifier: Programming Language :: Python
10
10
  Classifier: Programming Language :: Python :: 3.7
@@ -26,7 +26,7 @@ from boneio.const import (
26
26
  TOPIC_PREFIX,
27
27
  USERNAME,
28
28
  )
29
- from boneio.helper import CustomValidator, load_yaml_file
29
+ from boneio.helper import load_config_from_file
30
30
  from boneio.manager import Manager
31
31
  from boneio.mqtt_client import MQTTClient
32
32
  from boneio.version import __version__
@@ -124,13 +124,9 @@ async def run(ctx, debug: int, config: str, mqttpassword: str = ""):
124
124
  logging.getLogger("pymodbus.client").setLevel(logging.DEBUG)
125
125
  else:
126
126
  logging.getLogger(PAHO).setLevel(logging.WARN)
127
- schema = load_yaml_file(os.path.join(MAINPATH, "schema.yaml"))
128
- v = CustomValidator(schema, purge_unknown=True)
129
- config_yaml = load_yaml_file(config)
130
- if not config_yaml:
131
- _LOGGER.info("Missing file.")
127
+ _config = load_config_from_file(config_file=config)
128
+ if not _config:
132
129
  return
133
- _config = v.normalized(config_yaml)
134
130
  _LOGGER.info("Connecting to MQTT.")
135
131
  client = MQTTClient(
136
132
  host=_config[MQTT][HOST],
@@ -3,6 +3,8 @@ from datetime import timedelta
3
3
  from Adafruit_BBIO.GPIO import HIGH, LOW, BOTH, FALLING
4
4
  from typing_extensions import Literal
5
5
 
6
+ BONEIO = "boneIO"
7
+ NONE = "none"
6
8
 
7
9
  # MISCELLANEOUS CONSTS
8
10
  RELAY = "relay"
@@ -15,6 +17,7 @@ PIN = "pin"
15
17
  ID = "id"
16
18
  KIND = "kind"
17
19
  GPIO = "gpio"
20
+ GPIO_MODE = "gpio_mode"
18
21
  ACTIONS = "actions"
19
22
  ACTION = "action"
20
23
  OUTPUT = "output"
@@ -46,6 +49,7 @@ SECOND_DELAY_DURATION = 0.3
46
49
  HOMEASSISTANT = "homeassistant"
47
50
  HA_DISCOVERY = "ha_discovery"
48
51
  HA_TYPE = "ha_type"
52
+ OUTPUT_TYPE = "output_type"
49
53
  SHOW_HA = "show_in_ha"
50
54
 
51
55
  # OLED CONST
@@ -1,5 +1,5 @@
1
- - id: J1_2
2
- pin: P9_29
1
+ - id: IN_01
2
+ pin: P8_37
3
3
  actions:
4
4
  single:
5
5
  action: output
@@ -7,8 +7,8 @@
7
7
  double:
8
8
  action: output
9
9
  pin: switch 1
10
- - id: J1_3
11
- pin: P9_30
10
+ - id: IN_02
11
+ pin: P8_38
12
12
  actions:
13
13
  single:
14
14
  action: output
@@ -16,8 +16,8 @@
16
16
  double:
17
17
  action: output
18
18
  pin: switch 2
19
- - id: J1_4
20
- pin: P9_31
19
+ - id: IN_03
20
+ pin: P8_39
21
21
  actions:
22
22
  single:
23
23
  action: output
@@ -25,8 +25,8 @@
25
25
  double:
26
26
  action: output
27
27
  pin: switch 3
28
- - id: J1_5
29
- pin: P9_42
28
+ - id: IN_04
29
+ pin: P8_40
30
30
  actions:
31
31
  single:
32
32
  action: output
@@ -34,8 +34,8 @@
34
34
  double:
35
35
  action: output
36
36
  pin: switch 4
37
- - id: J1_6
38
- pin: P8_46
37
+ - id: IN_05
38
+ pin: P8_41
39
39
  actions:
40
40
  single:
41
41
  action: output
@@ -43,8 +43,8 @@
43
43
  double:
44
44
  action: output
45
45
  pin: switch 5
46
- - id: J1_7
47
- pin: P8_45
46
+ - id: IN_06
47
+ pin: P8_42
48
48
  actions:
49
49
  single:
50
50
  action: output
@@ -52,149 +52,153 @@
52
52
  double:
53
53
  action: output
54
54
  pin: switch 6
55
- - id: J1_8
56
- pin: P8_44
55
+ - id: IN_07
56
+ pin: P8_43
57
57
  actions:
58
58
  single:
59
59
  action: output
60
60
  pin: light 7
61
61
 
62
- - id: J2_2
63
- pin: P8_36
62
+ - id: IN_08
63
+ pin: P8_44
64
64
  actions:
65
65
  single:
66
66
  action: output
67
67
  pin: light 8
68
- - id: J2_3
69
- pin: P8_35
68
+ - id: IN_09
69
+ pin: P8_45
70
70
  actions:
71
71
  single:
72
72
  action: output
73
73
  pin: light 9
74
- - id: J2_4
75
- pin: P8_34
74
+ - id: IN_10
75
+ pin: P8_46
76
76
  actions:
77
77
  single:
78
78
  action: output
79
79
  pin: light 10
80
- - id: J2_5
81
- pin: P8_33
80
+ - id: IN_11
81
+ pin: P9_42
82
82
  actions:
83
83
  single:
84
84
  action: output
85
85
  pin: light 11
86
- - id: J2_6
87
- pin: P8_32
86
+ - id: IN_12
87
+ pin: P9_31
88
88
  actions:
89
89
  single:
90
90
  action: output
91
91
  pin: light 12
92
- - id: J2_7
93
- pin: P8_31
92
+ - id: IN_13
93
+ pin: P9_30
94
94
  actions:
95
95
  single:
96
96
  action: output
97
97
  pin: light 13
98
- - id: J2_8
99
- pin: P8_30
98
+ - id: IN_14
99
+ pin: P9_29
100
100
  actions:
101
101
  single:
102
102
  action: output
103
103
  pin: light 14
104
104
 
105
- - id: J3_2
106
- pin: P8_43
105
+ - id: IN_15
106
+ pin: P9_28
107
107
  actions:
108
108
  single:
109
109
  action: output
110
110
  pin: light 15
111
- - id: J3_3
112
- pin: P8_42
111
+ - id: IN_16
112
+ pin: P9_27
113
113
  actions:
114
114
  single:
115
115
  action: output
116
116
  pin: light 16
117
- - id: J3_4
118
- pin: P8_41
117
+ - id: IN_17
118
+ pin: P9_25
119
119
  actions:
120
120
  single:
121
121
  action: output
122
122
  pin: light 4
123
- - id: J3_5
124
- pin: P8_40
125
- - id: J3_6
126
- pin: P8_39
127
- - id: J3_7
128
- pin: P8_38
129
- - id: J3_8
130
- pin: P8_37
123
+ - id: IN_18
124
+ pin: P9_23
125
+ - id: IN_19
126
+ pin: P9_22
127
+ - id: IN_20
128
+ pin: P9_21
129
+ - id: IN_21
130
+ pin: P9_18
131
+
132
+ - id: IN_22
133
+ pin: P9_17
134
+ - id: IN_23
135
+ pin: P9_16
136
+ - id: IN_24
137
+ pin: P9_15
138
+ - id: IN_25
139
+ pin: P9_14
140
+ - id: IN_26
141
+ pin: P9_13
142
+ - id: IN_27
143
+ pin: P9_12
144
+ - id: IN_28
145
+ pin: P9_11
131
146
 
132
- - id: J4_2
147
+ - id: IN_29
148
+ pin: P8_36
149
+ - id: IN_30
150
+ pin: P8_35
151
+ - id: IN_31
152
+ pin: P8_34
153
+ - id: IN_32
154
+ pin: P8_33
155
+
156
+ - id: IN_33
157
+ pin: P8_32
158
+ - id: IN_34
159
+ pin: P8_31
160
+ - id: IN_35
161
+ pin: P8_30
162
+ - id: IN_36
133
163
  pin: P8_29
134
- - id: J4_3
164
+ - id: IN_37
135
165
  pin: P8_28
136
- - id: J4_4
166
+ - id: IN_38
137
167
  pin: P8_27
138
- - id: J4_5
168
+ - id: IN_39
139
169
  pin: P8_26
140
- - id: J4_6
170
+
171
+ - id: IN_40
141
172
  pin: P8_19
142
- - id: J4_7
173
+ - id: IN_41
143
174
  pin: P8_18
144
- - id: J4_8
175
+ - id: IN_42
145
176
  pin: P8_17
146
-
147
- - id: J5_2
148
- pin: P9_18
149
- - id: J5_3
150
- pin: P9_21
151
- - id: J5_4
152
- pin: P9_22
153
- - id: J5_5
154
- pin: P9_23
155
- - id: J5_6
156
- pin: P8_25 #MMC1_DAT0
157
- - id: J5_7
158
- pin: P8_27 #LCD VSYNC
159
- - id: J5_8
160
- pin: P8_28 #LCD_PCLK
161
-
162
- - id: J6_2
177
+ - id: IN_43
163
178
  pin: P8_16
164
- - id: J6_3
179
+ - id: IN_44
165
180
  pin: P8_15
166
- - id: J6_4
181
+ - id: IN_45
167
182
  pin: P8_14
168
- - id: J6_5
183
+ - id: IN_46
169
184
  pin: P8_13
170
- - id: J6_6
185
+
186
+ - id: IN_47
171
187
  pin: P8_12
172
- - id: J6_7
188
+ kind: sensor
189
+ - id: IN_48
173
190
  pin: P8_11
174
- - id: J6_8
191
+ kind: sensor
192
+ - id: IN_49
175
193
  pin: P8_10
194
+ kind: sensor
176
195
 
177
- - id: J7_2
178
- pin: P9_11
179
- - id: J7_3
180
- pin: P9_12
181
- - id: J7_4
182
- pin: P9_13
183
- - id: J7_5
184
- pin: P9_14
185
- - id: J7_6
186
- pin: P9_15
187
- - id: J7_7
188
- pin: P9_16
189
- - id: J7_8
190
- pin: P9_17
191
-
192
- - id: J8_2
193
- pin: P8_9
196
+ - id: IN_50
197
+ pin: P8_12
194
198
  kind: sensor
195
- - id: J8_3
199
+ - id: IN_51
196
200
  pin: P8_8
197
201
  kind: sensor
198
- - id: J8_4
202
+ - id: IN_52
199
203
  pin: P8_7
200
204
  kind: sensor
@@ -11,7 +11,13 @@ from boneio.helper.gpio import (
11
11
  from boneio.helper.oled import make_font
12
12
  from boneio.helper.mqtt import BasicMqtt
13
13
  from boneio.helper.stats import HostData, host_stats
14
- from boneio.helper.yaml import CustomValidator, load_yaml_file
14
+ from boneio.helper.yaml import (
15
+ CustomValidator,
16
+ load_yaml_file,
17
+ schema_file,
18
+ load_config_from_string,
19
+ load_config_from_file,
20
+ )
15
21
  from boneio.helper.ha_discovery import (
16
22
  ha_relay_availabilty_message,
17
23
  ha_sensor_temp_availabilty_message,
@@ -47,4 +53,7 @@ __all__ = [
47
53
  "configure_pin",
48
54
  "BasicMqtt",
49
55
  "UniqueQueue",
56
+ "schema_file",
57
+ "load_config_from_string",
58
+ "load_config_from_file",
50
59
  ]
@@ -10,6 +10,7 @@ import subprocess
10
10
  from boneio.const import (
11
11
  CONFIG_PIN,
12
12
  GPIO as GPIO_STR,
13
+ GPIO_MODE,
13
14
  ClickTypes,
14
15
  )
15
16
 
@@ -27,13 +28,13 @@ def configure_pin(pin: str, mode: str = GPIO_STR) -> None:
27
28
  )
28
29
 
29
30
 
30
- def setup_output(pin: str):
31
+ def setup_output(pin: str) -> None:
31
32
  """Set up a GPIO as output."""
32
33
 
33
34
  GPIO.setup(pin, GPIO.OUT, pull_up_down=GPIO.PUD_DOWN)
34
35
 
35
36
 
36
- def setup_input(pin: str, pull_mode: str = "UP"):
37
+ def setup_input(pin: str, pull_mode: str = "UP") -> None:
37
38
  """Set up a GPIO as input."""
38
39
  try:
39
40
  GPIO.setup(pin, GPIO.IN, GPIO.PUD_DOWN if pull_mode == "DOWN" else GPIO.PUD_UP)
@@ -41,20 +42,20 @@ def setup_input(pin: str, pull_mode: str = "UP"):
41
42
  raise GPIOInputException(err)
42
43
 
43
44
 
44
- def write_output(pin: str, value: str):
45
+ def write_output(pin: str, value: str) -> None:
45
46
  """Write a value to a GPIO."""
46
47
 
47
48
  GPIO.output(pin, value)
48
49
 
49
50
 
50
- def read_input(pin: str, on_state: Gpio_States = LOW):
51
+ def read_input(pin: str, on_state: Gpio_States = LOW) -> None:
51
52
  """Read a value from a GPIO."""
52
53
  return GPIO.input(pin) is on_state
53
54
 
54
55
 
55
56
  def edge_detect(
56
57
  pin: str, callback: Callable, bounce: int = 0, edge: Gpio_Edges = FALLING
57
- ):
58
+ ) -> None:
58
59
  """Add detection for RISING and FALLING events."""
59
60
  try:
60
61
  GPIO.add_event_detect(gpio=pin, edge=edge, callback=callback, bouncetime=bounce)
@@ -70,10 +71,11 @@ class GpioBaseClass:
70
71
  ) -> None:
71
72
  """Setup GPIO Input Button"""
72
73
  self._pin = pin
73
- configure_pin(pin)
74
+ gpio = kwargs.get("rest_pin", {GPIO_MODE: GPIO_STR})
75
+ configure_pin(pin=pin, mode=gpio.get(GPIO_MODE, GPIO_STR))
74
76
  self._loop = asyncio.get_running_loop()
75
77
  self._press_callback = press_callback
76
- setup_input(self._pin)
78
+ setup_input(pin=self._pin)
77
79
 
78
80
  @property
79
81
  def is_pressed(self):
@@ -4,16 +4,16 @@ from boneio.version import __version__
4
4
  from boneio.const import INPUT, OFF, ON, RELAY, STATE, SENSOR, INPUT_SENSOR
5
5
 
6
6
 
7
- def ha_relay_availabilty_message(id: str, name: str, topic: str = "boneio"):
7
+ def ha_relay_availabilty_message(id: str, name: str, topic: str = "boneIO"):
8
8
  """Create availability topic for HA."""
9
9
  return {
10
10
  "availability": [{"topic": f"{topic}/{STATE}"}],
11
11
  "command_topic": f"{topic}/relay/{id}/set",
12
12
  "device": {
13
13
  "identifiers": [topic],
14
- "manufacturer": "BoneIO",
15
- "model": "BoneIO Relay Board",
16
- "name": f"BoneIO {topic}",
14
+ "manufacturer": "boneIO",
15
+ "model": "boneIO Relay Board",
16
+ "name": f"boneIO {topic}",
17
17
  "sw_version": __version__,
18
18
  },
19
19
  "name": name,
@@ -26,16 +26,16 @@ def ha_relay_availabilty_message(id: str, name: str, topic: str = "boneio"):
26
26
 
27
27
 
28
28
  def ha_availabilty_message(
29
- id: str, name: str, topic: str = "boneio", sensor_type: str = INPUT
29
+ id: str, name: str, topic: str = "boneIO", sensor_type: str = INPUT
30
30
  ):
31
31
  """Create availability topic for HA."""
32
32
  return {
33
33
  "availability": [{"topic": f"{topic}/{STATE}"}],
34
34
  "device": {
35
35
  "identifiers": [topic],
36
- "manufacturer": "BoneIO",
37
- "model": "BoneIO Relay Board",
38
- "name": f"BoneIO {topic}",
36
+ "manufacturer": "boneIO",
37
+ "model": "boneIO Relay Board",
38
+ "name": f"boneIO {topic}",
39
39
  "sw_version": __version__,
40
40
  },
41
41
  "icon": "mdi:gesture-double-tap",
@@ -63,15 +63,15 @@ def ha_sensor_availabilty_message(unit_of_measurement: str = None, **kwargs):
63
63
  return msg
64
64
 
65
65
 
66
- def ha_binary_sensor_availabilty_message(id: str, name: str, topic: str = "boneio"):
66
+ def ha_binary_sensor_availabilty_message(id: str, name: str, topic: str = "boneIO"):
67
67
  """Create availability topic for HA."""
68
68
  return {
69
69
  "availability": [{"topic": f"{topic}/{STATE}"}],
70
70
  "device": {
71
71
  "identifiers": [topic],
72
- "manufacturer": "BoneIO",
73
- "model": "BoneIO Relay Board",
74
- "name": f"BoneIO {topic}",
72
+ "manufacturer": "boneIO",
73
+ "model": "boneIO Relay Board",
74
+ "name": f"boneIO {topic}",
75
75
  "sw_version": __version__,
76
76
  },
77
77
  "payload_on": "pressed",
@@ -82,15 +82,15 @@ def ha_binary_sensor_availabilty_message(id: str, name: str, topic: str = "bonei
82
82
  }
83
83
 
84
84
 
85
- def ha_sensor_temp_availabilty_message(id: str, name: str, topic: str = "boneio"):
85
+ def ha_sensor_temp_availabilty_message(id: str, name: str, topic: str = "boneIO"):
86
86
  """Create availability topic for HA."""
87
87
  return {
88
88
  "availability": [{"topic": f"{topic}/{STATE}"}],
89
89
  "device": {
90
90
  "identifiers": [topic],
91
- "manufacturer": "BoneIO",
92
- "model": "BoneIO Relay Board",
93
- "name": f"BoneIO {topic}",
91
+ "manufacturer": "boneIO",
92
+ "model": "boneIO Relay Board",
93
+ "name": f"boneIO {topic}",
94
94
  "sw_version": __version__,
95
95
  },
96
96
  "name": name,
@@ -107,6 +107,7 @@ def sdm630_availabilty_message(
107
107
  id: str,
108
108
  sensor_id: str,
109
109
  name: str,
110
+ state_topic_base: str,
110
111
  topic: str = "sdm630",
111
112
  sensor_type: str = SENSOR,
112
113
  **kwargs,
@@ -115,14 +116,14 @@ def sdm630_availabilty_message(
115
116
  return {
116
117
  "availability": [{"topic": f"{topic}/{id}{STATE}"}],
117
118
  "device": {
118
- "identifiers": [topic, id],
119
- "manufacturer": "BoneIO",
119
+ "identifiers": [id],
120
+ "manufacturer": "boneIO",
120
121
  "model": "SDM630",
121
- "name": f"BoneIO {name.upper()}",
122
+ "name": f"boneIO {name.upper()}",
122
123
  "sw_version": __version__,
123
124
  },
124
125
  "name": sensor_id,
125
- "state_topic": f"{topic}/{sensor_type}/{id}/{sensor_id}",
126
+ "state_topic": f"{topic}/{sensor_type}/{id}/{state_topic_base}",
126
127
  "unique_id": f"{topic}{sensor_id.replace('_', '').lower()}",
127
128
  **kwargs,
128
129
  }
@@ -23,6 +23,7 @@ from boneio.const import (
23
23
  NONE,
24
24
  )
25
25
  from boneio.sensor import LM75Sensor, MCP9808Sensor
26
+ from boneio.version import __version__
26
27
 
27
28
 
28
29
  intervals = (("d", 86400), ("h", 3600), ("m", 60))
@@ -153,7 +154,7 @@ class HostData:
153
154
  ) -> None:
154
155
  """Initialize HostData."""
155
156
  self._hostname = socket.gethostname()
156
- self.data[UPTIME] = {HOST: self._hostname, UPTIME: 0}
157
+ self.data[UPTIME] = {HOST: self._hostname, UPTIME: 0, "version": __version__}
157
158
  self._temp_sensor = temp_sensor
158
159
  self._output = output
159
160
  self._callback = callback
@@ -1,9 +1,13 @@
1
+ import logging
1
2
  from typing import Any
2
3
  import os
3
4
  from cerberus import Validator
4
5
  from boneio.const import ID, OUTPUT
5
6
  from yaml import load, YAMLError, SafeLoader
6
7
 
8
+ schema_file = os.path.join(os.path.dirname(__file__), "../schema.yaml")
9
+ _LOGGER = logging.getLogger(__name__)
10
+
7
11
 
8
12
  class Loader(SafeLoader):
9
13
  """Loader which support for include in yaml files."""
@@ -33,6 +37,20 @@ def load_yaml_file(filename: str) -> Any:
33
37
  raise exception
34
38
 
35
39
 
40
+ def load_config_from_string(config_yaml: str):
41
+ schema = load_yaml_file(schema_file)
42
+ v = CustomValidator(schema, purge_unknown=True)
43
+ return v.normalized(config_yaml)
44
+
45
+
46
+ def load_config_from_file(config_file: str):
47
+ config_yaml = load_yaml_file(config_file)
48
+ if not config_yaml:
49
+ _LOGGER.info("Missing file.")
50
+ return None
51
+ return load_config_from_string(config_yaml)
52
+
53
+
36
54
  class CustomValidator(Validator):
37
55
  """Custom validator of cerberus"""
38
56
 
@@ -12,8 +12,9 @@ from boneio.const import (
12
12
  ACTION,
13
13
  ACTIONS,
14
14
  ADDRESS,
15
+ BONEIO,
15
16
  GPIO,
16
- HA_TYPE,
17
+ OUTPUT_TYPE,
17
18
  HOMEASSISTANT,
18
19
  ID,
19
20
  INIT_SLEEP,
@@ -23,6 +24,7 @@ from boneio.const import (
23
24
  MCP,
24
25
  MCP_ID,
25
26
  MCP_TEMP_9808,
27
+ NONE,
26
28
  OFF,
27
29
  ON,
28
30
  ONLINE,
@@ -66,15 +68,15 @@ class Manager:
66
68
  def __init__(
67
69
  self,
68
70
  send_message: Callable[[str, Union[str, dict]], None],
69
- topic_prefix: str,
70
- relay_pins: List,
71
- input_pins: List,
71
+ relay_pins: List = [],
72
+ input_pins: List = [],
72
73
  sensors: dict = {},
74
+ topic_prefix: str = BONEIO,
73
75
  modbus: dict = None,
74
76
  ha_discovery: bool = True,
75
77
  ha_discovery_prefix: str = HOMEASSISTANT,
76
78
  mcp23017: Optional[List] = None,
77
- oled: bool = False,
79
+ oled: dict = {},
78
80
  adc_list: Optional[List] = None,
79
81
  ) -> None:
80
82
  """Initialize the manager."""
@@ -239,7 +241,7 @@ class Manager:
239
241
  topic_prefix=topic_prefix,
240
242
  mcp=mcp,
241
243
  mcp_id=mcp_id,
242
- ha_type=gpio[HA_TYPE],
244
+ output_type=gpio[OUTPUT_TYPE].lower(),
243
245
  callback=lambda: self._host_data_callback(mcp_id),
244
246
  )
245
247
  self._grouped_outputs[mcp_id][relay_id] = mcp_relay
@@ -257,26 +259,26 @@ class Manager:
257
259
  self._grouped_outputs[GPIO][relay_id] = gpio_relay
258
260
  return gpio_relay
259
261
 
260
- self.output = {
262
+ self._output = {
261
263
  gpio[ID].replace(" ", ""): configure_relay(gpio) for gpio in relay_pins
262
264
  }
263
- for out in self.output.values():
264
- self.send_ha_autodiscovery(
265
- id=out.id,
266
- name=out.name,
267
- ha_type=out.ha_type,
268
- ha_discovery_prefix=ha_discovery_prefix,
269
- availabilty_msg_func=ha_relay_availabilty_message,
270
- )
265
+ for out in self._output.values():
266
+ if out.output_type != NONE:
267
+ self.send_ha_autodiscovery(
268
+ id=out.id,
269
+ name=out.name,
270
+ ha_type=out.output_type,
271
+ ha_discovery_prefix=ha_discovery_prefix,
272
+ availabilty_msg_func=ha_relay_availabilty_message,
273
+ )
271
274
  self._loop.call_soon_threadsafe(
272
275
  self._loop.call_later,
273
276
  0.5,
274
277
  out.send_state,
275
278
  )
276
279
 
277
- def configure_input(gpio):
280
+ def configure_input(gpio: dict, pin: str) -> str:
278
281
  try:
279
- pin = gpio[PIN]
280
282
  input_type = gpio.get(KIND)
281
283
  if input_type == SENSOR:
282
284
  GpioInputSensor(
@@ -312,15 +314,21 @@ class Manager:
312
314
  ha_discovery_prefix=ha_discovery_prefix,
313
315
  availabilty_msg_func=availabilty_msg_func,
314
316
  )
317
+ return pin
315
318
  except GPIOInputException as err:
316
319
  _LOGGER.error("This PIN %s can't be configured. %s", pin, err)
317
320
  pass
318
321
 
319
322
  _LOGGER.info("Initializing inputs. This will take a while.")
323
+ input_pins = set()
320
324
  for gpio in self._input_pins:
321
- configure_input(gpio=gpio)
325
+ pin = gpio[PIN]
326
+ if pin in input_pins:
327
+ _LOGGER.warn("This PIN %s is already configured. Omitting it.", pin)
328
+ continue
329
+ input_pins.add(configure_input(gpio=gpio, pin=pin))
322
330
 
323
- if oled:
331
+ if oled.get("enabled", False):
324
332
  from boneio.oled import Oled
325
333
 
326
334
  self._host_data = HostData(
@@ -333,7 +341,9 @@ class Manager:
333
341
  _LOGGER.debug("Gathering host data enabled.")
334
342
  try:
335
343
  self._oled = Oled(
336
- host_data=self._host_data, output_groups=list(self._grouped_outputs)
344
+ host_data=self._host_data,
345
+ output_groups=list(self._grouped_outputs),
346
+ sleep_timeout=oled.get("screensaver_timeout", 60),
337
347
  )
338
348
  except (GPIOInputException, I2CError) as err:
339
349
  _LOGGER.error("Can't configure OLED display. %s", err)
@@ -359,7 +369,7 @@ class Manager:
359
369
  if action:
360
370
  if action[ACTION] == OUTPUT:
361
371
  """For now only output type is supported"""
362
- relay = self.output.get(action[PIN].replace(" ", ""))
372
+ relay = self._output.get(action[PIN].replace(" ", ""))
363
373
  if relay:
364
374
  relay.toggle()
365
375
  # This is similar how Z2M is clearing click sensor.
@@ -370,8 +380,8 @@ class Manager:
370
380
  id: str,
371
381
  name: str,
372
382
  ha_discovery_prefix: str,
383
+ ha_type: str,
373
384
  availabilty_msg_func: Callable,
374
- ha_type: str = "switch",
375
385
  topic_prefix: str = None,
376
386
  **kwargs,
377
387
  ) -> None:
@@ -390,9 +400,14 @@ class Manager:
390
400
  extracted_relay = topic.replace(f"{self._topic_prefix}/{RELAY}/", "").replace(
391
401
  "/set", ""
392
402
  )
393
- target_device = self.output.get(extracted_relay)
403
+ target_device = self._output.get(extracted_relay)
394
404
  if target_device:
395
405
  if message == ON:
396
406
  target_device.turn_on()
397
407
  elif message == OFF:
398
408
  target_device.turn_off()
409
+
410
+ @property
411
+ def output(self) -> dict:
412
+ """Get list of output."""
413
+ return self._output
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import logging
2
3
  from itertools import cycle
3
4
  from typing import List
@@ -22,27 +23,34 @@ _LOGGER = logging.getLogger(__name__)
22
23
 
23
24
 
24
25
  fontBig = make_font("DejaVuSans.ttf", 12)
25
- fontSmall = make_font("DejaVuSans.ttf", 10)
26
+ fontSmall = make_font("DejaVuSans.ttf", 9)
26
27
  fontExtraSmall = make_font("DejaVuSans.ttf", 7)
27
28
  danube = make_font("danube__.ttf", 15, local=True)
28
29
 
29
30
  screen_order = [UPTIME, NETWORK, CPU, DISK, MEMORY, SWAP]
30
31
 
31
32
  STANDARD_ROWS = [17, 32, 47]
32
- UPTIME_ROWS = list(range(25, 50, 10))
33
+ UPTIME_ROWS = list(range(22, 60, 10))
33
34
  OUTPUT_ROWS = list(range(14, 60, 6))
34
- OUTPUT_COLS = range(0, 101, 50)
35
+ OUTPUT_COLS = range(0, 113, 56)
35
36
 
36
37
 
37
38
  class Oled:
38
39
  """Oled display class."""
39
40
 
40
- def __init__(self, host_data: HostData, output_groups: List[str]) -> None:
41
+ def __init__(
42
+ self, host_data: HostData, output_groups: List[str], sleep_timeout: int
43
+ ) -> None:
41
44
  """Initialize OLED screen."""
45
+ self._loop = asyncio.get_running_loop()
42
46
  self._screen_order = cycle(screen_order + output_groups)
43
47
  self._output_groups = output_groups
44
48
  self._current_screen = next(self._screen_order)
45
49
  self._host_data = host_data
50
+ if sleep_timeout:
51
+ self._sleep = False
52
+ self._sleep_handle = None
53
+ self._sleep_timeout = sleep_timeout
46
54
  configure_pin(OLED_PIN)
47
55
  setup_input(OLED_PIN)
48
56
  edge_detect(pin=OLED_PIN, callback=self._handle_press, bounce=80)
@@ -66,10 +74,15 @@ class Oled:
66
74
  )
67
75
  i += 1
68
76
 
77
+ def _sleeptime(self):
78
+ with canvas(self._device) as draw:
79
+ draw.rectangle(self._device.bounding_box, outline="black", fill="black")
80
+ self._sleep = True
81
+
69
82
  def _draw_uptime(self, data: dict, draw: ImageDraw) -> None:
70
83
  """Draw uptime screen with boneIO logo."""
71
- draw.text((3, 5), "bone", font=danube, fill=WHITE)
72
- draw.text((53, 5), "iO", font=danube, fill=WHITE)
84
+ draw.text((3, 3), "bone", font=danube, fill=WHITE)
85
+ draw.text((53, 3), "iO", font=danube, fill=WHITE)
73
86
  i = 0
74
87
  for k in data:
75
88
  draw.text(
@@ -106,13 +119,25 @@ class Oled:
106
119
  self._draw_uptime(data, draw)
107
120
  else:
108
121
  self._draw_standard(data, draw)
122
+ if not self._sleep_handle and self._sleep_timeout > 0:
123
+ self._sleep_handle = self._loop.call_soon_threadsafe(
124
+ self._loop.call_later,
125
+ self._sleep_timeout,
126
+ self._sleeptime,
127
+ )
109
128
 
110
129
  def handle_data_update(self, type: str):
111
130
  """Callback to handle new data present into screen."""
112
- if type == self._current_screen:
131
+ if type == self._current_screen and not self._sleep:
113
132
  self.render_display()
114
133
 
115
134
  def _handle_press(self, pin: any) -> None:
116
135
  """Handle press of PIN for OLED display."""
117
- self._current_screen = next(self._screen_order)
136
+ if self._sleep_handle:
137
+ self._sleep_handle.cancel()
138
+ self._sleep_handle = None
139
+ if not self._sleep:
140
+ self._current_screen = next(self._screen_order)
141
+ else:
142
+ self._sleep = False
118
143
  self.render_display()
@@ -4,7 +4,7 @@ import asyncio
4
4
  import logging
5
5
  from typing import Callable
6
6
 
7
- from boneio.const import OFF, ON, RELAY, STATE, SWITCH
7
+ from boneio.const import OFF, ON, RELAY, STATE, SWITCH, NONE
8
8
  from boneio.helper import BasicMqtt
9
9
 
10
10
  _LOGGER = logging.getLogger(__name__)
@@ -14,11 +14,11 @@ class BasicRelay(BasicMqtt):
14
14
  """Basic relay class."""
15
15
 
16
16
  def __init__(
17
- self, callback: Callable, id: str = None, ha_type=SWITCH, **kwargs
17
+ self, callback: Callable, id: str = None, output_type=SWITCH, **kwargs
18
18
  ) -> None:
19
19
  """Initialize Basic relay."""
20
20
  super().__init__(id=id, name=id, topic_type=RELAY, **kwargs)
21
- self._ha_type = ha_type
21
+ self._output_type = output_type
22
22
  self._state = False
23
23
  self._callback = callback
24
24
  self._loop = asyncio.get_running_loop()
@@ -28,6 +28,11 @@ class BasicRelay(BasicMqtt):
28
28
  """Check if relay is mcp type."""
29
29
  return False
30
30
 
31
+ @property
32
+ def output_type(self) -> str:
33
+ """HA type."""
34
+ return self._output_type
35
+
31
36
  @property
32
37
  def id(self) -> bool:
33
38
  """Id of the relay.
@@ -48,10 +53,11 @@ class BasicRelay(BasicMqtt):
48
53
  """Send state to Mqtt on action."""
49
54
  state = ON if self.is_active else OFF
50
55
  self._state = state
51
- self._send_message(
52
- topic=self._send_topic,
53
- payload={STATE: state},
54
- )
56
+ if self.output_type != NONE:
57
+ self._send_message(
58
+ topic=self._send_topic,
59
+ payload={STATE: state},
60
+ )
55
61
  self._loop.call_soon_threadsafe(self._callback)
56
62
 
57
63
  def toggle(self) -> None:
@@ -25,6 +25,11 @@ class MCPRelay(BasicRelay):
25
25
  """Check if relay is mcp type."""
26
26
  return True
27
27
 
28
+ @property
29
+ def pin_id(self) -> str:
30
+ """Return PIN id."""
31
+ return self._pin_id
32
+
28
33
  @property
29
34
  def mcp_id(self) -> str:
30
35
  """Retrieve parent MCP ID."""
@@ -40,11 +45,6 @@ class MCPRelay(BasicRelay):
40
45
  """PIN of the relay"""
41
46
  return self._pin
42
47
 
43
- @property
44
- def ha_type(self) -> str:
45
- """HA type."""
46
- return self._ha_type
47
-
48
48
  def turn_on(self) -> None:
49
49
  """Call turn on action."""
50
50
  self.pin.value = True
@@ -49,8 +49,20 @@ mqtt:
49
49
  label: Prefix topic of HA discovery.
50
50
 
51
51
  oled:
52
- type: boolean
53
- coerce: to_bool
52
+ type: dict
53
+ default: {}
54
+ required: True
55
+ schema:
56
+ enabled:
57
+ type: boolean
58
+ default: False
59
+ meta:
60
+ label: Disable builtin screen.
61
+ screensaver_timeout:
62
+ type: integer
63
+ default: 60
64
+ meta:
65
+ label: How many seconds to wait to enable screensaver. 0 means disable screensaver.
54
66
 
55
67
  modbus:
56
68
  type: dict
@@ -174,13 +186,13 @@ output:
174
186
  required: True
175
187
  meta:
176
188
  label: PIN to use.
177
- ha_type:
189
+ output_type:
178
190
  type: string
179
191
  required: True
180
- allowed: ['switch', 'light']
192
+ allowed: ['switch', 'light', 'none']
181
193
  default: 'switch'
182
194
  meta:
183
- label: If HA discovery is used device if relay is light or switch.
195
+ label: If HA discovery is used device if relay is light or switch. If None is declared then any state is not published to MQTT (used for cover).
184
196
 
185
197
 
186
198
  input:
@@ -200,6 +212,13 @@ input:
200
212
  required: True
201
213
  meta:
202
214
  label: PIN to use.
215
+ gpio_mode:
216
+ type: string
217
+ required: True
218
+ default: "gpio"
219
+ allowed: ["gpio", "gpio_pu", "gpio_pd", "gpio_input"]
220
+ meta:
221
+ label: What mode to use in config PIN.
203
222
  show_in_ha:
204
223
  type: boolean
205
224
  required: True
@@ -135,7 +135,7 @@ class Sdm630(BasicMqtt):
135
135
  _LOGGER.debug("Sending HA discovery for sensor %s %s.", sdm_name, sensor_id)
136
136
  self._send_message(
137
137
  topic=(
138
- f"{self._ha_discovery_prefix}/{SENSOR}/{self._topic_prefix}"
138
+ f"{self._ha_discovery_prefix}/{SENSOR}/{self._topic_prefix}{id}"
139
139
  f"/{id}{sensor_id.replace('_', '').lower()}/config"
140
140
  ),
141
141
  payload=sdm630_availabilty_message(
@@ -155,13 +155,16 @@ class Sdm630(BasicMqtt):
155
155
  kwargs = {
156
156
  "unit_of_measurement": getattr(register, "unit_of_measurement"),
157
157
  "state_class": getattr(register, "state_class"),
158
- "value_template": "{{ value | round(2)}}",
158
+ "value_template": f'{{{{ value_json.{getattr(register, "sensor_id")} | round(2) }}}}',
159
159
  "sensor_id": getattr(register, "sensor_id"),
160
160
  }
161
161
  if getattr(register, "device_class"):
162
162
  kwargs["device_class"] = getattr(register, "device_class")
163
163
  self._send_ha_autodiscovery(
164
- id=self._id, sdm_name=self._name, **kwargs
164
+ id=self._id,
165
+ sdm_name=self._name,
166
+ state_topic_base=data[BASE],
167
+ **kwargs,
165
168
  )
166
169
  return True
167
170
  return False
@@ -183,11 +186,13 @@ class Sdm630(BasicMqtt):
183
186
  topic=f"{self._topic_prefix}/{self._id}{STATE}",
184
187
  payload=payload_online,
185
188
  )
189
+ output = {}
186
190
  for register in data["registers"]:
187
- self._send_message(
188
- topic=f'{self._send_topic}/{getattr(register, "sensor_id")}',
189
- payload=float32(
190
- values, data[BASE], getattr(register, "address")
191
- ),
191
+ output[getattr(register, "sensor_id")] = float32(
192
+ values, data[BASE], getattr(register, "address")
192
193
  )
194
+ self._send_message(
195
+ topic=f"{self._send_topic}/{data[BASE]}",
196
+ payload=output,
197
+ )
193
198
  await asyncio.sleep(self._update_interval)
@@ -0,0 +1,2 @@
1
+ # flake8: noqa
2
+ __version__ = "0.1.4"
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneio
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Python App for BoneIO
5
5
  Home-page: https://github.com/boneIO-eu/app_bbb
6
6
  License: GNU General Public License v3.0
7
- Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.1.2.zip
7
+ Download-URL: https://github.com/boneIO-eu/app_bbb/archive/0.1.4.zip
8
8
  Platform: UNKNOWN
9
9
  Classifier: Programming Language :: Python
10
10
  Classifier: Programming Language :: Python :: 3.7
@@ -1,2 +0,0 @@
1
- # flake8: noqa
2
- __version__ = "0.1.2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes