boneIO 0.8.0.dev8__py3-none-any.whl → 0.8.0.dev10__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneIO
3
- Version: 0.8.0dev8
3
+ Version: 0.8.0dev10
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>
@@ -1,5 +1,5 @@
1
1
  boneio/__init__.py,sha256=hoLKnu6h1uEsiCHA9Ql2MMDC7VQS0E-s_2cxBS-CTOg,147
2
- boneio/bonecli.py,sha256=30NobXHwuCYeDm3jZWcZD99Fx1nj9F4Q_YsgBQL5vbA,8052
2
+ boneio/bonecli.py,sha256=CpqKJxIG8wQGE26r-wXU36aPbqWMtP3oOSQ3HdlJ7a4,9713
3
3
  boneio/const.py,sha256=bGvnwS28zFLSrbV3F2nkqV0hklCgcrQKpBys8PC75Ds,5087
4
4
  boneio/cover.py,sha256=EfO1DAOGTPQykfgJHzg1WqPs0U8b1AnD2NMI-sLZccM,8444
5
5
  boneio/example_config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -25,10 +25,10 @@ boneio/helper/click_timer.py,sha256=Gu8sEi1S8GG42SYbfaMju7WXFhnnil9gYfirLZX7kJk,
25
25
  boneio/helper/config.py,sha256=5cDnJ7usJDlUvXv8K2rSWEx30OFcU2k1U1vUEjO69WY,2431
26
26
  boneio/helper/events.py,sha256=ttb2_xOgyTXPIZv4ywJ2udCdqYLIVejBo7ATqsm7OQQ,8818
27
27
  boneio/helper/exceptions.py,sha256=vyYSUojwB7OttOPUjbxeHFM7C_o5ZQmRUcZ_vYpxYYI,717
28
- boneio/helper/filter.py,sha256=8jgSbHDaInEVlAPd7nrahnFYsi1y6C2fmI0yn55XzK0,935
29
- boneio/helper/gpio.py,sha256=q2r2uklPWePuuekPO63kVfoaQdkvNObUJ3ktwsHgOB0,4771
28
+ boneio/helper/filter.py,sha256=XwlaapfTTYXwcvJmKYJBksJD7i1u_xHIm_XrvyiuC6o,1005
29
+ boneio/helper/gpio.py,sha256=QAYusC51Yuxv0jQwYMa0107XdklvI43Mi1lTzKH7VyE,4923
30
30
  boneio/helper/ha_discovery.py,sha256=B2t1cfOfKWys4EM1H7OxvOaYL8H_v18CTuHCEVP2w2c,7107
31
- boneio/helper/loader.py,sha256=3MVgTLp1NlYbQ0nCw-MfF1nSvcwb-VXGUbgXIdg84VM,17496
31
+ boneio/helper/loader.py,sha256=-kOCe0ooYfWJu0EIcn4lzWjNz_4RJkwMQ5XF1NyYfwQ,17563
32
32
  boneio/helper/logger.py,sha256=zyF_Vk3o2eSHuXypJhNzK99eZgkWDWybuB5KcJgurDs,1801
33
33
  boneio/helper/mqtt.py,sha256=1YgwO0RjkarN5qS5HS5rONf4H3_m3ak7tT_hHm-HeOQ,931
34
34
  boneio/helper/oled.py,sha256=f0XYbaFstUbJ6ISmFe1vQCnmNVMctQWtnStNdROrblc,351
@@ -40,7 +40,7 @@ boneio/helper/pcf8575.py,sha256=qeNYLqV5foDEQCyAz1WRQRi1CYYxtbPIha06Z5TyZVQ,311
40
40
  boneio/helper/queue.py,sha256=7fE7d344-BEW8sljN40wmqsbBr4kPLvz4ShBjkT04p8,1066
41
41
  boneio/helper/sensor/ina_219_smbus.py,sha256=eXp2epjUgsqaXamTSWSn3LMow5X_YxAxdREaWD7N3mk,6170
42
42
  boneio/helper/state_manager.py,sha256=6OeqJsLQPCyQhhmFlNxCd80cTYLnKb02L4AZ1ZFFVBE,2616
43
- boneio/helper/stats.py,sha256=oWxKC3EjuL2hzvLk4qBIN_KskoXIcELQOyOpR02J79w,7850
43
+ boneio/helper/stats.py,sha256=qVqX9AleMDN28Jh73avurovnuPyKF42hxvJA6QYlbUA,7897
44
44
  boneio/helper/timeperiod.py,sha256=xpg9oe30Z5WiLDQPq3EBKKScejOnN47NhcpeFvDd3bY,5806
45
45
  boneio/helper/util.py,sha256=DyppBTE2zTWoxVpl83Kb4SpJLEqOOSEkxXEITCrwnfk,938
46
46
  boneio/helper/yaml_util.py,sha256=aaXMwXC2JoDYkBMcZkkB8nic3QOyGOhxPTRxWvMf3G4,11334
@@ -49,17 +49,20 @@ boneio/input/gpio.py,sha256=3Eh_3ko0RkTKqq7pKlgTROJeaSYgt05NkfeGoWudqfY,2674
49
49
  boneio/input/gpio_new.py,sha256=gpPfDr39B8FVUyh9XHtLgVQr4glMGFBgQsyIMzXDPaw,2822
50
50
  boneio/manager.py,sha256=leMDXrmyHmlndgt_GdlkvKnFRaUDZI8uDzCr8yLvcY8,29869
51
51
  boneio/modbus/__init__.py,sha256=yeHIxZ0_u7eCL7CqScvob5Utcru6Iza0LEtTagEtNtw,116
52
- boneio/modbus/client.py,sha256=-TMFQPVWWTlzS1HG1QVX4QwpfwSIxf0cgFOv3_gu7so,5851
53
- boneio/modbus/cwt.json,sha256=JwkQuRZFA03C3o9RgryMuCaYoCwM4RkiakEB6dkKgxE,886
52
+ boneio/modbus/client.py,sha256=M8ylJ7t6YvUnuHffK57VYZjHzx7kwUiiKXC4J64I51s,6174
53
+ boneio/modbus/cwt.json,sha256=PCn9t5wQkNCD8AqwXSoJ3cEm50bKAX4FmPw6fWCvLrg,908
54
54
  boneio/modbus/dts1964_3f.json,sha256=WABph_2X4OgMidSM28vw4dLd9ZByRoiUP-RqE0UMpR8,8810
