boneIO 0.6.0dev3__py3-none-any.whl → 0.6.0dev5__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,26 +1,26 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneIO
3
- Version: 0.6.0dev3
3
+ Version: 0.6.0dev5
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>
7
7
  Requires-Python: >=3.7
8
8
  Requires-Dist: Adafruit-BBIO>=1.2.0
9
- Requires-Dist: Adafruit-Blinka>=8.0.2
9
+ Requires-Dist: Adafruit-Blinka>=8.19.0
10
10
  Requires-Dist: Cerberus>=1.3.4
11
11
  Requires-Dist: PyYAML>=6.0
12
- Requires-Dist: adafruit-circuitpython-ds18x20>=1.3.12
13
- Requires-Dist: adafruit-circuitpython-mcp230xx>=2.5.5
14
- Requires-Dist: adafruit-circuitpython-mcp9808>=3.3.14
15
- Requires-Dist: adafruit-circuitpython-onewire>=2.0.1
16
- Requires-Dist: adafruit-circuitpython-pca9685>=3.4.6
17
- Requires-Dist: adafruit-circuitpython-pct2075>=1.1.14
18
- Requires-Dist: asyncio-mqtt>=0.12.1
19
- Requires-Dist: colorlog>=6.6.0
20
- Requires-Dist: gpio>=0.3.0
21
- Requires-Dist: luma.core>=2.3.1
22
- Requires-Dist: luma.oled>=3.8.1
23
- Requires-Dist: psutil>=5.9.1
12
+ Requires-Dist: adafruit-circuitpython-ds18x20>=1.3.16
13
+ Requires-Dist: adafruit-circuitpython-mcp230xx>=2.5.9
14
+ Requires-Dist: adafruit-circuitpython-mcp9808>=3.3.19
15
+ Requires-Dist: adafruit-circuitpython-onewire>=2.0.4
16
+ Requires-Dist: adafruit-circuitpython-pca9685>=3.4.8
17
+ Requires-Dist: adafruit-circuitpython-pct2075>=1.1.18
18
+ Requires-Dist: asyncio-mqtt>=0.16.1
19
+ Requires-Dist: colorlog>=6.7.0
20
+ Requires-Dist: gpio>=1.0.0
21
+ Requires-Dist: luma-core>=2.4.0
22
+ Requires-Dist: luma-oled>=3.12.0
23
+ Requires-Dist: psutil>=5.9.5
24
24
  Requires-Dist: pymodbus>=2.5.3
25
25
  Requires-Dist: pyserial-asyncio>=0.6
26
26
  Requires-Dist: w1thermsensor[async]>=2.0.0
@@ -1,6 +1,6 @@
1
1
  boneio/__init__.py,sha256=hoLKnu6h1uEsiCHA9Ql2MMDC7VQS0E-s_2cxBS-CTOg,147
2
- boneio/bonecli.py,sha256=Wg3Wc2xZ9FjF_23PK6Ja3YzXUkYanzYyQ_QdtQbKESw,3155
3
- boneio/const.py,sha256=9_bmHoetk6TE53KHBXjHRSBbD4gOqaUM_z8PYR1Qx2o,2908
2
+ boneio/bonecli.py,sha256=VhY1BMt6OaZz-752UjhEexdn8fDJkJaDWcGQNhCmgN0,3341
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,17 +11,18 @@ 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/config.py,sha256=XeHG7OSMCMmEL43rCbWy6Ij0RcTNlrIpevWZ0UJyrlo,1311
17
- boneio/helper/events.py,sha256=63FEM5bKIDmMHncJG0NLcVHJZ7gIZBEb0TP7xtfyKvs,5579
18
- boneio/helper/exceptions.py,sha256=Tll3ZZPOo0JZskN67hkoAxxGJ4I5ZY4IjeXtKyveziI,637
16
+ boneio/helper/click_timer.py,sha256=blWofzFIwuYcF_yFfCGDtI8nGSMpSdXdl9qMLXlKdXc,1169
17
+ boneio/helper/config.py,sha256=hhM4KUNaAFVXgQ1ZX56Zu7XV0pjp636vrcBuwoTH18g,2233
18
+ boneio/helper/events.py,sha256=EHYJy507RF1LikWQ2s4r990JRvR9rO4z7FkaJqt1Mrk,7494
19
+ boneio/helper/exceptions.py,sha256=vyYSUojwB7OttOPUjbxeHFM7C_o5ZQmRUcZ_vYpxYYI,717
19
20
  boneio/helper/filter.py,sha256=UcjifjaC5wHDW2He7wmwCX2IjSSeLVhXyhrXHeT8RmA,885
