boneIO 0.8.0.dev8__tar.gz → 0.8.0.dev9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/PKG-INFO +1 -1
  2. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/bonecli.py +57 -7
  3. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/filter.py +3 -2
  4. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/loader.py +1 -0
  5. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/client.py +2 -0
  6. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/cwt.json +1 -1
  7. boneIO-0.8.0.dev9/boneio/modbus/liquid-sensor.json +37 -0
  8. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/modbuscli.py +91 -18
  9. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/r4dcb08.json +7 -1
  10. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/sensor.py +16 -2
  11. boneIO-0.8.0.dev9/boneio/modbus/sht20.json +37 -0
  12. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/schema.yaml +8 -0
  13. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/ina219.py +3 -3
  14. boneIO-0.8.0.dev9/boneio/version.py +2 -0
  15. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/pyproject.toml +1 -1
  16. boneIO-0.8.0.dev8/boneio/version.py +0 -2
  17. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/LICENSE +0 -0
  18. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/README.md +0 -0
  19. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/__init__.py +0 -0
  20. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/const.py +0 -0
  21. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/cover.py +0 -0
  22. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/__init__.py +0 -0
  23. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/adc.yaml +0 -0
  24. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/binary_sensor.yaml +0 -0
  25. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/binary_sensor_v_0_7.yaml +0 -0
  26. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/config.yaml +0 -0
  27. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/cover.yaml +0 -0
  28. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/event.yaml +0 -0
  29. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/event_all.yaml +0 -0
  30. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/event_v_0_7.yaml +0 -0
  31. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/led32x4A.yaml +0 -0
  32. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/output24x16A.yaml +0 -0
  33. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/output24x16A_v0.3.yaml +0 -0
  34. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/output32x10A.yaml +0 -0
  35. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/example_config/output32x5A.yaml +0 -0
  36. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/fonts/danube__.ttf +0 -0
  37. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/group/__init__.py +0 -0
  38. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/group/output.py +0 -0
  39. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/__init__.py +0 -0
  40. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/async_updater.py +0 -0
  41. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/click_timer.py +0 -0
  42. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/config.py +0 -0
  43. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/events.py +0 -0
  44. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/exceptions.py +0 -0
  45. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/gpio.py +0 -0
  46. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/ha_discovery.py +0 -0
  47. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/logger.py +0 -0
  48. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/mqtt.py +0 -0
  49. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/oled.py +0 -0
  50. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/onewire/W1ThermSensor.py +0 -0
  51. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/onewire/__init__.py +0 -0
  52. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/onewire/ds2482.py +0 -0
  53. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/onewire/onewire.py +0 -0
  54. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/pcf8575.py +0 -0
  55. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/queue.py +0 -0
  56. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/sensor/ina_219_smbus.py +0 -0
  57. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/state_manager.py +0 -0
  58. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/stats.py +0 -0
  59. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/timeperiod.py +0 -0
  60. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/util.py +0 -0
  61. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/helper/yaml_util.py +0 -0
  62. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/input/__init__.py +0 -0
  63. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/input/gpio.py +0 -0
  64. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/input/gpio_new.py +0 -0
  65. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/manager.py +0 -0
  66. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/__init__.py +0 -0
  67. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/dts1964_3f.json +0 -0
  68. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/orno-or-we-517.json +0 -0
  69. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/pt100.json +0 -0
  70. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/sdm120.json +0 -0
  71. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/sdm630.json +0 -0
  72. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/socomec_e23.json +0 -0
  73. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/sofar.json +0 -0
  74. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/modbus/utils.py +0 -0
  75. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/mqtt_client.py +0 -0
  76. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/oled.py +0 -0
  77. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/relay/__init__.py +0 -0
  78. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/relay/basic.py +0 -0
  79. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/relay/gpio.py +0 -0
  80. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/relay/mcp.py +0 -0
  81. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/relay/pca.py +0 -0
  82. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/relay/pcf.py +0 -0
  83. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/runner.py +0 -0
  84. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/actions.yaml +0 -0
  85. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/actions_sensor.yaml +0 -0
  86. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/actions_switch.yaml +0 -0
  87. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/filters.yaml +0 -0
  88. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/filters_adc.yaml +0 -0
  89. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/id.yaml +0 -0
  90. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/temp_unit.yaml +0 -0
  91. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/schema/update_interval.yaml +0 -0
  92. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/__init__.py +0 -0
  93. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/adc.py +0 -0
  94. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/gpio.py +0 -0
  95. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/gpio_new.py +0 -0
  96. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/temp/__init__.py +0 -0
  97. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/temp/dallas.py +0 -0
  98. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/temp/lm75.py +0 -0
  99. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/boneio/sensor/temp/mcp9808.py +0 -0
  100. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/tests/32_5_config.yaml +0 -0
  101. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/tests/bandit.yaml +0 -0
  102. {boneIO-0.8.0.dev8 → boneIO-0.8.0.dev9}/tests/relay_32_5.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: boneIO
3
- Version: 0.8.0.dev8
3
+ Version: 0.8.0.dev9
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>
@@ -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
 
@@ -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(
@@ -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:
@@ -43,6 +43,7 @@ class Modbus:
43
43
  stopbits: int = 1,
44
44
  bytesize: int = 8,
45
45
  parity: str = "N",
46
+ timeout: float = 3,
46
47
  ) -> None:
47
48
  """Initialize the Modbus hub."""
48
49
  rx = uart.get(RX)
@@ -68,6 +69,7 @@ class Modbus:
68
69
  stopbits=stopbits,
69
70
  bytesize=bytesize,
70
71
  parity=parity,
72
+ timeout=timeout,
71
73
  )
72
74
  self._read_methods = {
73
75
  "input": self._client.read_input_registers,
@@ -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,
@@ -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": [
@@ -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
+ }
@@ -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
@@ -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
@@ -111,4 +111,4 @@ class INA219(AsyncUpdater, Filter):
111
111
  for k, sensor in self._sensors.items():
112
112
  if sensor.raw_state != self._states[k]:
113
113
  sensor.raw_state = self._states[k]
114
- self._loop.call_soon(sensor.update, time)
114
+ self._loop.call_soon_threadsafe(sensor.update, time)
@@ -0,0 +1,2 @@
1
+ # flake8: noqa
2
+ __version__ = "0.8.0dev9"
@@ -30,7 +30,7 @@ dependencies = [
30
30
  "Adafruit-BBIO>=1.2.0",
31
31
  ]
32
32
  requires-python = ">=3.7"
33
- version = "0.8.0.dev8"
33
+ version = "0.8.0.dev9"
34
34
 
35
35
  [project.license]
36
36
  text = "GNU General Public License v3.0"
@@ -1,2 +0,0 @@
1
- # flake8: noqa
2
- __version__ = "0.8.0dev8"
File without changes
File without changes
File without changes
File without changes
File without changes