55
- boneio/modbus/modbuscli.py,sha256=VJKI85HRD7Usi0x4pSMS9GzuhYfLCx8qVjNsHuao0Is,6231
56
- boneio/modbus/orno-or-we-517.json,sha256=w4kPFD8Wtr6Vv5BbGuvCiTHflo71FOxwp3fY8gZN2pQ,842
55
+ boneio/modbus/liquid-sensor.json,sha256=y00XpFFktm2a-ZrF_jujbqy2YAjHYBCBV_Avzlqih4s,737
56
+ boneio/modbus/modbuscli.py,sha256=wvj1QKDSIoXg9_zpoMqRD43CEYLLt6fBkQ0g-IRhs8w,8498
57
+ boneio/modbus/orno-or-we-517.json,sha256=AmFZmsa0Q4gOOUh_7ye6L_U98z-oA4US9jYbsAmP12o,1070
57
58
  boneio/modbus/pt100.json,sha256=bzKNYDc3lMto94Ut8gutVIsHytQiMobwFCkonOiMegs,526
58
- boneio/modbus/r4dcb08.json,sha256=uoQ5EGiFVY_uhYlOWYyFLCXpWxgtEB4SRAAkgON9ii8,2550
59
+ boneio/modbus/r4dcb08.json,sha256=3SeAs_BYEoh12HOfQ-m7HB_UeFYrJLAGF6CV3hzalLo,2623
59
60
  boneio/modbus/sdm120.json,sha256=4sueFfSw7G6a77gdIUhbfJvE-MNVJFOeVbRvHDw5Rvk,4145
60
61
  boneio/modbus/sdm630.json,sha256=TUiuc060IpF64p_HSDvdxEQcwkWHWUpnd48_xaGU-_o,8255
61
- boneio/modbus/sensor.py,sha256=TZYMPzgrrNE2gYO9dYeEZ6bSBUvHmubNK3gc-ukVkm8,8429
62
- boneio/modbus/socomec_e23.json,sha256=Is51YelEd4d6SYmz4Gd_oKx4Qi3bp-VHsl9zxWOFI5s,2882
62
+ boneio/modbus/sensor.py,sha256=JmmG3CcfmKEheOQY0XasVEjygnwxvtD01JpwBGLgpdE,8957
63
+ boneio/modbus/sht20.json,sha256=KV7TAvYo3oIQPM65SKyJYEugo6D8Ubz34hg6AGMwq3Y,907
64
+ boneio/modbus/socomec_e03.json,sha256=4nuFHTAzKX-7LOfUDsCf3C-WaGQNqqmzX-HT4Ed0aiU,2878
65
+ boneio/modbus/socomec_e23.json,sha256=oQUFW7dWfps0o6FMixtH02jGe9bLf051cpFpRZNtaNU,4772
63
66
  boneio/modbus/sofar.json,sha256=A_YztQN_ctyItIm2LH1tfcs-pSyG18I530qleLd2tOw,5592
64
67
  boneio/modbus/utils.py,sha256=cG75mmKTGaw_qrCG_D1qw-jl9XybUXa03i1ap5oBxGE,1753
65
68
  boneio/mqtt_client.py,sha256=hzGT3IyftPHNrQXSKbWUXGYZBpP-VdRBkOrILkXDNHs,8665
@@ -70,28 +73,28 @@ boneio/relay/gpio.py,sha256=s64FBf6zlxciF57xJ6nrvy0t5Rie0uiXlwos0HL3RKM,1163
70
73
  boneio/relay/mcp.py,sha256=m1-AtmgFiIzy00uns3gGGCTwr-ppfAiN_zeIdZXVtQE,2000
71
74
  boneio/relay/pca.py,sha256=qiO5YWaywbtkbjVlqKi0y9VomsWuMHsfdQiGG6b_yug,2951
72
75
  boneio/relay/pcf.py,sha256=TU5yCqUVMFj_-W1rRqweRtCQWOu24Z6kFnBKGZHjptk,2498
73
- boneio/runner.py,sha256=PC1rbgsURBbtXe3xIX1zk0bDgSGNKwxTdgX1eq68vfc,2855
76
+ boneio/runner.py,sha256=Zsm4F5Hb3IBl-4aWpD5VvPSpg5tDAEnWF81j-_oFIMg,2855
74
77
  boneio/schema/actions.yaml,sha256=kaJZ9B6SOl4Wbujtnr5k-g5JcAi2NSC1oGc0wZy8fnQ,1039
75
78
  boneio/schema/actions_sensor.yaml,sha256=rWd8pfsN7KvmvVvW6VedelFayRVehNQt6x4ou6yN9BY,91
76
79
  boneio/schema/actions_switch.yaml,sha256=cDgSi12k4S-TWADQ20Fy9NvYKOXnm7YkyMaWpPyXVoc,96
77
80
  boneio/schema/filters.yaml,sha256=WopX1SmCZsSZXNiGccLoi7uMCsUpdbs0eVfsAjmbay4,286
78
81
  boneio/schema/filters_adc.yaml,sha256=3e0ts92MoFKOnfGOOn6WYIHxu0-tnZe9OjAjN9m7hiI,304
79
82
  boneio/schema/id.yaml,sha256=vHI_6dxkJwoiGp5ien_pPpyaWA1F06eirTgfWMyWa1E,75
80
- boneio/schema/schema.yaml,sha256=Chcsh1kHMxhE_cx-T3GWpfXWmSZANhzyNQa-Qw4PKoY,18658
83
+ boneio/schema/schema.yaml,sha256=j15G2tWUqb6jupuZDMJGKMzsNnpIqoiVaZ4jQ-UVi1Q,19166
81
84
  boneio/schema/temp_unit.yaml,sha256=m32VGz9RTW92Lz08l9n6RftkcVNZquOGPPr5mc3eZVc,65
82
85
  boneio/schema/update_interval.yaml,sha256=L_YLddAZdybcdO-T57Qhlv1GaWIVDwhvH-GadD1oOIo,133
83
86
  boneio/sensor/__init__.py,sha256=Ztj-xzey-SWrEdVEozcwFsZSuEmJW8STVaf_vPMWiVc,619
84
87
  boneio/sensor/adc.py,sha256=tCUdr3KN5uSbgXiwhNXbMjeNkO2CzPYhIOncHR5_LD0,1328
85
88
  boneio/sensor/gpio.py,sha256=8m07tW1xDsrhBM2dZ9_VvmvYRn-5hLQVTTUhPlKg1rg,1199
86
- boneio/sensor/gpio_new.py,sha256=m54agOF2gUh3aoC6f8WpCPAmBRADvqlKeWLqwlon9fg,1223
87
- boneio/sensor/ina219.py,sha256=mIvu-nIfpfrSi_sn7FBYS8n3y2AkGsXBO_OLAy3tQ48,3518
89
+ boneio/sensor/gpio_new.py,sha256=_9ai1P_ex-_DUaa2j_VrQSipcCFdlhG8FxY4SmCeGtU,1698
90
+ boneio/sensor/ina219.py,sha256=5oto2k9ThKTKWuGwOESlNPFB2c2keULm68OvU4vEJi0,3290
88
91
  boneio/sensor/temp/__init__.py,sha256=JLNH6Nc78ezleftnIYylIcNtKIm0rdqetbPZLsuCgDc,1844