20
- boneio/helper/gpio.py,sha256=Z-P76CcvFL7msoSopXooaTUi3Lx0WQYeWoRXeO64K7Y,2710
21
- boneio/helper/ha_discovery.py,sha256=e2xjArXixpbVru3oD_8L8UKMgEkpbL5OV2ybZaNi-f0,6129
22
- boneio/helper/loader.py,sha256=8lWjNVLcV-uqIGGgD7bY3lGEK9dhEDB0wQppxFb_Vys,13488
21
+ boneio/helper/gpio.py,sha256=v4QrJfwlhIOqRCcD1SCpwPVcY6zsTlm1tens0eLbazM,2718
22
+ boneio/helper/ha_discovery.py,sha256=s80gwx1Fik2_vtq-6kqabUqPx4KwwZUt4G1Oy6RgGgU,6278
23
+ boneio/helper/loader.py,sha256=dKlk42tI7RkyI_FmX6CneN3FIGnHQ55c20sfn11B_bk,13547
23
24
  boneio/helper/logger.py,sha256=zyF_Vk3o2eSHuXypJhNzK99eZgkWDWybuB5KcJgurDs,1801
24
- boneio/helper/mqtt.py,sha256=Aqf6Sx4-3GQsK5GjgJ5QxVMyCTdRcL5Zq_GTIDu7ne0,759
25
+ boneio/helper/mqtt.py,sha256=UVa4KaxvVif6By_sVMdSMiYI_doZjiXF4LS9RFltxJk,765
25
26
  boneio/helper/oled.py,sha256=f0XYbaFstUbJ6ISmFe1vQCnmNVMctQWtnStNdROrblc,351
26
27
  boneio/helper/onewire/W1ThermSensor.py,sha256=Pu5Fp29pKbxjJqDbFs05Mjg3Vy-9z_DTVoBpSWM_byA,2430
27
28
  boneio/helper/onewire/__init__.py,sha256=4djH-uxiq5XhAiFTOxyqjvWVoJe0c8U8iN0BfmH8nSU,448
@@ -32,31 +33,31 @@ 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=7teo2fDyDUarorCn9REF5sGFMIimRrWaKOqildYG8_Y,2597
39
+ boneio/manager.py,sha256=cs2vy-26kvQROWHjHopACY2U1OLufcsu522RjShVXyQ,21023
39
40
  boneio/modbus.py,sha256=eA_sGnmdcIneXX75ZcXOI223-UkKN1UYmWFqiJBAhJo,4176
40
- boneio/mqtt_client.py,sha256=ioOBEmnbjpZjYrD5u8W5CrVsrNFRHDJ93fyk6XcWkeE,6983
41
+ boneio/mqtt_client.py,sha256=NYvok8y_g8iRXDopVojzcDGVnDJEFqHBEYhOGy8m7T8,8331
41
42
  boneio/oled.py,sha256=d_ofDQHc7zr3j0qOR0B_L3C8TJhvRH85nnb9Le-88nk,5244
42
43
  boneio/relay/__init__.py,sha256=iLEUL8kxnEndCQtgDIJfHqUZOfyWfWmuOrqSYAUxb2w,181
43
- boneio/relay/basic.py,sha256=zOXf84yTGeArk3ghXt_WI2ul8L0RxyziOTD6U7-nCLM,2629
44
+ boneio/relay/basic.py,sha256=QEWG8HodBqEqLpQxcQm29hdPIxO7c6ep0uDgfo3pcco,2623
44
45
  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
