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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneIO
3
- Version: 0.6.0dev2
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.1
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=9_bmHoetk6TE53KHBXjHRSBbD4gOqaUM_z8PYR1Qx2o,2908
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=IRuXwAcbpV8jNJ_wuBF0rm5uFn9qP43naEmRiE8dRGs,1972
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=63FEM5bKIDmMHncJG0NLcVHJZ7gIZBEb0TP7xtfyKvs,5579
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=Z-P76CcvFL7msoSopXooaTUi3Lx0WQYeWoRXeO64K7Y,2710
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=3VL0KMh9mRZ2O-6iO8xoMx46IaQ8xV1AAFt2RRktKFM,11304
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=2WK3DR3kGAxHvmsNHZhN-oq8dF75oROxwm_mOZzYYh8,4391
38
- boneio/manager.py,sha256=vg4Kzxj8F_Kz2SujBPn2-OyGENPmSSLqrkdc3BUK_sU,20179
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=0QJlzZGVj4yyv1LMr1p7mc2oy58XscCPahuwcPTs8P8,1009
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=LqGjH5qCSOMZO7N4PmLRjvoZvtBWmXSUBdIIYzvhvMM,2355
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=n0K_D5qFEGdPK43G_weoquIzwPuwhNbYwDFFsFbj0js,41
72
- boneIO-0.6.0.dev2.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
73
- boneIO-0.6.0.dev2.dist-info/WHEEL,sha256=_LDBqpgIVFNHZvvFOGbg2pvJOENq6RHAyT5px-HeX0U,87
74
- boneIO-0.6.0.dev2.dist-info/METADATA,sha256=-vGHlXwsVkb7Bb2cWkcLJimskk3pt5QugjOMP8pBljY,1696
75
- boneIO-0.6.0.dev2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
76
- boneIO-0.6.0.dev2.dist-info/RECORD,,
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-pep517 1.0.6
2
+ Generator: pdm-pep517 1.1.3
3
3
  Root-Is-Purelib: True
4
4
  Tag: py3-none-any
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", "TOGGLE": "toggle"}
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(loop: asyncio.AbstractEventLoop, event_callback) -> None:
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 = (utc_point_in_time - now).total_seconds()
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 = utc_point_in_time.timestamp() - time.time()
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) -> None:
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)
@@ -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).lower()
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 "toggle"
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
- from datetime import datetime, timedelta
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
- LONG_PRESS_DURATION = timedelta(microseconds=700000)
12
- DELAY_DURATION = 0.08
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
- edge_detect(
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 _handle_press(self, pin: str) -> None:
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._loop.call_later,
62
- DELAY_DURATION,
63
- self.check_press_length,
43
+ partial(self._press_callback, click_type, self._pin)
64
44
  )
65
45
 
66
- def check_press_length(self) -> None:
67
- """Check if it's a single, double or long press"""
68
- # Check if button is still pressed
69
- if self.is_pressed:
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
- # Handle edge case due to multiple clicks
78
- if self._first_press_timestamp is None:
79
- return
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
- # Check if we reached a long press
82
- diff = datetime.now() - self._first_press_timestamp
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
- # Handle short press
92
- if not self._is_long_press:
93
- if not self._second_press_timestamp and not self._second_check:
94
- # let's try to check if second click will atempt
95
- self._second_check = True
96
- self._loop.call_soon_threadsafe(
97
- self._loop.call_later,
98
- SECOND_DELAY_DURATION,
99
- self.check_press_length,
100
- )
101
- return
102
- if self._second_check:
103
- if self._second_press_timestamp:
104
- _LOGGER.debug(
105
- "Double click event on pin %s, diff %s",
106
- self._pin,
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")
@@ -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.
@@ -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.0dev2"
2
+ __version__ = "0.6.0dev4"