89
92
  boneio/sensor/temp/dallas.py,sha256=xrvd1LNBh1fRcjz_yd_9S29Lv26ItVtLCmhZgVQWJos,2485
90
93
  boneio/sensor/temp/lm75.py,sha256=-mpOv78429plRPBp9s09Ljz1x2Bdxuagalqz40vlAKE,243
91
94
  boneio/sensor/temp/mcp9808.py,sha256=yAh5yJzZLGTqa39xV4fyqsruj7oy3niOZAUV2W6eyCM,271
92
- boneio/version.py,sha256=kohMs-Riwj-UAibQEHZq5p9eZISaEAIlNcuJ0QrkGFg,41
93
- boneIO-0.8.0.dev8.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
94
- boneIO-0.8.0.dev8.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
95
- boneIO-0.8.0.dev8.dist-info/METADATA,sha256=ooHB3DwTlfrhH1xux3m_XC-puIs6nVCLX00ZW7Gff0I,1801
96
- boneIO-0.8.0.dev8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
97
- boneIO-0.8.0.dev8.dist-info/RECORD,,
95
+ boneio/version.py,sha256=c8uyaJeQfqGrdwmR0AHXgRhne9emuj2DCS7KRQ-4wHQ,42
96
+ boneIO-0.8.0.dev10.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
97
+ boneIO-0.8.0.dev10.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
98
+ boneIO-0.8.0.dev10.dist-info/METADATA,sha256=o3N1aXTfUEr2WtDC9UB4D2khOOHAZWN2hijJb0oc7C0,1802
99
+ boneIO-0.8.0.dev10.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
100
+ boneIO-0.8.0.dev10.dist-info/RECORD,,
boneio/bonecli.py CHANGED
@@ -13,7 +13,11 @@ import sys
13
13
  from colorlog import ColoredFormatter
14
14
  from yaml import MarkedYAMLError
15
15
 
16
- from boneio.modbus.modbuscli import async_run_modbus_set, async_run_modbus_get
16
+ from boneio.modbus.modbuscli import (
17
+ async_run_modbus_set,
18
+ async_run_modbus_get,
19
+ async_run_modbus_search,
20
+ )
17
21
  from boneio.modbus.client import VALUE_TYPES
18
22
 
19
23
 
@@ -99,13 +103,14 @@ def get_arguments() -> argparse.Namespace:
99
103
  modbus_parser.add_argument(
100
104
  "--address",
101
105
  type=lambda x: int(x, 0),
102
- required=True,
106
+ required=False,
107
+ default=1,
103
108
  help="Current device address (hex or integer)",
104
109
  )
105
110
  modbus_parser.add_argument(
106
111
  "--baudrate",
107
112
  type=int,
108
- choices=[2400, 4800, 9600, 19200],
113
+ choices=[2400, 4800, 9600, 14400, 19200],
109
114
  required=True,
110
115
  help="Current baudrate",
111
116
  )
@@ -139,11 +144,21 @@ def get_arguments() -> argparse.Namespace:
139
144
  dest="modbus_action", required=True
140
145
  )
141
146
  set_modbus_parser = modbus_sub_parser.add_parser("set")
147
+ set_modbus_parser.add_argument(
148
+ "--custom-value",
149
+ type=int,
150
+ help="Set Custom value",
151
+ )
152
+ set_modbus_parser.add_argument(
153
+ "--custom-register-address",
154
+ type=int,
155
+ help="Register address for custom value",
156
+ )
142
157
  set_modbus_parser.add_argument(
143
158
  "--device",
144
159
  type=str,
145
- choices=["cwt", "r4dcb08"],
146
- help="Choose device to set modbus address/baudrate",
160
+ choices=["cwt", "r4dcb08", "liquid-sensor", "sht20", "custom"],
161
+ help="Choose device to set modbus address/baudrate. For custom you must provide --custom-value and --custom-register-address",
147
162
  required=True,
148
163
  )
149
164
  set_modbus_parser_group = set_modbus_parser.add_mutually_exclusive_group()
@@ -182,6 +197,23 @@ def get_arguments() -> argparse.Namespace:
182
197
  required=True,
183
198
  )
184
199
  parser.add_argument("--version", action="version", version=__version__)
200
+ search_modbus_parser = modbus_sub_parser.add_parser(
201
+ name="search",
202
+ help="Search for device. Iterate over every address 1-253 with provided register address",
203
+ )
204
+ search_modbus_parser.add_argument(
205
+ "--register-address",
206
+ type=int,
207
+ help="Register address",
208
+ required=True,
209
+ )
210
+ search_modbus_parser.add_argument(
211
+ "--register-type",
212
+ type=str,
213
+ choices=["input", "holding"],
214
+ help="Register type",
215
+ required=True,
216
+ )
185
217
  arguments = parser.parse_args()
186
218
 
187
219
  return arguments