- boneio/runner.py,sha256=geT_ps_vo1SLoBszmhtcpkzk_LwWpG8OZYgUcQg3nKU,2287
48
- boneio/schema/actions.yaml,sha256=0QJlzZGVj4yyv1LMr1p7mc2oy58XscCPahuwcPTs8P8,1009
49
- boneio/schema/actions_sensor.yaml,sha256=LhXEsYsg6qs7iHqgQE6n-2jj-o-ZZRusDW_9nWIiZAY,129
50
- boneio/schema/actions_switch.yaml,sha256=qyooX0izkgl4wBEh8xUsYFEKMrvhbIAQYxOGTB5AROY,124
48
+ boneio/runner.py,sha256=eLRd3NtE8c5fqYu76B4Kz7vs5ftNDSZ_L-KHbipRu90,2569
49
+ boneio/schema/actions.yaml,sha256=WD0LR9SxVPgwU12x10RvFaTeyDiCjdRiicfkrCGLNvc,1030
50
+ boneio/schema/actions_sensor.yaml,sha256=U_VfdjqdorQZHYD6dZOzhlRKnOGwsnTJ3CDGiqrKxW8,124
51
+ boneio/schema/actions_switch.yaml,sha256=sdqhwz0LrcfaiAN3-RfAR_xApxo5dh9RxXQubuKcsjk,129
51
52
  boneio/schema/filters.yaml,sha256=WopX1SmCZsSZXNiGccLoi7uMCsUpdbs0eVfsAjmbay4,286
52
53
  boneio/schema/filters_adc.yaml,sha256=3e0ts92MoFKOnfGOOn6WYIHxu0-tnZe9OjAjN9m7hiI,304
53
54
  boneio/schema/id.yaml,sha256=vHI_6dxkJwoiGp5ien_pPpyaWA1F06eirTgfWMyWa1E,75
54
- boneio/schema/schema.yaml,sha256=CbwRtUW1cn8H-q_FQSVoXyTsPYFKOrzxA5hW-JeXTK4,12551
55
+ boneio/schema/schema.yaml,sha256=GHqcUaCUJypX2JD7tXVKoIZ3XO4rqLaoHW0ppWFWvzU,12988
55
56
  boneio/schema/temp_unit.yaml,sha256=m32VGz9RTW92Lz08l9n6RftkcVNZquOGPPr5mc3eZVc,65
56
57
  boneio/schema/update_interval.yaml,sha256=L_YLddAZdybcdO-T57Qhlv1GaWIVDwhvH-GadD1oOIo,133
57
58
  boneio/sensor/__init__.py,sha256=VjFBEQQv_U0T2ENkzefuBdzmqNvBTEv4M-gQKScc8o0,431
58
59
  boneio/sensor/adc.py,sha256=Yf5F8JcZJt0K4ijpPqI8do0BqDfLvfja_LE8_Zu3u7U,1281
59
- boneio/sensor/gpio.py,sha256=a4rn4cALZBPqqU-nlpzOjpPd8MjEAnxBTCS6pdJ0tpA,1289
60
+ boneio/sensor/gpio.py,sha256=oAUYHGLX0_JK6AJMplmDBnLBIAZ2GaDJ7ts8AceljvQ,1303
60
61
  boneio/sensor/modbus/__init__.py,sha256=LEOnMqBACNxZmCN2adZtTsq76gPbsNba5JewMiUENBw,8500
61
62
  boneio/sensor/modbus/dts1964_3f.json,sha256=WABph_2X4OgMidSM28vw4dLd9ZByRoiUP-RqE0UMpR8,8810
62
63
  boneio/sensor/modbus/pt100.json,sha256=bzKNYDc3lMto94Ut8gutVIsHytQiMobwFCkonOiMegs,526
@@ -68,9 +69,9 @@ boneio/sensor/temp/__init__.py,sha256=h5rGbkC8K6y2GJSNHtm9f8EmoBS3wFlSNIFjcrRj47
68
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=Pf1BYcBNZGiAiMtBcSQCwVAKFQ93thbCD_3Y8PGqCfg,41
72
- boneIO-0.6.0.dev3.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
73
- boneIO-0.6.0.dev3.dist-info/WHEEL,sha256=JtIceljpZF_3FlF7JEESqvYUELdenaIGNR7wSL2mRl0,87
74
- boneIO-0.6.0.dev3.dist-info/METADATA,sha256=zQ-akniwDSx5dVr6bdL2ebQd-v0Xtqn8nHWnGb5S-NQ,1696
75
- boneIO-0.6.0.dev3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
76
- boneIO-0.6.0.dev3.dist-info/RECORD,,
72
+ boneio/version.py,sha256=MRoHBbiT0xKVNIGf8uc_weaaaOMvuoXa9HcssIlg3_0,41
73
+ boneIO-0.6.0.dev5.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
74
+ boneIO-0.6.0.dev5.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
75
+ boneIO-0.6.0.dev5.dist-info/METADATA,sha256=b5xgbS9_foPU_jVQq9CPRUDE1XV9Ceq_LlI0e6KBz9U,1698
76
+ boneIO-0.6.0.dev5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
77
+ boneIO-0.6.0.dev5.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: pdm-pep517 1.1.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
boneio/bonecli.py CHANGED
@@ -1,9 +1,11 @@
1
1
  """Bonecli script."""
