boneIO 0.6.0dev2__py3-none-any.whl → 0.6.0dev4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of boneIO might be problematic. Click here for more details.
- {boneIO-0.6.0.dev2.dist-info → boneIO-0.6.0.dev4.dist-info}/METADATA +2 -2
- {boneIO-0.6.0.dev2.dist-info → boneIO-0.6.0.dev4.dist-info}/RECORD +16 -15
- {boneIO-0.6.0.dev2.dist-info → boneIO-0.6.0.dev4.dist-info}/WHEEL +1 -1
- boneio/const.py +2 -1
- boneio/helper/__init__.py +2 -0
- boneio/helper/click_timer.py +37 -0
- boneio/helper/events.py +65 -5
- boneio/helper/gpio.py +2 -2
- boneio/helper/yaml_util.py +4 -6
- boneio/input/gpio.py +50 -98
- boneio/manager.py +2 -0
- boneio/schema/actions.yaml +2 -1
- boneio/sensor/temp/dallas.py +3 -1
- boneio/version.py +1 -1
- {boneIO-0.6.0.dev2.dist-info → boneIO-0.6.0.dev4.dist-info}/entry_points.txt +0 -0
- {boneIO-0.6.0.dev2.dist-info → boneIO-0.6.0.dev4.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: boneIO
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.0dev4
|
|
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>
|
|
@@ -12,7 +12,7 @@ Requires-Dist: PyYAML>=6.0
|
|
|
12
12
|
Requires-Dist: adafruit-circuitpython-ds18x20>=1.3.12
|
|
13
13
|
Requires-Dist: adafruit-circuitpython-mcp230xx>=2.5.5
|
|
14
14
|
Requires-Dist: adafruit-circuitpython-mcp9808>=3.3.14
|
|
15
|
-
Requires-Dist: adafruit-circuitpython-onewire>=2.0.
|
|
15
|
+
Requires-Dist: adafruit-circuitpython-onewire>=2.0.4
|
|
16
16
|
Requires-Dist: adafruit-circuitpython-pca9685>=3.4.6
|
|
17
17
|
Requires-Dist: adafruit-circuitpython-pct2075>=1.1.14
|
|
18
18
|
Requires-Dist: asyncio-mqtt>=0.12.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
boneio/__init__.py,sha256=hoLKnu6h1uEsiCHA9Ql2MMDC7VQS0E-s_2cxBS-CTOg,147
|
|
2
2
|
boneio/bonecli.py,sha256=Wg3Wc2xZ9FjF_23PK6Ja3YzXUkYanzYyQ_QdtQbKESw,3155
|
|
3
|
-
boneio/const.py,sha256=
|
|
3
|
+
boneio/const.py,sha256=jowaP49OLdHOK2Bop2KDVPVKRVbqjBPHl_Fgl5aRzIg,2924
|
|
4
4
|
boneio/cover.py,sha256=nr76ft5smAPdBB8Jytk-uFd6RWuqtcZiG6EE129OUjw,8454
|
|
5
5
|
boneio/example_config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
boneio/example_config/adc.yaml,sha256=KaNfPuZmrhpiKJVUKC6uQXQ0YRCp0DoXVxYtqsbiSGI,168
|
|
@@ -11,13 +11,14 @@ boneio/example_config/led32x4A.yaml,sha256=YkcZ5XH2JF9Oa3pAmrYM5wsE8qQODCHcjYH47
|
|
|
11
11
|
boneio/example_config/output24x16A.yaml,sha256=BTtHToRgz-U_rMMDbmHkM4wQxHakdzInb3zKMkOkj4w,1691
|
|
12
12
|
boneio/example_config/output32x5A.yaml,sha256=G2Pb6qL8mXs6MliIM1roAanPag9ozRe3McYYuFsiBc0,2403
|
|
13
13
|
boneio/fonts/danube__.ttf,sha256=KBRPUcGvmroCjrWC8zK4MulUb9lV8R0lXkOY7lNnQWc,19372
|
|
14
|
-
boneio/helper/__init__.py,sha256=
|
|
14
|
+
boneio/helper/__init__.py,sha256=r-9dubCtDlrs_HFF2OGPQEPmw1XREgb4qQF6I486Li4,2039
|
|
15
15
|
boneio/helper/async_updater.py,sha256=BVh5mXFxgaZqoekjQbQSCTssfyVIdCQ80LCJny-rOo4,985
|
|
16
|
+
boneio/helper/click_timer.py,sha256=blWofzFIwuYcF_yFfCGDtI8nGSMpSdXdl9qMLXlKdXc,1169
|
|
16
17
|
boneio/helper/config.py,sha256=XeHG7OSMCMmEL43rCbWy6Ij0RcTNlrIpevWZ0UJyrlo,1311
|
|
17
|
-
boneio/helper/events.py,sha256=
|
|
18
|
+
boneio/helper/events.py,sha256=EHYJy507RF1LikWQ2s4r990JRvR9rO4z7FkaJqt1Mrk,7494
|
|
18
19
|
boneio/helper/exceptions.py,sha256=Tll3ZZPOo0JZskN67hkoAxxGJ4I5ZY4IjeXtKyveziI,637
|
|
19
20
|
boneio/helper/filter.py,sha256=UcjifjaC5wHDW2He7wmwCX2IjSSeLVhXyhrXHeT8RmA,885
|
|
20
|
-
boneio/helper/gpio.py,sha256=
|
|
21
|
+
boneio/helper/gpio.py,sha256=v4QrJfwlhIOqRCcD1SCpwPVcY6zsTlm1tens0eLbazM,2718
|
|
21
22
|
boneio/helper/ha_discovery.py,sha256=e2xjArXixpbVru3oD_8L8UKMgEkpbL5OV2ybZaNi-f0,6129
|
|
22
23
|
boneio/helper/loader.py,sha256=8lWjNVLcV-uqIGGgD7bY3lGEK9dhEDB0wQppxFb_Vys,13488
|
|
23
24
|
boneio/helper/logger.py,sha256=zyF_Vk3o2eSHuXypJhNzK99eZgkWDWybuB5KcJgurDs,1801
|
|
@@ -32,10 +33,10 @@ boneio/helper/state_manager.py,sha256=LsMQRrD7WXu5jXFoltYXvzHDeiNDDEx6UWYebFw18g
|
|
|
32
33
|
boneio/helper/stats.py,sha256=eLz3-g6cyaClZ7N1YVEuKVg-P6MAhuKX8D-cm5Nj-k8,5693
|
|
33
34
|
boneio/helper/timeperiod.py,sha256=xpg9oe30Z5WiLDQPq3EBKKScejOnN47NhcpeFvDd3bY,5806
|
|
34
35
|
boneio/helper/util.py,sha256=QfSoT3H3WnOQAKO5bFRIBCy62HT5NMa9Ek-FmfTW_rw,508
|
|
35
|
-
boneio/helper/yaml_util.py,sha256=
|
|
36
|
+
boneio/helper/yaml_util.py,sha256=gAX7hCaHUlPgkhGCIQ4zjv0Vj9JmLzQsSyF51ZmSb9g,11304
|
|
36
37
|
boneio/input/__init__.py,sha256=u9wuehuC_TNizL4tyn7EygZW5LaTFjSnFaZeZr3zZ1U,99
|
|
37
|
-
boneio/input/gpio.py,sha256=
|
|
38
|
-
boneio/manager.py,sha256=
|
|
38
|
+
boneio/input/gpio.py,sha256=oCJNJ7FYvznsNt2xwtmEGMOOeXCJj-3Ssh-xMYVXOfQ,2583
|
|
39
|
+
boneio/manager.py,sha256=D_VT_VpGAZo3CVjoxDecYPlQwIbdEA-2rkABXUIDxW4,20273
|
|
39
40
|
boneio/modbus.py,sha256=eA_sGnmdcIneXX75ZcXOI223-UkKN1UYmWFqiJBAhJo,4176
|
|
40
41
|
boneio/mqtt_client.py,sha256=ioOBEmnbjpZjYrD5u8W5CrVsrNFRHDJ93fyk6XcWkeE,6983
|
|
41
42
|
boneio/oled.py,sha256=d_ofDQHc7zr3j0qOR0B_L3C8TJhvRH85nnb9Le-88nk,5244
|
|
@@ -45,7 +46,7 @@ boneio/relay/gpio.py,sha256=s64FBf6zlxciF57xJ6nrvy0t5Rie0uiXlwos0HL3RKM,1163
|
|
|
45
46
|
boneio/relay/mcp.py,sha256=DhgqZbFHB6TucL9hJaJiqdVAbkw4Rv5VPHm_khSBIFo,2669
|
|
46
47
|
boneio/relay/pca.py,sha256=tCwXvMJcsxzFj48ZO2tPYyvElZfyIRTFmEMp7ENKvtk,4873
|
|
47
48
|
boneio/runner.py,sha256=geT_ps_vo1SLoBszmhtcpkzk_LwWpG8OZYgUcQg3nKU,2287
|
|
48
|
-
boneio/schema/actions.yaml,sha256=
|
|
49
|
+
boneio/schema/actions.yaml,sha256=WD0LR9SxVPgwU12x10RvFaTeyDiCjdRiicfkrCGLNvc,1030
|
|
49
50
|
boneio/schema/actions_sensor.yaml,sha256=LhXEsYsg6qs7iHqgQE6n-2jj-o-ZZRusDW_9nWIiZAY,129
|
|
50
51
|
boneio/schema/actions_switch.yaml,sha256=qyooX0izkgl4wBEh8xUsYFEKMrvhbIAQYxOGTB5AROY,124
|
|
51
52
|
boneio/schema/filters.yaml,sha256=WopX1SmCZsSZXNiGccLoi7uMCsUpdbs0eVfsAjmbay4,286
|
|
@@ -65,12 +66,12 @@ boneio/sensor/modbus/sdm120.json,sha256=4sueFfSw7G6a77gdIUhbfJvE-MNVJFOeVbRvHDw5
|
|
|
65
66
|
boneio/sensor/modbus/sdm630.json,sha256=6LbIfXWk_PVRW-OuJwrsFEnRGLVEmEqqGIbj-1FDaiI,10969
|
|
66
67
|
boneio/sensor/modbus/sofar.json,sha256=A_YztQN_ctyItIm2LH1tfcs-pSyG18I530qleLd2tOw,5592
|
|
67
68
|
boneio/sensor/temp/__init__.py,sha256=h5rGbkC8K6y2GJSNHtm9f8EmoBS3wFlSNIFjcrRj470,1659
|
|
68
|
-
boneio/sensor/temp/dallas.py,sha256=
|
|
69
|
+
boneio/sensor/temp/dallas.py,sha256=xrvd1LNBh1fRcjz_yd_9S29Lv26ItVtLCmhZgVQWJos,2485
|
|
69
70
|
boneio/sensor/temp/lm75.py,sha256=-mpOv78429plRPBp9s09Ljz1x2Bdxuagalqz40vlAKE,243
|
|
70
71
|
boneio/sensor/temp/mcp9808.py,sha256=yAh5yJzZLGTqa39xV4fyqsruj7oy3niOZAUV2W6eyCM,271
|
|
71
|
-
boneio/version.py,sha256=
|
|
72
|
-
boneIO-0.6.0.
|
|
73
|
-
boneIO-0.6.0.
|
|
74
|
-
boneIO-0.6.0.
|
|
75
|
-
boneIO-0.6.0.
|
|
76
|
-
boneIO-0.6.0.
|
|
72
|
+
boneio/version.py,sha256=c4Y90PQyvZ4QIDtX6BiDOphICDX-64mrmDrLk75FXoU,41
|
|
73
|
+
boneIO-0.6.0.dev4.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
|
|
74
|
+
boneIO-0.6.0.dev4.dist-info/WHEEL,sha256=lsei1NEk3eJVaxXEuOSSqU002B_yCocFbsEPxBs2x2s,87
|
|
75
|
+
boneIO-0.6.0.dev4.dist-info/METADATA,sha256=S4FUlkbD_kjqB7DboCk17eVjdIYKWoLk_8aSxXLVvTI,1696
|
|
76
|
+
boneIO-0.6.0.dev4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
77
|
+
boneIO-0.6.0.dev4.dist-info/RECORD,,
|
boneio/const.py
CHANGED
|
@@ -18,6 +18,7 @@ RELAY = "relay"
|
|
|
18
18
|
LED = "led"
|
|
19
19
|
ON = "ON"
|
|
20
20
|
OFF = "OFF"
|
|
21
|
+
TOGGLE = "TOGGLE"
|
|
21
22
|
STATE = "state"
|
|
22
23
|
BRIGHTNESS = "brightness"
|
|
23
24
|
SET_BRIGHTNESS = "set_brightness"
|
|
@@ -55,7 +56,7 @@ UARTS = {
|
|
|
55
56
|
"uart5": {ID: "/dev/ttyS5", TX: "P8.37", RX: "P8.38"},
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
relay_actions = {ON: "turn_on", OFF: "turn_off",
|
|
59
|
+
relay_actions = {ON: "turn_on", OFF: "turn_off", TOGGLE: "toggle"}
|
|
59
60
|
|
|
60
61
|
# HA CONSTS
|
|
61
62
|
HOMEASSISTANT = "homeassistant"
|
boneio/helper/__init__.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Helper dir for BoneIO."""
|
|
2
2
|
|
|
3
3
|
from boneio.helper.exceptions import GPIOInputException, GPIOOutputException, I2CError
|
|
4
|
+
from boneio.helper.click_timer import ClickTimer
|
|
4
5
|
from boneio.helper.gpio import (
|
|
5
6
|
GpioBaseClass,
|
|
6
7
|
configure_pin,
|
|
@@ -70,4 +71,5 @@ __all__ = [
|
|
|
70
71
|
"TimePeriod",
|
|
71
72
|
"callback",
|
|
72
73
|
"is_callback",
|
|
74
|
+
"ClickTimer",
|
|
73
75
|
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
from boneio.helper.events import async_call_later_miliseconds
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ClickTimer:
|
|
7
|
+
"""Represent async call later function with variable to check if timing is ON."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, delay: float, action) -> None:
|
|
10
|
+
"""Initialize Click timer."""
|
|
11
|
+
self._loop = asyncio.get_running_loop()
|
|
12
|
+
self._remove_listener = None
|
|
13
|
+
self._delay = delay
|
|
14
|
+
self._action = action
|
|
15
|
+
|
|
16
|
+
def is_waiting(self) -> bool:
|
|
17
|
+
"""If variable is set then timer is ON, if None is Off."""
|
|
18
|
+
return self._remove_listener is not None
|
|
19
|
+
|
|
20
|
+
def action(self, x: float) -> None:
|
|
21
|
+
"""Reset Call later variable and call action."""
|
|
22
|
+
self.reset()
|
|
23
|
+
self._action(x)
|
|
24
|
+
|
|
25
|
+
def reset(self) -> None:
|
|
26
|
+
"""Uninitialize variable remove_listener."""
|
|
27
|
+
if self._remove_listener:
|
|
28
|
+
self._remove_listener()
|
|
29
|
+
self._remove_listener = None
|
|
30
|
+
|
|
31
|
+
def start_timer(self) -> None:
|
|
32
|
+
"""Start timer."""
|
|
33
|
+
self._remove_listener = async_call_later_miliseconds(
|
|
34
|
+
loop=self._loop,
|
|
35
|
+
action=self.action,
|
|
36
|
+
delay=self._delay,
|
|
37
|
+
)
|
boneio/helper/events.py
CHANGED
|
@@ -21,7 +21,9 @@ def utcnow() -> dt.datetime:
|
|
|
21
21
|
time_tracker_utcnow = utcnow
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def _async_create_timer(
|
|
24
|
+
def _async_create_timer(
|
|
25
|
+
loop: asyncio.AbstractEventLoop, event_callback
|
|
26
|
+
) -> CALLBACK_TYPE:
|
|
25
27
|
"""Create a timer that will start on BoneIO start."""
|
|
26
28
|
handle = None
|
|
27
29
|
|
|
@@ -149,6 +151,7 @@ def async_track_point_in_time(
|
|
|
149
151
|
"""Add a listener that fires once after a specific point in UTC time."""
|
|
150
152
|
# Ensure point_in_time is UTC
|
|
151
153
|
utc_point_in_time = as_utc(point_in_time)
|
|
154
|
+
expected_fire_timestamp = utc_point_in_time.timestamp()
|
|
152
155
|
|
|
153
156
|
# Since this is called once, we accept a so we can avoid
|
|
154
157
|
# having to figure out how to call the action every time its called.
|
|
@@ -159,14 +162,12 @@ def async_track_point_in_time(
|
|
|
159
162
|
"""Call the action."""
|
|
160
163
|
nonlocal cancel_callback
|
|
161
164
|
|
|
162
|
-
now = time_tracker_utcnow()
|
|
163
|
-
|
|
164
165
|
# Depending on the available clock support (including timer hardware
|
|
165
166
|
# and the OS kernel) it can happen that we fire a little bit too early
|
|
166
167
|
# as measured by utcnow(). That is bad when callbacks have assumptions
|
|
167
168
|
# about the current time. Thus, we rearm the timer for the remaining
|
|
168
169
|
# time.
|
|
169
|
-
delta =
|
|
170
|
+
delta = expected_fire_timestamp - time.time()
|
|
170
171
|
if delta > 0:
|
|
171
172
|
_LOGGER.debug("Called %f seconds too early, rearming", delta)
|
|
172
173
|
|
|
@@ -175,7 +176,52 @@ def async_track_point_in_time(
|
|
|
175
176
|
|
|
176
177
|
loop.call_soon(job, utc_point_in_time)
|
|
177
178
|
|
|
178
|
-
delta =
|
|
179
|
+
delta = expected_fire_timestamp - time.time()
|
|
180
|
+
cancel_callback = loop.call_later(delta, run_action, action)
|
|
181
|
+
|
|
182
|
+
@callback
|
|
183
|
+
def unsub_point_in_time_listener() -> None:
|
|
184
|
+
"""Cancel the call_later."""
|
|
185
|
+
assert cancel_callback is not None
|
|
186
|
+
cancel_callback.cancel()
|
|
187
|
+
|
|
188
|
+
return unsub_point_in_time_listener
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@callback
|
|
192
|
+
def async_track_point_in_timestamp(
|
|
193
|
+
loop: asyncio.AbstractEventLoop,
|
|
194
|
+
action,
|
|
195
|
+
timestamp: float,
|
|
196
|
+
) -> CALLBACK_TYPE:
|
|
197
|
+
"""Add a listener that fires once after a specific point in UTC time."""
|
|
198
|
+
# Since this is called once, we accept a so we can avoid
|
|
199
|
+
# having to figure out how to call the action every time its called.
|
|
200
|
+
cancel_callback: Optional[asyncio.TimerHandle] = None
|
|
201
|
+
|
|
202
|
+
@callback
|
|
203
|
+
def run_action(job) -> None:
|
|
204
|
+
"""Call the action."""
|
|
205
|
+
nonlocal cancel_callback
|
|
206
|
+
|
|
207
|
+
now = time.time()
|
|
208
|
+
|
|
209
|
+
# Depending on the available clock support (including timer hardware
|
|
210
|
+
# and the OS kernel) it can happen that we fire a little bit too early
|
|
211
|
+
# as measured by utcnow(). That is bad when callbacks have assumptions
|
|
212
|
+
# about the current time. Thus, we rearm the timer for the remaining
|
|
213
|
+
# time.
|
|
214
|
+
delta = timestamp - now
|
|
215
|
+
if delta > 0:
|
|
216
|
+
_LOGGER.debug("Called %f seconds too early, rearming", delta)
|
|
217
|
+
|
|
218
|
+
cancel_callback = loop.call_later(delta, run_action, job)
|
|
219
|
+
return
|
|
220
|
+
|
|
221
|
+
loop.call_soon(job, timestamp)
|
|
222
|
+
|
|
223
|
+
now = time.time()
|
|
224
|
+
delta = timestamp - now
|
|
179
225
|
cancel_callback = loop.call_later(delta, run_action, action)
|
|
180
226
|
|
|
181
227
|
@callback
|
|
@@ -185,3 +231,17 @@ def async_track_point_in_time(
|
|
|
185
231
|
cancel_callback.cancel()
|
|
186
232
|
|
|
187
233
|
return unsub_point_in_time_listener
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@callback
|
|
237
|
+
def async_call_later_miliseconds(
|
|
238
|
+
loop: asyncio.AbstractEventLoop,
|
|
239
|
+
action,
|
|
240
|
+
delay: float,
|
|
241
|
+
) -> CALLBACK_TYPE:
|
|
242
|
+
"""Add a listener that fires once after a specific point in UTC time."""
|
|
243
|
+
# Ensure point_in_time is UTC
|
|
244
|
+
expected_fire_timestamp = time.time() + (delay / 1000)
|
|
245
|
+
return async_track_point_in_timestamp(
|
|
246
|
+
loop=loop, action=action, timestamp=expected_fire_timestamp
|
|
247
|
+
)
|
boneio/helper/gpio.py
CHANGED
|
@@ -67,7 +67,7 @@ def write_output(pin: str, value: str) -> None:
|
|
|
67
67
|
GPIO.output(pin, value)
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def read_input(pin: str, on_state: Gpio_States = LOW) ->
|
|
70
|
+
def read_input(pin: str, on_state: Gpio_States = LOW) -> bool:
|
|
71
71
|
"""Read a value from a GPIO."""
|
|
72
72
|
return GPIO.input(pin) is on_state
|
|
73
73
|
|
|
@@ -97,6 +97,6 @@ class GpioBaseClass:
|
|
|
97
97
|
setup_input(pin=self._pin, pull_mode=gpio_mode)
|
|
98
98
|
|
|
99
99
|
@property
|
|
100
|
-
def is_pressed(self):
|
|
100
|
+
def is_pressed(self) -> bool:
|
|
101
101
|
"""Is button pressed."""
|
|
102
102
|
return read_input(self._pin)
|
boneio/helper/yaml_util.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import Any, Tuple
|
|
|
8
8
|
from cerberus import TypeDefinition, Validator
|
|
9
9
|
from yaml import MarkedYAMLError, SafeLoader, YAMLError, load
|
|
10
10
|
|
|
11
|
-
from boneio.const import COVER, ID, OUTPUT
|
|
11
|
+
from boneio.const import COVER, ID, OUTPUT, TOGGLE
|
|
12
12
|
from boneio.helper.exceptions import ConfigurationException
|
|
13
13
|
from boneio.helper.timeperiod import TimePeriod
|
|
14
14
|
|
|
@@ -103,9 +103,7 @@ BoneIOLoader.add_constructor(
|
|
|
103
103
|
BoneIOLoader.add_constructor(
|
|
104
104
|
"!include_dir_merge_named", BoneIOLoader.construct_include_dir_merge_named
|
|
105
105
|
)
|
|
106
|
-
BoneIOLoader.add_constructor(
|
|
107
|
-
"!include_files", BoneIOLoader.construct_include_files
|
|
108
|
-
)
|
|
106
|
+
BoneIOLoader.add_constructor("!include_files", BoneIOLoader.construct_include_files)
|
|
109
107
|
|
|
110
108
|
|
|
111
109
|
def filter_yaml_files(files):
|
|
@@ -246,7 +244,7 @@ class CustomValidator(Validator):
|
|
|
246
244
|
return str(value).upper()
|
|
247
245
|
|
|
248
246
|
def _normalize_coerce_actions_output(self, value):
|
|
249
|
-
return str(value).
|
|
247
|
+
return str(value).upper()
|
|
250
248
|
|
|
251
249
|
def _normalize_coerce_str(self, value):
|
|
252
250
|
return str(value)
|
|
@@ -324,4 +322,4 @@ class CustomValidator(Validator):
|
|
|
324
322
|
|
|
325
323
|
parent = get_parent()
|
|
326
324
|
if parent["action"] == COVER:
|
|
327
|
-
return
|
|
325
|
+
return TOGGLE
|
boneio/input/gpio.py
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"""GPIOInputButton to receive signals."""
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
import logging
|
|
3
|
-
|
|
4
|
+
import asyncio
|
|
5
|
+
from datetime import timedelta
|
|
4
6
|
from functools import partial
|
|
7
|
+
from boneio.const import DOUBLE, LONG, SINGLE, ClickTypes
|
|
8
|
+
from boneio.helper import GpioBaseClass, ClickTimer
|
|
5
9
|
|
|
6
|
-
from boneio.const import DOUBLE, LONG, SINGLE
|
|
7
|
-
from boneio.helper import GpioBaseClass, edge_detect
|
|
8
10
|
|
|
9
11
|
# TIMINGS FOR BUTTONS
|
|
12
|
+
|
|
10
13
|
DEBOUNCE_DURATION = timedelta(microseconds=150000)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
SECOND_DELAY_DURATION = 0.14
|
|
14
|
+
DOUBLE_CLICK_DURATION_MS = 350
|
|
15
|
+
LONG_PRESS_DURATION_MS = 700
|
|
14
16
|
|
|
15
17
|
_LOGGER = logging.getLogger(__name__)
|
|
16
18
|
|
|
@@ -21,103 +23,53 @@ class GpioInputButton(GpioBaseClass):
|
|
|
21
23
|
def __init__(self, **kwargs) -> None:
|
|
22
24
|
"""Setup GPIO Input Button"""
|
|
23
25
|
super().__init__(**kwargs)
|
|
24
|
-
|
|
25
|
-
self._pin,
|
|
26
|
-
callback=self._handle_press,
|
|
27
|
-
bounce=self._bounce_time.total_milliseconds,
|
|
28
|
-
)
|
|
29
|
-
self._first_press_timestamp = None
|
|
30
|
-
self._is_long_press = False
|
|
31
|
-
self._second_press_timestamp = None
|
|
32
|
-
self._second_check = False
|
|
26
|
+
self._state = self.is_pressed
|
|
33
27
|
_LOGGER.debug("Configured listening for input pin %s", self._pin)
|
|
28
|
+
self._timer_double = ClickTimer(
|
|
29
|
+
delay=DOUBLE_CLICK_DURATION_MS,
|
|
30
|
+
action=lambda x: self.double_click_press_callback(),
|
|
31
|
+
)
|
|
32
|
+
self._timer_long = ClickTimer(
|
|
33
|
+
delay=LONG_PRESS_DURATION_MS,
|
|
34
|
+
action=lambda x: self.press_callback(click_type=LONG),
|
|
35
|
+
)
|
|
36
|
+
self._double_click_ran = False
|
|
37
|
+
self._is_waiting_for_second_click = False
|
|
38
|
+
self._long_press_ran = False
|
|
39
|
+
asyncio.create_task(self._run())
|
|
34
40
|
|
|
35
|
-
def
|
|
36
|
-
"""Handle the button press callback"""
|
|
37
|
-
# Ignore if we are in a long press
|
|
38
|
-
if self._is_long_press:
|
|
39
|
-
return
|
|
40
|
-
now = datetime.now()
|
|
41
|
-
|
|
42
|
-
# Debounce button
|
|
43
|
-
if (
|
|
44
|
-
self._first_press_timestamp is not None
|
|
45
|
-
and now - self._first_press_timestamp < DEBOUNCE_DURATION
|
|
46
|
-
):
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
# Second click debounce. Just in case.
|
|
50
|
-
if (
|
|
51
|
-
self._second_press_timestamp is not None
|
|
52
|
-
and now - self._second_press_timestamp < DEBOUNCE_DURATION
|
|
53
|
-
):
|
|
54
|
-
return
|
|
55
|
-
if not self._first_press_timestamp:
|
|
56
|
-
self._first_press_timestamp = now
|
|
57
|
-
elif not self._second_press_timestamp:
|
|
58
|
-
self._second_press_timestamp = now
|
|
59
|
-
|
|
41
|
+
def press_callback(self, click_type: ClickTypes):
|
|
60
42
|
self._loop.call_soon_threadsafe(
|
|
61
|
-
self.
|
|
62
|
-
DELAY_DURATION,
|
|
63
|
-
self.check_press_length,
|
|
43
|
+
partial(self._press_callback, click_type, self._pin)
|
|
64
44
|
)
|
|
65
45
|
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# Schedule a new check
|
|
71
|
-
self._loop.call_soon_threadsafe(
|
|
72
|
-
self._loop.call_later,
|
|
73
|
-
DELAY_DURATION,
|
|
74
|
-
self.check_press_length,
|
|
75
|
-
)
|
|
46
|
+
def double_click_press_callback(self):
|
|
47
|
+
self._is_waiting_for_second_click = False
|
|
48
|
+
if not self._state and not self._timer_long.is_waiting():
|
|
49
|
+
self.press_callback(click_type=SINGLE)
|
|
76
50
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
51
|
+
async def _run(self) -> None:
|
|
52
|
+
while True:
|
|
53
|
+
self.check_state(state=self.is_pressed)
|
|
54
|
+
await asyncio.sleep(self._bounce_time.total_in_seconds)
|
|
80
55
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if not self._is_long_press and diff > LONG_PRESS_DURATION:
|
|
84
|
-
self._is_long_press = True
|
|
85
|
-
_LOGGER.debug("Long button press on pin %s, call callback", self._pin)
|
|
86
|
-
self._loop.call_soon_threadsafe(
|
|
87
|
-
partial(self._press_callback, LONG, self._pin)
|
|
88
|
-
)
|
|
56
|
+
def check_state(self, state):
|
|
57
|
+
if state == self._state:
|
|
89
58
|
return
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if
|
|
94
|
-
|
|
95
|
-
self.
|
|
96
|
-
self.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if self.
|
|
103
|
-
if self.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self._second_press_timestamp - self._first_press_timestamp,
|
|
108
|
-
)
|
|
109
|
-
self._loop.call_soon_threadsafe(
|
|
110
|
-
partial(self._press_callback, DOUBLE, self._pin)
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
elif self._first_press_timestamp:
|
|
114
|
-
_LOGGER.debug("One click event on pin %s, call callback", self._pin)
|
|
115
|
-
self._loop.call_soon_threadsafe(
|
|
116
|
-
partial(self._press_callback, SINGLE, self._pin)
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# Clean state on button released
|
|
120
|
-
self._first_press_timestamp = None
|
|
121
|
-
self._second_press_timestamp = None
|
|
122
|
-
self._second_check = False
|
|
123
|
-
self._is_long_press = False
|
|
59
|
+
self._state = state
|
|
60
|
+
if state:
|
|
61
|
+
self._timer_long.start_timer()
|
|
62
|
+
if self._timer_double.is_waiting():
|
|
63
|
+
self._timer_double.reset()
|
|
64
|
+
self._double_click_ran = True
|
|
65
|
+
self.press_callback(click_type=DOUBLE)
|
|
66
|
+
else:
|
|
67
|
+
self._timer_double.start_timer()
|
|
68
|
+
self._is_waiting_for_second_click = True
|
|
69
|
+
|
|
70
|
+
else:
|
|
71
|
+
if not self._is_waiting_for_second_click and not self._double_click_ran:
|
|
72
|
+
if self._timer_long.is_waiting():
|
|
73
|
+
self.press_callback(click_type=SINGLE)
|
|
74
|
+
self._timer_long.reset()
|
|
75
|
+
self._double_click_ran = False
|
boneio/manager.py
CHANGED
|
@@ -442,6 +442,8 @@ class Manager:
|
|
|
442
442
|
action = relay_actions.get(action_definition["action_output"])
|
|
443
443
|
if relay and action:
|
|
444
444
|
getattr(relay, action)()
|
|
445
|
+
else:
|
|
446
|
+
_LOGGER.warn("PIN %s for action not found", device)
|
|
445
447
|
elif action_definition[ACTION] == MQTT:
|
|
446
448
|
action_topic = action_definition.get(TOPIC)
|
|
447
449
|
action_payload = action_definition.get("action_mqtt_msg")
|
boneio/schema/actions.yaml
CHANGED
|
@@ -23,6 +23,8 @@ schema:
|
|
|
23
23
|
default_setter: toggle_cover
|
|
24
24
|
dependencies:
|
|
25
25
|
action: ['cover']
|
|
26
|
+
coerce:
|
|
27
|
+
- actions_output
|
|
26
28
|
meta:
|
|
27
29
|
label: If cover action chosen then what action to perform.
|
|
28
30
|
action_output:
|
|
@@ -32,7 +34,6 @@ schema:
|
|
|
32
34
|
dependencies:
|
|
33
35
|
action: ['output']
|
|
34
36
|
coerce:
|
|
35
|
-
- lower
|
|
36
37
|
- actions_output
|
|
37
38
|
meta:
|
|
38
39
|
label: If output action chosen then what action to perform.
|
boneio/sensor/temp/dallas.py
CHANGED
|
@@ -5,7 +5,7 @@ import logging
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
7
|
from adafruit_ds18x20 import DS18X20
|
|
8
|
-
from w1thermsensor import SensorNotReadyError
|
|
8
|
+
from w1thermsensor import SensorNotReadyError, NoSensorFoundError
|
|
9
9
|
|
|
10
10
|
from boneio.const import SENSOR, STATE, TEMPERATURE
|
|
11
11
|
from boneio.helper import AsyncUpdater, BasicMqtt
|
|
@@ -74,3 +74,5 @@ class DallasSensorW1(TempSensor, AsyncUpdater):
|
|
|
74
74
|
)
|
|
75
75
|
except SensorNotReadyError as err:
|
|
76
76
|
_LOGGER.error("Sensor not ready, can't update %s", err)
|
|
77
|
+
except NoSensorFoundError as err:
|
|
78
|
+
_LOGGER.error("Sensor not found, can't update %s", err)
|
boneio/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# flake8: noqa
|
|
2
|
-
__version__ = "0.6.
|
|
2
|
+
__version__ = "0.6.0dev4"
|
|
File without changes
|
|
File without changes
|