@@ -223,6 +255,7 @@ def run_modbus_command(
223
255
  _LOGGER.info("BoneIO %s starting.", __version__)
224
256
  try:
225
257
  configure_logger(log_config={}, debug=args.debug)
258
+ ret = 0
226
259
  if args.modbus_action == "set":
227
260
  ret = asyncio.run(
228
261
  async_run_modbus_set(
@@ -235,9 +268,11 @@ def run_modbus_command(
235
268
  stopbits=args.stopbits,
236
269
  new_baudrate=args.new_baudrate,
237
270
  new_address=args.new_address,
271
+ custom_address=args.custom_register_address,
272
+ custom_value=args.custom_value,
238
273
  ),
239
274
  )
240
- else:
275
+ elif args.modbus_action == "get":
241
276
  ret = asyncio.run(
242
277
  async_run_modbus_get(
243
278
  uart=args.uart,
@@ -251,6 +286,18 @@ def run_modbus_command(
251
286
  value_type=args.value_type,
252
287
  ),
253
288
  )
289
+ else:
290
+ ret = asyncio.run(
291
+ async_run_modbus_search(
292
+ uart=args.uart,
293
+ baudrate=args.baudrate,
294
+ register_address=args.register_address,
295
+ register_type=args.register_type,
296
+ parity=args.parity,
297
+ bytesize=args.bytesize,
298
+ stopbits=args.stopbits,
299
+ ),
300
+ )
254
301
  return ret
255
302
  except (RestartRequestException, GracefulExit) as err:
256
303
  if err is not None:
@@ -281,7 +328,10 @@ def main() -> int:
281
328
  args=args,
282
329
  )
283
330
 
284
- _LOGGER.info("Exiting with exit code %s", exit_code)
331
+ if exit_code == 0:
332
+ _LOGGER.info("Exiting with exit code %s", exit_code)
333
+ else:
334
+ _LOGGER.error("Exiting with exit code %s", exit_code)
285
335
  return exit_code
286
336
 
287
337
 
boneio/helper/filter.py CHANGED
@@ -19,8 +19,9 @@ FILTERS = {
19
19
  class Filter:
20
20
  _filters = []
21
21
 
22
- def _apply_filters(self, value: float) -> float | None:
23
- for filter in self._filters:
22
+ def _apply_filters(self, value: float, filters: list = []) -> float | None:
23
+ filters = filters if filters else self._filters
24
+ for filter in filters:
24
25
  for k, v in filter.items():
25
26
  if k not in FILTERS:
26
27
  _LOGGER.warning(
boneio/helper/gpio.py CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
  import asyncio
3
3
  import logging
4
4
  from datetime import datetime
5
+
5
6
  try:
6
7
  from Adafruit_BBIO import GPIO
7
8
  except ModuleNotFoundError:
@@ -21,7 +22,14 @@ from typing import Callable, Awaitable, List
21
22
 
22
23
  from boneio.const import CONFIG_PIN, FALLING
23
24
  from boneio.const import GPIO as GPIO_STR
24
- from boneio.const import GPIO_MODE, LOW, ClickTypes, Gpio_Edges, Gpio_States, InputTypes
25
+ from boneio.const import (
26
+ GPIO_MODE,
27
+ LOW,
28
+ ClickTypes,
29
+ Gpio_Edges,
30
+ Gpio_States,
31
+ InputTypes,
32
+ )
25
33
  from boneio.helper.exceptions import GPIOInputException
26
34
  from boneio.helper.timeperiod import TimePeriod
27
35
  from concurrent.futures import ThreadPoolExecutor
@@ -79,7 +87,9 @@ def edge_detect(
79
87
  ) -> None:
80
88
  """Add detection for RISING and FALLING events."""
81
89
  try:
82
- GPIO.add_event_detect(gpio=pin, edge=edge, callback=callback, bouncetime=bounce)
90
+ GPIO.add_event_detect(
91
+ gpio=pin, edge=edge, callback=callback, bouncetime=bounce
92
+ )
83
93
  except RuntimeError as err:
84
94
  raise GPIOInputException(err)
85
95
 
@@ -107,7 +117,8 @@ class GpioBaseClass:
107
117
  self,
108
118
  pin: str,
109
119
  press_callback: Callable[
110
- [ClickTypes, str, List, InputTypes, bool, float | None], Awaitable[None]
120
+ [ClickTypes, str, List, InputTypes, bool, float | None],
121
+ Awaitable[None],
111
122
  ],
112
123
  name: str,
113
124
  actions: dict,
@@ -118,7 +129,9 @@ class GpioBaseClass:
118
129
  """Setup GPIO Input Button"""
119
130
  self._pin = pin
120
131
  gpio_mode = kwargs.get(GPIO_MODE, GPIO_STR)
121
- bounce_time: TimePeriod = kwargs.get("bounce_time", TimePeriod(milliseconds=50))
132
+ bounce_time: TimePeriod = kwargs.get(
133
+ "bounce_time", TimePeriod(milliseconds=50)
134
+ )
122
135
  self._bounce_time = bounce_time.total_in_seconds
123
136
  self._loop = asyncio.get_running_loop()
124
137
  self._press_callback = press_callback
@@ -129,14 +142,22 @@ class GpioBaseClass:
129
142
  self._input_type = input_type
130
143
  self._empty_message_after = empty_message_after
131
144
 
132
- def press_callback(self, click_type: ClickTypes, duration: float | None = None) -> None:
145
+ def press_callback(
146
+ self, click_type: ClickTypes, duration: float | None = None
147
+ ) -> None:
133
148
  actions = self._actions.get(click_type, [])
134
- self._loop.create_task(self.async_press_callback(click_type, duration, actions))
149
+ self._loop.create_task(
150
+ self.async_press_callback(click_type, duration, actions)
151
+ )
135
152
 
136
153
  async def async_press_callback(
137
- self, click_type: ClickTypes, duration: float | None = None, actions: List = []
154
+ self,
155
+ click_type: ClickTypes,
156
+ duration: float | None = None,
157
+ actions: List = [],
138
158
  ) -> None:
139
- _LOGGER.warn("press callback %s", datetime.now())
159
+
160
+ _LOGGER.warning("press callback %s", datetime.now())
140
161
  await self._press_callback(
141
162
  click_type,
142
163
  self._pin,
boneio/helper/loader.py CHANGED
@@ -211,6 +211,7 @@ def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
211
211
  update_interval=sensor.get(
212
212
  UPDATE_INTERVAL, TimePeriod(seconds=60)
213
213
  ),
214
+ sensors_filters=sensor.get("sensors_filters", {}),
214
215
  **kwargs,
215
216
  )
216
217
  except FileNotFoundError as err:
boneio/helper/stats.py CHANGED
@@ -233,13 +233,15 @@ class HostData:
233
233
  },
234
234
  }
235
235
  if ina219 is not None:
236
+
237
+ def get_ina_values():
238
+ return {
239
+ sensor.device_class: f"{sensor.state} {sensor.unit_of_measurement}"
240
+ for sensor in ina219.sensors.values()
241
+ }
242
+
236
243
  host_stats[INA219] = {
237
- "f": lambda: {
238
- *{
239
- sensor.device_class: sensor.state
240
- for sensor in ina219.sensors.values()
241
- }
242
- },
244
+ "f": get_ina_values,
243
245
  "update_interval": TimePeriod(seconds=60),
244
246
  }
245
247
  self._data = {}
boneio/modbus/client.py CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import logging
5
5
  import struct
6
+ import time
6
7
  from typing import Any
7
8
 
8
9
  from pymodbus.client.sync import BaseModbusClient, ModbusSerialClient
@@ -43,6 +44,7 @@ class Modbus:
43
44
  stopbits: int = 1,
44
45
  bytesize: int = 8,
45
46
  parity: str = "N",
47
+ timeout: float = 3,
46
48
  ) -> None:
47
49
  """Initialize the Modbus hub."""
48
50
  rx = uart.get(RX)
@@ -68,6 +70,7 @@ class Modbus:
68
70
  stopbits=stopbits,
69
71
  bytesize=bytesize,
70
72
  parity=parity,
73
+ timeout=timeout,
71
74
  )
72
75
  self._read_methods = {
73
76
  "input": self._client.read_input_registers,
@@ -129,6 +132,7 @@ class Modbus:
129
132
  ) -> ModbusResponse:
130
133
  """Call async pymodbus."""
131
134
  async with self._lock:
135
+ start_time = time.perf_counter()
132
136
  if not self._pymodbus_connect():
133
137
  _LOGGER.error("Can't connect to Modbus.")
134
138
  return None
@@ -151,6 +155,11 @@ class Modbus:
151
155
  if not hasattr(result, REGISTERS):
152
156
  _LOGGER.error(str(result))
153
157
  return None
158
+ end_time = time.perf_counter()
159
+ _LOGGER.debug(
160
+ "Time of execution of read_registers: %s ms.",
161
+ round((end_time - start_time) * 1000, 3),
162
+ )
154
163
  return result
155
164
 
156
165
  def decode_value(self, payload, value_type):
boneio/modbus/cwt.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "set_address_address": 2000,
5
5
  "set_baudrate": {
6
6
  "address": 2001,
7
- "possible_baudrates": [2400, 4800, 9600, 19200]
7
+ "possible_baudrates": { "2400": 0, "4800": 1, "9600": 2, "19200": 3 }
8
8
  }
9
9
  },
10
10
  "registers_base": [
@@ -0,0 +1,37 @@
1
+ {
2
+ "model": "Liquid sensor",
3
+ "set_base": {
4
+ "set_address_address": 0,
5
+ "set_baudrate": {
6
+ "address": 1,
7
+ "possible_baudrates": {
8
+ "1200": 0,
9
+ "2400": 1,
10
+ "4800": 2,
11
+ "9600": 3,
12
+ "19200": 4,
13
+ "38400": 5,
14
+ "57600": 6,
15
+ "115200": 7
16
+ }
17
+ }
18
+ },
19
+ "registers_base": [
20
+ {
21
+ "base": 0,
22
+ "length": 2,
23
+ "register_type": "holding",
24
+ "registers": [
25
+ {
26
+ "name": "Immersion depth",
27
+ "address": 0,
28
+ "unit_of_measurement": "mm",
29
+ "state_class": "measurement",
30
+ "device_class": "humidity",
31
+ "value_type": "S_WORD",
32
+ "filters": [{ "multiply": 0.1 }]
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ }
@@ -78,7 +78,7 @@ class ModbusHelper:
78
78
 
79
79
  def set_connection_speed(self, new_baudrate: int) -> int:
80
80
  baudrate_model = self._model[SET_BAUDRATE]
81
- ind = baudrate_model["possible_baudrates"].index(new_baudrate)
81
+ ind = baudrate_model["possible_baudrates"].get(str(new_baudrate))
82
82
  if ind:
83
83
  result = self._modbus.client.write_register(
84
84
  address=baudrate_model["address"],
@@ -110,6 +110,19 @@ class ModbusHelper:
110
110
  else:
111
111
  _LOGGER.error("Invalid new address.")
112
112
 
113
+ def set_custom_command(self, register_address: int, value: int | float):
114
+ result = self._modbus.client.write_register(
115
+ address=register_address,
116
+ value=value,
117
+ unit=self._device_address,
118
+ )
119
+ if result.isError():
120
+ _LOGGER.error("Operation failed.")
121
+ else:
122
+ _LOGGER.info(
123
+ "Operation succeeded. Now restart device by disconnecting it."
124
+ )
125
+
113
126
 
114
127
  async def async_run_modbus_set(
115
128
  device: str,
@@ -118,6 +131,8 @@ async def async_run_modbus_set(
118
131
  baudrate: int,
119
132
  new_baudrate: int,
120
133
  new_address: int,
134
+ custom_address: int,
135
+ custom_value: int,
121
136
  stopbits: int = 1,
122
137
  bytesize: int = 8,
123
138
  parity: str = "N",
@@ -125,15 +140,21 @@ async def async_run_modbus_set(
125
140
  """Run Modbus Set Function."""
126
141
  if new_address and new_baudrate:
127
142
  _LOGGER.error("Can't set both methods new_address and new_baudrate.")
128
- _db = open_json(path=os.path.dirname(__file__), model=device)
129
- set_base = _db.get(SET_BASE, {})
130
- first_reg_base = _db.get(REGISTERS_BASE, [])[0]
131
- if not first_reg_base:
132
- return False
133
- first_record = first_reg_base.get(REGISTERS, [])[0]
134
- _LOGGER.debug(
135
- f"Connecting with params uart: {uart}, baudrate: {baudrate}, stopbits: {stopbits}, bytesize: {bytesize}, parity: {parity}."
136
- )
143
+ custom_cmd = True if device == "custom" else False
144
+ set_base = {}
145
+ if not custom_cmd:
146
+ _db = open_json(path=os.path.dirname(__file__), model=device)
147
+ set_base = _db.get(SET_BASE, {})
148
+ first_reg_base = _db.get(REGISTERS_BASE, [])[0]
149
+ if not first_reg_base:
150
+ return False
151
+ first_record = first_reg_base.get(REGISTERS, [])[0]
152
+ _LOGGER.debug(
153
+ f"Connecting with params uart: {uart}, baudrate: {baudrate}, stopbits: {stopbits}, bytesize: {bytesize}, parity: {parity}."
154
+ )
155
+ else:
156
+ first_record = {}
157
+ first_reg_base = {}
137
158
  modbus_helper = ModbusHelper(
138
159
  device=device,
139
160
  uart=uart,
@@ -146,17 +167,69 @@ async def async_run_modbus_set(
146
167
  bytesize=bytesize,
147
168
  parity=parity,
148
169
  )
149
- if not await modbus_helper.check_connection():
150
- _LOGGER.error("Can't connect with sensor. Exiting")
151
- return 1
152
- if new_baudrate:
153
- return modbus_helper.set_connection_speed(new_baudrate=new_baudrate)
154
- if new_address:
155
- modbus_helper.set_new_address(new_address=new_address)
156
- return 0
170
+
171
+ async def default_action():
172
+ if not await modbus_helper.check_connection():
173
+ _LOGGER.error("Can't connect with sensor. Exiting")
174
+ return 1
175
+ if new_baudrate:
176
+ return modbus_helper.set_connection_speed(new_baudrate=new_baudrate)
177
+ if new_address:
178
+ modbus_helper.set_new_address(new_address=new_address)
179
+ return 0
180
+
181
+ if not custom_cmd:
182
+ _LOGGER.debug("Invoking default action.")
183
+ return await default_action()
184
+ elif custom_address is not None and custom_value is not None:
185
+ _LOGGER.debug("Invoking custom command action.")
186
+ modbus_helper.set_custom_command(
187
+ register_address=custom_address, value=custom_value
188
+ )
157
189
  return 1
158
190
 
159
191
 
192
+ async def async_run_modbus_search(
193
+ uart: str,
194
+ baudrate: int,
195
+ register_address: int,
196
+ register_type: str = "holding",
197
+ stopbits: int = 1,
198
+ bytesize: int = 8,
199
+ parity: str = "N",
200
+ ):
201
+ """Run Modbus Seach Function."""
202
+ _modbus = Modbus(
203
+ uart=UARTS[uart],
204
+ baudrate=baudrate,
205
+ stopbits=stopbits,
206
+ bytesize=bytesize,
207
+ parity=parity,
208
+ timeout=0.1,
209
+ )
210
+ units_found = []
211
+ for unit_id in range(1, 248): # Modbus RTU address range is 1 to 247
212
+ _LOGGER.debug(f"Searching device at address {unit_id}.")
213
+ value = await _modbus.read_registers(
214
+ unit=unit_id,
215
+ address=register_address,
216
+ count=2,
217
+ method=register_type,
218
+ )
219
+ if value:
220
+ units_found.append(unit_id)
221
+ _LOGGER.info(f"Found device at address {unit_id}.")
222
+ else:
223
+ _LOGGER.debug(f"No device found at address {unit_id}.")
224
+ if units_found:
225
+ _LOGGER.info(
226
+ "Found devices: [%s]", ", ".join(str(x) for x in units_found)
227
+ )
228
+ else:
229
+ _LOGGER.info("No devices found.")
230
+ return 0
231
+
232
+
160
233
  async def async_run_modbus_get(
161
234
  uart: str,
162
235
  device_address: int,
@@ -29,6 +29,14 @@
29
29
  "state_class": "measurement",
30
30
  "device_class": "voltage",
31
31
  "value_type": "FP32"
32
+ },
33
+ {
34
+ "name": "Grid Frequency",
35
+ "address": 18,
36
+ "unit_of_measurement": "V",
37
+ "state_class": "measurement",
38
+ "device_class": "voltage",
39
+ "value_type": "FP32"
32
40
  }
33
41
  ]
34
42
  }
@@ -4,7 +4,13 @@
4
4
  "set_address_address": 254,
5
5
  "set_baudrate": {
6
6
  "address": 255,
7
- "possible_baudrates": [1200, 2400, 4800, 9600, 19200]
7
+ "possible_baudrates": {
8
+ "1200": 0,
9
+ "2400": 1,
10
+ "4800": 2,
11
+ "9600": 3,
12
+ "19200": 4
13
+ }
8
14
  }
9
15
  },
10
16
  "registers_base": [
boneio/modbus/sensor.py CHANGED
@@ -4,6 +4,8 @@ import logging
4
4
  import os
5
5
  from datetime import datetime
6
6
  from typing import Optional
7
+
8
+ from boneio.helper.filter import Filter
7
9
  from .utils import CONVERT_METHODS, REGISTERS_BASE, allowed_operations
8
10
  from boneio.const import (
9
11
  ADDRESS,
@@ -26,7 +28,7 @@ from boneio.helper.util import open_json
26
28
  _LOGGER = logging.getLogger(__name__)
27
29
 
28
30
 
29
- class ModbusSensor(BasicMqtt, AsyncUpdater):
31
+ class ModbusSensor(BasicMqtt, AsyncUpdater, Filter):
30
32
  """Represent Modbus sensor in BoneIO."""
31
33
 
32
34
  SensorClass = None
@@ -37,6 +39,7 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
37
39
  modbus: Modbus,
38
40
  address: str,
39
41
  model: str,
42
+ sensors_filters: dict,
40
43
  config_helper: ConfigHelper,
41
44
  event_bus: EventBus,
42
45
  id: str = DefaultName,
@@ -56,6 +59,9 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
56
59
  self._address = address
57
60
  self._discovery_sent = False
58
61
  self._payload_online = OFFLINE
62
+ self._sensors_filters = {
63
+ k.lower(): v for k, v in sensors_filters.items()
64
+ }
59
65
  event_bus.add_haonline_listener(target=self.set_payload_offline)
60
66
  AsyncUpdater.__init__(self, **kwargs)
61
67
 
@@ -154,7 +160,9 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
154
160
  method=data.get("register_type", "input"),
155
161
  )
156
162
  if self._payload_online == OFFLINE and values:
157
- _LOGGER.info("Sending online payload about device.")
163
+ _LOGGER.info(
164
+ "Sending online payload about device %s.", self._name
165
+ )
158
166
  self._payload_online = ONLINE
159
167
  self._send_message(
160
168
  topic=f"{self._config_helper.topic_prefix}/{self._id}{STATE}",
@@ -204,6 +212,12 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
204
212
  if key in allowed_operations:
205
213
  lamda_function = allowed_operations[key]
206
214
  decoded_value = lamda_function(decoded_value, value)
215
+ name = register.get("name").replace(" ", "")
216
+ user_filters = self._sensors_filters.get(name.lower(), [])
217
+ decoded_value = self._apply_filters(
218
+ value=decoded_value,
219
+ filters=user_filters,
220
+ )
207
221
  output[register.get("name").replace(" ", "")] = decoded_value
208
222
  self._send_message(
209
223
  topic=f"{self._send_topic}/{data[BASE]}",
@@ -0,0 +1,37 @@
1
+ {
2
+ "model": "SHT20 Temp and Humidity sensor",
3
+ "set_base": {
4
+ "set_address_address": 257,
5
+ "set_baudrate": {
6
+ "address": 258,
7
+ "possible_baudrates": { "9600": 9600, "14400": 14400, "19200": 19200 }
8
+ }
9
+ },
10
+ "registers_base": [
11
+ {
12
+ "base": 1,
13
+ "length": 2,
14
+ "register_type": "input",
15
+ "registers": [
16
+ {
17
+ "name": "Temperature",
18
+ "address": 1,
19
+ "unit_of_measurement": "°C",
20
+ "state_class": "measurement",
21
+ "device_class": "temperature",
22
+ "value_type": "S_WORD",
23
+ "filters": [{ "multiply": 0.1 }]
24
+ },
25
+ {
26
+ "name": "Humidity",
27
+ "address": 2,
28
+ "unit_of_measurement": "%",
29
+ "state_class": "measurement",
30
+ "device_class": "humidity",
31
+ "value_type": "S_WORD",
32
+ "filters": [{ "multiply": 0.1 }]
33
+ }
34
+ ]
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "model": "Socomec E03",
3
+ "registers_base": [
4
+ {
5
+ "base": 50520,
6
+ "length": 26,
7
+ "register_type": "holding",
8
+ "registers": [
9
+ {
10
+ "name": "Voltage_Phase1",
11
+ "address": 50520,
12
+ "unit_of_measurement": "V",
13
+ "state_class": "measurement",
14
+ "device_class": "voltage",
15
+ "value_type": "U_DWORD",
16
+ "filters": [{ "multiply": 0.01 }]
17
+ },
18
+ {
19
+ "name": "Frequency",
20
+ "address": 50526,
21
+ "unit_of_measurement": "Hz",
22
+ "state_class": "measurement",
23
+ "device_class": "voltage",
24
+ "value_type": "U_DWORD",
25
+ "filters": [{ "multiply": 0.01 }]
26
+ },
27
+ {
28
+ "name": "Current",
29
+ "address": 50528,
30
+ "unit_of_measurement": "A",
31
+ "state_class": "measurement",
32
+ "device_class": "current",
33
+ "value_type": "U_DWORD",
34
+ "filters": [{ "multiply": 0.001 }]
35
+ },
36
+ {
37
+ "name": "Sum_Active_Power",
38
+ "address": 50536,
39
+ "unit_of_measurement": "W",
40
+ "state_class": "measurement",
41
+ "value_type": "S_DWORD",
42
+ "filters": [{ "multiply": 10 }]
43
+ },
44
+ {
45
+ "name": "Sum_Reactive_Power",
46
+ "address": 50538,
47
+ "unit_of_measurement": "var",
48
+ "state_class": "measurement",
49
+ "value_type": "S_DWORD",
50
+ "filters": [{ "multiply": 10 }]
51
+ },
52
+ {
53
+ "name": "Sum_Apparent_Power",
54
+ "address": 50540,
55
+ "unit_of_measurement": "VA",
56
+ "state_class": "measurement",
57
+ "value_type": "U_DWORD",
58
+ "filters": [{ "multiply": 10 }]
59
+ },
60
+ {
61
+ "name": "Sum_Power_Factor",
62
+ "address": 50542,
63
+ "unit_of_measurement": "",
64
+ "state_class": "measurement",
65
+ "value_type": "S_DWORD",
66
+ "filters": [{ "multiply": 0.001 }]
67
+ },
68
+ {
69
+ "name": "Active_Power_Phase",
70
+ "address": 50544,
71
+ "unit_of_measurement": "W",
72
+ "state_class": "measurement",
73
+ "value_type": "S_DWORD",
74
+ "filters": [{ "multiply": 0.001 }]
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ "base": 50946,
80
+ "length": 8,
81
+ "register_type": "holding",
82
+ "registers": [
83
+ {
84
+ "name": "Total_Positive_Active_Energy",
85
+ "address": 50946,
86
+ "unit_of_measurement": "kWh",
87
+ "value_type": "U_DWORD",
88
+ "state_class": "total",
89
+ "device_class": "energy",
90
+ "filters": [{ "multiply": 0.01 }]
91
+ },
92
+ {
93
+ "name": "Total_Negative_Active_Energy",
94
+ "address": 50952,
95
+ "unit_of_measurement": "kWh",
96
+ "state_class": "total",
97
+ "device_class": "energy",
98
+ "filters": [{ "multiply": 0.01 }]
99
+ }
100
+ ]
101
+ }
102
+ ]
103
+ }
@@ -15,6 +15,24 @@
15
15
  "value_type": "U_DWORD",
16
16
  "filters": [{ "multiply": 0.01 }]
17
17
  },
18
+ {
19
+ "name": "Voltage_Phase2",
20
+ "address": 50522,
21
+ "unit_of_measurement": "V",
22
+ "state_class": "measurement",
23
+ "device_class": "voltage",
24
+ "value_type": "U_DWORD",
25
+ "filters": [{ "multiply": 0.01 }]
26
+ },
27
+ {
28
+ "name": "Voltage_Phase3",
29
+ "address": 50524,
30
+ "unit_of_measurement": "V",
31
+ "state_class": "measurement",
32
+ "device_class": "voltage",
33
+ "value_type": "U_DWORD",
34
+ "filters": [{ "multiply": 0.01 }]
35
+ },
18
36
  {
19
37
  "name": "Frequency",
20
38
  "address": 50526,
@@ -22,10 +40,10 @@
22
40
  "state_class": "measurement",
23
41
  "device_class": "voltage",
24
42
  "value_type": "U_DWORD",
25
- "filters": [{ "multiply": 0.01 }]
43
+ "filters": [{ "multiply": 0.001 }]
26
44
  },
27
45
  {
28
- "name": "Current",
46
+ "name": "Current_Phase1",
29
47
  "address": 50528,
30
48
  "unit_of_measurement": "A",
31
49
  "state_class": "measurement",
@@ -33,6 +51,33 @@
33
51
  "value_type": "U_DWORD",
34
52
  "filters": [{ "multiply": 0.001 }]
35
53
  },
54
+ {
55
+ "name": "Current_Phase2",
56
+ "address": 50530,
57
+ "unit_of_measurement": "A",
58
+ "state_class": "measurement",
59
+ "device_class": "current",
60
+ "value_type": "U_DWORD",
61
+ "filters": [{ "multiply": 0.001 }]
62
+ },
63
+ {
64
+ "name": "Current_Phase3",
65
+ "address": 50532,
66
+ "unit_of_measurement": "A",
67
+ "state_class": "measurement",
68
+ "device_class": "current",
69
+ "value_type": "U_DWORD",
70
+ "filters": [{ "multiply": 0.001 }]
71
+ },
72
+ {
73
+ "name": "Current_In",
74
+ "address": 50534,
75
+ "unit_of_measurement": "A",
76
+ "state_class": "measurement",
77
+ "device_class": "current",
78
+ "value_type": "U_DWORD",
79
+ "filters": [{ "multiply": 0.001 }]
80
+ },
36
81
  {
37
82
  "name": "Sum_Active_Power",
38
83
  "address": 50536,
@@ -66,12 +111,28 @@
66
111
  "filters": [{ "multiply": 0.001 }]
67
112
  },
68
113
  {
69
- "name": "Active_Power_Phase",
114
+ "name": "Active_Power_Phase1",
70
115
  "address": 50544,
71
116
  "unit_of_measurement": "W",
72
117
  "state_class": "measurement",
73
118
  "value_type": "S_DWORD",
74
- "filters": [{ "multiply": 0.001 }]
119
+ "filters": [{ "multiply": 10 }]
120
+ },
121
+ {
122
+ "name": "Active_Power_Phase2",
123
+ "address": 50546,
124
+ "unit_of_measurement": "W",
125
+ "state_class": "measurement",
126
+ "value_type": "S_DWORD",
127
+ "filters": [{ "multiply": 10 }]
128
+ },
129
+ {
130
+ "name": "Active_Power_Phase3",
131
+ "address": 50548,
132
+ "unit_of_measurement": "W",
133
+ "state_class": "measurement",
134
+ "value_type": "S_DWORD",
135
+ "filters": [{ "multiply": 10 }]
75
136
  }
76
137
  ]
77
138
  },
boneio/runner.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Runner code for boneIO. Based on HA runner."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import asyncio
@@ -80,7 +81,6 @@ async def async_run(
80
81
  for item in config_modules
81
82
  }
82
83
 
83
-
84
84
  manager = Manager(
85
85
  send_message=client.send_message,
86
86
  stop_client=client.stop_client,
boneio/schema/schema.yaml CHANGED
@@ -170,6 +170,14 @@ modbus_sensors:
170
170
  default: 30s
171
171
  meta:
172
172
  label: Update interval.
173
+ sensors_filters:
174
+ type: dict
175
+ required: False
176
+ meta:
177
+ label: List of sub sensors to use to filter. Available values are temperature or humidity.
178
+ schema:
179
+ temperature: !include filters.yaml
180
+ humidity: !include filters.yaml
173
181
  lm75:
174
182
  type: list
175
183
  required: False
@@ -506,6 +514,12 @@ binary_sensor:
506
514
  required: True
507
515
  meta:
508
516
  label: Check if sensor type is inverted. Only aplicable for sensor kind.
517
+ initial_send:
518
+ type: boolean
519
+ default: False
520
+ required: True
521
+ meta:
522
+ label: If set to true, then on startup of application initial status of the binary sensor will be send to MQTT.
509
523
  device_class:
510
524
  type: string
511
525
  required: False
boneio/sensor/gpio_new.py CHANGED
@@ -1,12 +1,14 @@
1
1
  """GpioInputBinarySensorNew to receive signals."""
2
+
2
3
  import logging
3
4
  from boneio.const import PRESSED, RELEASED, BOTH
4
5
  from boneio.helper import GpioBaseClass
6
+ import time
5
7
  from boneio.helper.gpio import add_event_callback, add_event_detect
6
8
 
7
9
  _LOGGER = logging.getLogger(__name__)
8
10
 
9
-
11
+ soc
10
12
  class GpioInputBinarySensorNew(GpioBaseClass):
11
13
  """Represent Gpio sensor on input boards."""
12
14
 
@@ -14,20 +16,32 @@ class GpioInputBinarySensorNew(GpioBaseClass):
14
16
  """Setup GPIO Input Button"""
15
17
  super().__init__(**kwargs)
16
18
  self._state = self.is_pressed
19
+ self.button_pressed_time = 0.0
17
20
  self._click_type = (
18
21
  (RELEASED, PRESSED)
19
22
  if kwargs.get("inverted", False)
20
23
  else (PRESSED, RELEASED)
21
24
  )
25
+ self._initial_send = kwargs.get("initial_send", False)
22
26
  _LOGGER.debug("Configured sensor pin %s", self._pin)
23
27
  add_event_detect(pin=self._pin, edge=BOTH)
24
28
  add_event_callback(pin=self._pin, callback=self.check_state)
29
+ self._loop.call_soon_threadsafe(self.check_state, self._initial_send)
25
30
 
26
- def check_state(self, _) -> None:
31
+ def check_state(self, initial_send: bool = False) -> None:
32
+ """Check if state has changed."""
33
+ time_now = time.time()
27
34
  state = self.is_pressed
28
- if state == self._state:
35
+ if (time_now - self.button_pressed_time <= self._bounce_time) or (
36
+ not initial_send and state == self._state
37
+ ):
29
38
  return
30
39
  self._state = state
31
40
  click_type = self._click_type[0] if state else self._click_type[1]
32
- _LOGGER.debug("%s event on pin %s - %s", click_type, self._pin, self.name)
41
+ _LOGGER.debug(
42
+ "Binary sensor: %s event on pin %s - %s",
43
+ click_type,
44
+ self._pin,
45
+ self.name,
46
+ )
33
47
  self.press_callback(click_type=click_type, duration=None)
boneio/sensor/ina219.py CHANGED
@@ -15,7 +15,7 @@ unit_converter = {"current": "A", "power": "W", "voltage": "V"}
15
15
 
16
16
 
17
17
  class INA219Sensor(BasicMqtt, Filter):
18
- """Represent singel value from INA219 as sensor."""
18
+ """Represent single value from INA219 as sensor."""
19
19
 
20
20
  def __init__(
21
21
  self, device_class: str, filters: list, state: float | None, **kwargs
@@ -52,7 +52,7 @@ class INA219Sensor(BasicMqtt, Filter):
52
52
  return self._unit_of_measurement
53
53
 
54
54
  def update(self, time: datetime) -> None:
55
- """Fetch temperature periodically and send to MQTT."""
55
+ """Fetch sensor data periodically and send to MQTT."""
56
56
  _state = (
57
57
  self._apply_filters(value=self._raw_state)
58
58
  if self._raw_state
@@ -67,7 +67,7 @@ class INA219Sensor(BasicMqtt, Filter):
67
67
  )
68
68
 
69
69
 
70
- class INA219(AsyncUpdater, Filter):
70
+ class INA219(AsyncUpdater):
71
71
  """Represent INA219 sensors."""
72
72
 
73
73
  def __init__(
@@ -77,16 +77,14 @@ class INA219(AsyncUpdater, Filter):
77
77
  self._loop = asyncio.get_event_loop()
78
78
  self._ina_219 = INA219_I2C(address=address)
79
79
  self._sensors = {}
80
- self._states = {}
81
80
  self._id = id
82
81
  for sensor in sensors:
83
82
  _name = sensor["id"]
84
83
  _id = f"{id}{_name.replace(' ', '')}"
85
- self._states[sensor["device_class"]] = None
86
84
  self._sensors[sensor["device_class"]] = INA219Sensor(
87
85
  device_class=sensor["device_class"],
88
86
  filters=sensor.get("filters", []),
89
- state=self._states[sensor["device_class"]],
87
+ state=None,
90
88
  name=_name,
91
89
  id=_id,
92
90
  **kwargs,
@@ -104,11 +102,9 @@ class INA219(AsyncUpdater, Filter):
104
102
 
105
103
  async def async_update(self, time: datetime) -> None:
106
104
  """Fetch temperature periodically and send to MQTT."""
107
- for k in self._states.keys():
108
- value = getattr(self._ina_219, k)
109
- self._states[k] = value
110
- _LOGGER.debug("Read %s with value: %s", k, value)
111
105
  for k, sensor in self._sensors.items():
112
- if sensor.raw_state != self._states[k]:
113
- sensor.raw_state = self._states[k]
114
- self._loop.call_soon(sensor.update, time)
106
+ value = getattr(self._ina_219, k)
107
+ _LOGGER.debug("Fetched INA219 value: %s %s", k, value)
108
+ if sensor.raw_state != value:
109
+ sensor.raw_state = value
110
+ sensor.update(time=time)
boneio/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # flake8: noqa
2
- __version__ = "0.8.0dev8"
2
+ __version__ = "0.8.0dev10"