2
+ from __future__ import annotations
2
3
  import argparse
3
4
  import asyncio
4
5
  import logging
5
6
  import sys
6
7
  import os
8
+ from typing import Any
7
9
 
8
10
  os.environ["W1THERMSENSOR_NO_KERNEL_MODULE"] = "1"
9
11
 
@@ -12,7 +14,7 @@ from yaml import MarkedYAMLError
12
14
 
13
15
  from boneio.const import ACTION
14
16
  from boneio.helper import load_config_from_file
15
- from boneio.helper.exceptions import ConfigurationException
17
+ from boneio.helper.exceptions import ConfigurationException, RestartRequestException
16
18
  from boneio.helper.logger import configure_logger
17
19
  from boneio.runner import async_run
18
20
  from boneio.version import __version__
@@ -69,7 +71,7 @@ def get_arguments() -> argparse.Namespace:
69
71
  return arguments
70
72
 
71
73
 
72
- def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = ""):
74
+ def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = "") -> int:
73
75
  """Run BoneIO."""
74
76
  _LOGGER.info("BoneIO %s starting.", __version__)
75
77
  try:
@@ -78,7 +80,7 @@ def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = "")
78
80
  _LOGGER.error("Config not loaded. Exiting.")
79
81
  return 1
80
82
  configure_logger(log_config=_config.get("logger"), debug=debug)
81
- return asyncio.run(
83
+ asyncio.run(
82
84
  async_run(
83
85
  config=_config,
84
86
  config_file=config,
@@ -86,6 +88,10 @@ def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = "")
86
88
  mqttpassword=mqttpassword,
87
89
  ),
88
90
  )
91
+ return 0
92
+ except RestartRequestException as err:
93
+ _LOGGER.info(err)
94
+ return 0
89
95
  except (ConfigurationException, MarkedYAMLError) as err:
90
96
  _LOGGER.error("Failed to load config. %s Exiting.", err)
91
97
  return 1
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/config.py CHANGED
@@ -1,9 +1,9 @@
1
1
  """
2
2
  Module to provide basic config options.
3
3
  """
4
+ from __future__ import annotations
4
5
  from _collections_abc import dict_values
5
-
6
- from boneio.const import BONEIO, HOMEASSISTANT
6
+ from boneio.const import BONEIO, HOMEASSISTANT, LIGHT, SENSOR, COVER, BUTTON, SWITCH, BINARY_SENSOR
7
7
 
8
8
 
9
9
  class ConfigHelper:
@@ -16,7 +16,16 @@ class ConfigHelper:
16
16
  self._topic_prefix = topic_prefix
17
17
  self._ha_discovery = ha_discovery
18
18
  self._ha_discovery_prefix = ha_discovery_prefix
19
- self._autodiscovery_messages = {}
19
+ self._fetch_old_discovery = None
20
+ self._autodiscovery_messages = {
21
+ SWITCH: {},
22
+ LIGHT: {},
23
+ BINARY_SENSOR: {},
24
+ SENSOR: {},
25
+ COVER: {},
26
+ BUTTON: {}
27
+ }
28
+ self.manager_ready: bool = False
20
29
 
21
30
  @property
22
31
  def topic_prefix(self) -> str:
@@ -38,11 +47,28 @@ class ConfigHelper:
38
47
  def subscribe_topic(self) -> str:
39
48
  return f"{self.cmd_topic_prefix}+/+/#"
40
49
 
41
- def add_autodiscovery_msg(self, topic: str, payload: str):
50
+ def add_autodiscovery_msg(self, ha_type: str, topic: str, payload: str):
42
51
  """Add autodiscovery message."""
43
- self._autodiscovery_messages[topic] = {"topic": topic, "payload": payload}
52
+ self._autodiscovery_messages[ha_type][topic] = {"topic": topic, "payload": payload}
53
+
54
+ @property
55
+ def ha_types(self) -> list[str]:
56
+ return list(self._autodiscovery_messages.keys())
57
+
58
+ def is_topic_in_autodiscovery(self, topic: str) -> bool:
59
+ topic_parts_raw = topic[len(f"{self._ha_discovery_prefix}/") :].split("/")
60
+ ha_type = topic_parts_raw[0]
61
+ if ha_type in self._autodiscovery_messages:
62
+ if topic in self._autodiscovery_messages[ha_type]:
63
+ return True
64
+ return False
65
+
66
+
44
67
 
45
68
  @property
46
69
  def autodiscovery_msgs(self) -> dict_values:
47
70
  """Get autodiscovery messages"""
48
- return self._autodiscovery_messages.values()
71
+ output = {}
72
+ for ha_type in self._autodiscovery_messages:
73
+ output.update(self._autodiscovery_messages[ha_type])
74
+ return output.values()
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
+ )
@@ -8,6 +8,7 @@ class BoneIOException(Exception):
8
8
  class GPIOInputException(BoneIOException):
9
9
  """GPIOInput Exception."""
10
10
 
11
+
11
12
  class GPIOOutputException(BoneIOException):
12
13
  """GPIOInput Exception."""
13
14
 
@@ -30,3 +31,7 @@ class CoverRelayException(BoneIOException):
30
31
 
31
32
  class ModbusUartException(BoneIOException):
32
33
  """Cover configuration exception."""
34
+
35
+
36
+ class RestartRequestException(BoneIOException):
37
+ """Restart exception."""
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)
@@ -51,6 +51,7 @@ def ha_light_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
51
51
  msg["state_value_template"] = "{{ value_json.state }}"
52
52
  return msg
53
53
 
54
+
54
55
  def ha_led_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
55
56
  """Create LED availability topic for HA."""
56
57
  msg = ha_availabilty_message(device_type=RELAY, topic=topic, id=id, **kwargs)
@@ -64,11 +65,14 @@ def ha_led_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
64
65
  msg["brightness_value_template"] = "{{ value_json.brightness }}"
65
66
  return msg
66
67
 
67
- def ha_button_availabilty_message(id: str, topic: str = "boneIO", **kwargs):
68
+
69
+ def ha_button_availabilty_message(
70
+ id: str, topic: str = "boneIO", payload_press: str = "reload", **kwargs
71
+ ):
68
72
  """Create BUTTON availability topic for HA."""
69
73
  msg = ha_availabilty_message(device_type="button", topic=topic, id=id, **kwargs)
70
74
  msg["command_topic"] = f"{topic}/cmd/button/{id}/set"
71
- msg["payload_press"] = "reload"
75
+ msg["payload_press"] = payload_press
72
76
  return msg
73
77
 
74
78
 
@@ -102,9 +106,11 @@ def ha_sensor_availabilty_message(unit_of_measurement: str = None, **kwargs):
102
106
  return msg
103
107
 
104
108
 
105
- def ha_binary_sensor_availabilty_message(id: str, name: str, topic: str = "boneIO"):
109
+ def ha_binary_sensor_availabilty_message(id: str, name: str, device_class: str, topic: str = "boneIO"):
106
110
  """Create availability topic for HA."""
111
+ kwargs = {"device_class": device_class} if device_class else {}
107
112
  return {
113
+ **kwargs,
108
114
  "availability": [{"topic": f"{topic}/{STATE}"}],
109
115
  "device": {
110
116
  "identifiers": [topic],
boneio/helper/loader.py CHANGED
@@ -354,6 +354,7 @@ def configure_input(
354
354
  id=pin,
355
355
  name=gpio.get(ID, pin),
356
356
  ha_type=getattr(input, "ha_type"),
357
+ device_class=gpio.get(DEVICE_CLASS, None),
357
358
  availability_msg_func=getattr(input, "availability_msg_f"),
358
359
  )
359
360
  return pin
boneio/helper/mqtt.py CHANGED
@@ -21,11 +21,11 @@ class BasicMqtt:
21
21
  self._send_topic = f"{topic_prefix}/{topic_type}/{self.id}"
22
22
 
23
23
  @property
24
- def id(self) -> bool:
24
+ def id(self) -> str:
25
25
  """Id of the module."""
26
26
  return self._id
27
27
 
28
28
  @property
29
- def name(self):
29
+ def name(self) -> str:
30
30
  """Return name of the sensor."""
31
31
  return self._name
@@ -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