boneIO 0.7.2.dev4__py3-none-any.whl → 0.8.0.dev2__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.7.2dev4
3
+ Version: 0.8.0dev2
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=fKPcTEMjYG8zhWig3F6dqE2jDxBd17ydWHp0XVnq6sc,3491
2
+ boneio/bonecli.py,sha256=JR4ILR5E3fVFkVL28-_tJcxckrKUIQwbNFkVF3YPMXs,7280
3
3
  boneio/const.py,sha256=eIpq1EvFYh1p9I83xaDSOrF_JfdYr-1-yXO5vsAaqCg,5093
4
4
  boneio/cover.py,sha256=EfO1DAOGTPQykfgJHzg1WqPs0U8b1AnD2NMI-sLZccM,8444
5
5
  boneio/example_config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -22,12 +22,12 @@ boneio/helper/click_timer.py,sha256=Gu8sEi1S8GG42SYbfaMju7WXFhnnil9gYfirLZX7kJk,
22
22
  boneio/helper/config.py,sha256=5cDnJ7usJDlUvXv8K2rSWEx30OFcU2k1U1vUEjO69WY,2431
23
23
  boneio/helper/events.py,sha256=f4JDMMkyp0lWz9w8ABZ_hlKyAbJWtYHGnGTs2vv4vac,8648
24
24
  boneio/helper/exceptions.py,sha256=vyYSUojwB7OttOPUjbxeHFM7C_o5ZQmRUcZ_vYpxYYI,717
25
- boneio/helper/filter.py,sha256=UcjifjaC5wHDW2He7wmwCX2IjSSeLVhXyhrXHeT8RmA,885
25
+ boneio/helper/filter.py,sha256=8jgSbHDaInEVlAPd7nrahnFYsi1y6C2fmI0yn55XzK0,935
26
26
  boneio/helper/gpio.py,sha256=q2r2uklPWePuuekPO63kVfoaQdkvNObUJ3ktwsHgOB0,4771
27
27
  boneio/helper/ha_discovery.py,sha256=B2t1cfOfKWys4EM1H7OxvOaYL8H_v18CTuHCEVP2w2c,7107
28
- boneio/helper/loader.py,sha256=zbg6WrKg7sfFRjny6qNQL7l-6ENbPq5AoEuW2T69PQE,17333
28
+ boneio/helper/loader.py,sha256=mkvM6Fg_4xHI079iiWFcUQFW1w8819AXAkiBja0vKxo,17473
29
29
  boneio/helper/logger.py,sha256=zyF_Vk3o2eSHuXypJhNzK99eZgkWDWybuB5KcJgurDs,1801
30
- boneio/helper/mqtt.py,sha256=novgn5Xl--dmwJ3p6gYVnurVxF5uf-i_t9rj5EmmvP8,859
30
+ boneio/helper/mqtt.py,sha256=1YgwO0RjkarN5qS5HS5rONf4H3_m3ak7tT_hHm-HeOQ,931
31
31
  boneio/helper/oled.py,sha256=f0XYbaFstUbJ6ISmFe1vQCnmNVMctQWtnStNdROrblc,351
32
32
  boneio/helper/onewire/W1ThermSensor.py,sha256=Pu5Fp29pKbxjJqDbFs05Mjg3Vy-9z_DTVoBpSWM_byA,2430
33
33
  boneio/helper/onewire/__init__.py,sha256=4djH-uxiq5XhAiFTOxyqjvWVoJe0c8U8iN0BfmH8nSU,448
@@ -36,16 +36,29 @@ boneio/helper/onewire/onewire.py,sha256=tHofTu1l0qG7hH2XoSf-lj8gW7wVKe27j57qQWpV
36
36
  boneio/helper/pcf8575.py,sha256=qeNYLqV5foDEQCyAz1WRQRi1CYYxtbPIha06Z5TyZVQ,311
37
37
  boneio/helper/queue.py,sha256=7fE7d344-BEW8sljN40wmqsbBr4kPLvz4ShBjkT04p8,1066
38
38
  boneio/helper/sensor/ina_219_smbus.py,sha256=eXp2epjUgsqaXamTSWSn3LMow5X_YxAxdREaWD7N3mk,6170
39
- boneio/helper/state_manager.py,sha256=W63oGPCKo1vZ8zr5Q_3SALM0mgjuab5b8Y397HAiO_o,2633
39
+ boneio/helper/state_manager.py,sha256=6OeqJsLQPCyQhhmFlNxCd80cTYLnKb02L4AZ1ZFFVBE,2616
40
40
  boneio/helper/stats.py,sha256=Ard04Z0WpkV7U6hgv1Uf4KxkjIde5iIW8W2cqRGXZyg,6731
41
41
  boneio/helper/timeperiod.py,sha256=xpg9oe30Z5WiLDQPq3EBKKScejOnN47NhcpeFvDd3bY,5806
42
- boneio/helper/util.py,sha256=SwTxVnUFe-YCmzubRzfICJDgrr0xMAJaR0G1wBXCMR8,681
42
+ boneio/helper/util.py,sha256=DyppBTE2zTWoxVpl83Kb4SpJLEqOOSEkxXEITCrwnfk,938
43
43
  boneio/helper/yaml_util.py,sha256=aaXMwXC2JoDYkBMcZkkB8nic3QOyGOhxPTRxWvMf3G4,11334
44
44
  boneio/input/__init__.py,sha256=8Hcps-wCCl6bCAMoEmDJecR-Q9giFL29AvG1ZGe0dZw,200
45
45
  boneio/input/gpio.py,sha256=mqmce4P_dNzmNHqNNiNAmKeeZKbbKtPUtQ6zd8-R-9I,2438
46
46
  boneio/input/gpio_new.py,sha256=gpPfDr39B8FVUyh9XHtLgVQr4glMGFBgQsyIMzXDPaw,2822
47
- boneio/manager.py,sha256=Qgnk_5-rnVZ4ZcvpsFMmJndXJiWnxb4AarlPs37E_1s,29859
48
- boneio/modbus.py,sha256=edeBrIKfpcPdU6KkfVTgCCVijrqkhZzx9hBmR2b0czk,5550
47
+ boneio/manager.py,sha256=06smEmgB9UDWUjCvy2l_lEHFyONU6N6ppW_dOiRv-wM,29866
48
+ boneio/modbus/__init__.py,sha256=yeHIxZ0_u7eCL7CqScvob5Utcru6Iza0LEtTagEtNtw,116
49
+ boneio/modbus/client.py,sha256=tmArCt9ac6rxUymdmFMEn4xpZtGdU7Yby7r3RkGJVxM,6030
50
+ boneio/modbus/cwt.json,sha256=4zJAHAV-h1JsV_Yp4VF6ecg_0eef-EHOdzRnhnMHRQs,814
51
+ boneio/modbus/dts1964_3f.json,sha256=WABph_2X4OgMidSM28vw4dLd9ZByRoiUP-RqE0UMpR8,8810
52
+ boneio/modbus/modbuscli.py,sha256=kt9T707FHCOzWE7SJEMTbLyM8BPPnTmcWsY5-0q9zqU,5502
53
+ boneio/modbus/orno-or-we-517.json,sha256=PtaG0B_uNLCemN2vrIXFS4Kzt6JBVoGCYhNMG-1wZhg,505
54
+ boneio/modbus/pt100.json,sha256=bzKNYDc3lMto94Ut8gutVIsHytQiMobwFCkonOiMegs,526
55
+ boneio/modbus/r4dcb08.json,sha256=oj4eK3bD1bG8BTRE4STVHB5L92luWaJ3FYFHQvFg-ZA,2735
56
+ boneio/modbus/sdm120.json,sha256=4sueFfSw7G6a77gdIUhbfJvE-MNVJFOeVbRvHDw5Rvk,4145
57
+ boneio/modbus/sdm630.json,sha256=TUiuc060IpF64p_HSDvdxEQcwkWHWUpnd48_xaGU-_o,8255
58
+ boneio/modbus/sensor.py,sha256=tfFYQNK0dE1yA0Otw66dxoM5wJ1b6nvW2_k4y8WAk_g,8303
59
+ boneio/modbus/socomec_e23.json,sha256=Is51YelEd4d6SYmz4Gd_oKx4Qi3bp-VHsl9zxWOFI5s,2882
60
+ boneio/modbus/sofar.json,sha256=A_YztQN_ctyItIm2LH1tfcs-pSyG18I530qleLd2tOw,5592
61
+ boneio/modbus/utils.py,sha256=cG75mmKTGaw_qrCG_D1qw-jl9XybUXa03i1ap5oBxGE,1753
49
62
  boneio/mqtt_client.py,sha256=hzGT3IyftPHNrQXSKbWUXGYZBpP-VdRBkOrILkXDNHs,8665
50
63
  boneio/oled.py,sha256=dLfAaH2Qto9P3mil_JK4siGvkSQ7LebhCabhL-OYGaM,5505
51
64
  boneio/relay/__init__.py,sha256=Cz6D37GKHxm8DiuPuxE2EMaey2wdUdJYVet_hfR0lzA,231
@@ -61,7 +74,7 @@ boneio/schema/actions_switch.yaml,sha256=cDgSi12k4S-TWADQ20Fy9NvYKOXnm7YkyMaWpPy
61
74
  boneio/schema/filters.yaml,sha256=WopX1SmCZsSZXNiGccLoi7uMCsUpdbs0eVfsAjmbay4,286
62
75
  boneio/schema/filters_adc.yaml,sha256=3e0ts92MoFKOnfGOOn6WYIHxu0-tnZe9OjAjN9m7hiI,304
63
76
  boneio/schema/id.yaml,sha256=vHI_6dxkJwoiGp5ien_pPpyaWA1F06eirTgfWMyWa1E,75
64
- boneio/schema/schema.yaml,sha256=f7fgzVI14yMmL_j2ojFKx2kG95a1KjkuSnP3tP8Vay0,18368
77
+ boneio/schema/schema.yaml,sha256=R9EqtON1dTNsyCtIXDy6B1vJQArGnSQlnSLExJhVmqc,18418
65
78
  boneio/schema/temp_unit.yaml,sha256=m32VGz9RTW92Lz08l9n6RftkcVNZquOGPPr5mc3eZVc,65
66
79
  boneio/schema/update_interval.yaml,sha256=L_YLddAZdybcdO-T57Qhlv1GaWIVDwhvH-GadD1oOIo,133
67
80
  boneio/sensor/__init__.py,sha256=Ztj-xzey-SWrEdVEozcwFsZSuEmJW8STVaf_vPMWiVc,619
@@ -69,21 +82,13 @@ boneio/sensor/adc.py,sha256=tCUdr3KN5uSbgXiwhNXbMjeNkO2CzPYhIOncHR5_LD0,1328
69
82
  boneio/sensor/gpio.py,sha256=8m07tW1xDsrhBM2dZ9_VvmvYRn-5hLQVTTUhPlKg1rg,1199
70
83
  boneio/sensor/gpio_new.py,sha256=m54agOF2gUh3aoC6f8WpCPAmBRADvqlKeWLqwlon9fg,1223
71
84
  boneio/sensor/ina219.py,sha256=kBwaCjY63CNFj1mRZ2EEtm2BrMZ6BW4ahjAD2LT-0jo,3439
72
- boneio/sensor/modbus/__init__.py,sha256=qB7MGcC6c-2X0U0iN7ai5qSo7tHp4zwZ_FX6TcQmiNU,10129
73
- boneio/sensor/modbus/dts1964_3f.json,sha256=WABph_2X4OgMidSM28vw4dLd9ZByRoiUP-RqE0UMpR8,8810
74
- boneio/sensor/modbus/pt100.json,sha256=bzKNYDc3lMto94Ut8gutVIsHytQiMobwFCkonOiMegs,526
75
- boneio/sensor/modbus/r4dcb08.json,sha256=oj4eK3bD1bG8BTRE4STVHB5L92luWaJ3FYFHQvFg-ZA,2735
76
- boneio/sensor/modbus/sdm120.json,sha256=4sueFfSw7G6a77gdIUhbfJvE-MNVJFOeVbRvHDw5Rvk,4145
77
- boneio/sensor/modbus/sdm630.json,sha256=TUiuc060IpF64p_HSDvdxEQcwkWHWUpnd48_xaGU-_o,8255
78
- boneio/sensor/modbus/socomec_e23.json,sha256=G4dEvOQbJpkLonubpjI77KFtlt13iwVxmArMgUzuwm0,2859
79
- boneio/sensor/modbus/sofar.json,sha256=A_YztQN_ctyItIm2LH1tfcs-pSyG18I530qleLd2tOw,5592
80
85
  boneio/sensor/temp/__init__.py,sha256=JLNH6Nc78ezleftnIYylIcNtKIm0rdqetbPZLsuCgDc,1844
81
86
  boneio/sensor/temp/dallas.py,sha256=xrvd1LNBh1fRcjz_yd_9S29Lv26ItVtLCmhZgVQWJos,2485
82
87
  boneio/sensor/temp/lm75.py,sha256=-mpOv78429plRPBp9s09Ljz1x2Bdxuagalqz40vlAKE,243
83
88
  boneio/sensor/temp/mcp9808.py,sha256=yAh5yJzZLGTqa39xV4fyqsruj7oy3niOZAUV2W6eyCM,271
84
- boneio/version.py,sha256=MwhIhpPdwgnlOYgQUWre-MHZsuhOMXaDZ69JqvVW4uU,41
85
- boneIO-0.7.2.dev4.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
86
- boneIO-0.7.2.dev4.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
87
- boneIO-0.7.2.dev4.dist-info/METADATA,sha256=wVLYQttucUYjOEYNEDHL1W6zM8JELdY5tBq_V01Iq7Q,1801
88
- boneIO-0.7.2.dev4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
89
- boneIO-0.7.2.dev4.dist-info/RECORD,,
89
+ boneio/version.py,sha256=qUYOwKU4jFQvDJRLavdrZJyoMqaNsiJCiYpN35E3_Ak,41
90
+ boneIO-0.8.0.dev2.dist-info/entry_points.txt,sha256=Igl1SMDEWwMg144bwRz28UOCb80hdxomC99QJ3u6qC0,46
91
+ boneIO-0.8.0.dev2.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
92
+ boneIO-0.8.0.dev2.dist-info/METADATA,sha256=hcxcGSVtqYAvfGFFwZuI5FBtvvMd6Kf_Ingf-D-OWlo,1801
93
+ boneIO-0.8.0.dev2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
94
+ boneIO-0.8.0.dev2.dist-info/RECORD,,
boneio/bonecli.py CHANGED
@@ -1,20 +1,28 @@
1
1
  """Bonecli script."""
2
+
2
3
  from __future__ import annotations
3
- import argparse
4
- import asyncio
5
- import logging
6
- import sys
4
+
7
5
  import os
8
- from typing import Any
9
6
 
10
7
  os.environ["W1THERMSENSOR_NO_KERNEL_MODULE"] = "1"
11
8
 
9
+ import argparse
10
+ import asyncio
11
+ import logging
12
+ import sys
12
13
  from colorlog import ColoredFormatter
13
14
  from yaml import MarkedYAMLError
14
15
 
16
+ from boneio.modbus.modbuscli import async_run_modbus_set, async_run_modbus_get
17
+ from boneio.modbus.client import VALUE_TYPES
18
+
19
+
15
20
  from boneio.const import ACTION
16
21
  from boneio.helper import load_config_from_file
17
- from boneio.helper.exceptions import ConfigurationException, RestartRequestException
22
+ from boneio.helper.exceptions import (
23
+ ConfigurationException,
24
+ RestartRequestException,
25
+ )
18
26
  from boneio.helper.events import GracefulExit
19
27
  from boneio.helper.logger import configure_logger
20
28
  from boneio.runner import async_run
@@ -49,30 +57,114 @@ def get_arguments() -> argparse.Namespace:
49
57
  parser = argparse.ArgumentParser(
50
58
  description="boneIO app for BeagleBone Black.",
51
59
  )
52
- parser.add_argument(ACTION, type=str, default="run")
53
- parser.add_argument("--version", action="version", version=__version__)
54
- parser.add_argument(
60
+ subparsers = parser.add_subparsers(dest=ACTION, required=True)
61
+ run_parser = subparsers.add_parser("run")
62
+ run_parser.add_argument(
63
+ "--debug",
64
+ "-d",
65
+ action="count",
66
+ help="Start boneIO in debug mode",
67
+ default=0,
68
+ )
69
+ run_parser.add_argument(
55
70
  "-c",
56
71
  "--config",
57
72
  metavar="path_to_config_dir",
58
73
  default="./config.yaml",
59
74
  help="File which contains boneIO configuration",
60
75
  )
61
- parser.add_argument(
62
- "--debug", "-d", action="count", help="Start boneIO in debug mode", default=0
76
+ run_parser.add_argument(
77
+ "--mqttusername",
78
+ help="Mqtt username to use if you don't want provide in file.",
79
+ )
80
+ run_parser.add_argument(
81
+ "--mqttpassword",
82
+ help="Mqtt password to use if you don't want provide in file.",
83
+ )
84
+ modbus_parser = subparsers.add_parser("modbus")
85
+ modbus_parser.add_argument(
86
+ "--debug",
87
+ "-d",
88
+ action="count",
89
+ help="Start boneIO in debug mode",
90
+ default=0,
91
+ )
92
+ modbus_parser.add_argument(
93
+ "--uart",
94
+ type=str,
95
+ choices=["uart1", "uart4"],
96
+ help="Choose UART",
97
+ required=True,
98
+ )
99
+ modbus_parser.add_argument(
100
+ "--address",
101
+ type=lambda x: int(x, 0),
102
+ required=True,
103
+ help="Current device address (hex or integer)",
104
+ )
105
+ modbus_parser.add_argument(
106
+ "--baudrate",
107
+ type=int,
108
+ choices=[2400, 4800, 9600, 19200],
109
+ required=True,
110
+ help="Current baudrate",
111
+ )
112
+
113
+ modbus_sub_parser = modbus_parser.add_subparsers(
114
+ dest="modbus_action", required=True
63
115
  )
64
- parser.add_argument(
65
- "--mqttusername", help="Mqtt username to use if you don't want provide in file."
116
+ set_modbus_parser = modbus_sub_parser.add_parser("set")
117
+ set_modbus_parser.add_argument(
118
+ "--device",
119
+ type=str,
120
+ choices=["cwt"],
121
+ help="Choose device to set modbus address/baudrate",
122
+ required=True,
66
123
  )
67
- parser.add_argument(
68
- "--mqttpassword", help="Mqtt password to use if you don't want provide in file."
124
+ set_modbus_parser_group = set_modbus_parser.add_mutually_exclusive_group()
125
+ set_modbus_parser_group.add_argument(
126
+ "--new-address",
127
+ type=lambda x: int(x, 0),
128
+ help="Set new address (hex or integer / 1 - 253/)",
69
129
  )
130
+
131
+ set_modbus_parser_group.add_argument(
132
+ "--new-baudrate",
133
+ type=int,
134
+ choices=[2400, 4800, 9600, 19200],
135
+ help="Choose new baudrate to set",
136
+ )
137
+
138
+ get_modbus_parser = modbus_sub_parser.add_parser("get")
139
+ get_modbus_parser.add_argument(
140
+ "--register-address",
141
+ type=int,
142
+ help="Register address",
143
+ required=True,
144
+ )
145
+ get_modbus_parser.add_argument(
146
+ "--register-type",
147
+ type=str,
148
+ choices=["input", "holding"],
149
+ help="Register type",
150
+ required=True,
151
+ )
152
+ get_modbus_parser.add_argument(
153
+ "--value-type",
154
+ type=str,
155
+ choices=VALUE_TYPES.keys(),
156
+ help="Value types",
157
+ required=True,
158
+ )
159
+ parser.add_argument("--version", action="version", version=__version__)
70
160
  arguments = parser.parse_args()
71
161
 
72
162
  return arguments
73
163
 
74
164
 
75
- def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = "") -> int:
165
+ def run(
166
+ config: str, debug: int, mqttusername: str = "", mqttpassword: str = ""
167
+ ) -> int:
76
168
  """Run BoneIO."""
77
169
  _LOGGER.info("BoneIO %s starting.", __version__)
78
170
  try:
@@ -99,6 +191,45 @@ def run(config: str, debug: int, mqttusername: str = "", mqttpassword: str = "")
99
191
  return 1
100
192
 
101
193
 
194
+ def run_modbus_command(
195
+ args: argparse.Namespace,
196
+ ) -> int:
197
+ """Run BoneIO."""
198
+ _LOGGER.info("BoneIO %s starting.", __version__)
199
+ try:
200
+ configure_logger(log_config={}, debug=args.debug)
201
+ if args.modbus_action == "set":
202
+ ret = asyncio.run(
203
+ async_run_modbus_set(
204
+ device=args.device,
205
+ uart=args.uart,
206
+ address=args.address,
207
+ baudrate=args.baudrate,
208
+ new_baudrate=args.new_baudrate,
209
+ new_address=args.new_address,
210
+ ),
211
+ )
212
+ else:
213
+ ret = asyncio.run(
214
+ async_run_modbus_get(
215
+ uart=args.uart,
216
+ device_address=args.address,
217
+ baudrate=args.baudrate,
218
+ register_address=args.register_address,
219
+ register_type=args.register_type,
220
+ value_type=args.value_type,
221
+ ),
222
+ )
223
+ return ret
224
+ except (RestartRequestException, GracefulExit) as err:
225
+ if err is not None:
226
+ _LOGGER.info(err)
227
+ return 0
228
+ except (ConfigurationException, MarkedYAMLError) as err:
229
+ _LOGGER.error("Failed to load config. %s Exiting.", err)
230
+ return 1
231
+
232
+
102
233
  def main() -> int:
103
234
  """Start boneIO."""
104
235
 
@@ -113,6 +244,12 @@ def main() -> int:
113
244
  mqttpassword=args.mqttpassword,
114
245
  debug=debug,
115
246
  )
247
+ elif args.action == "modbus":
248
+ _LOGGER.info("BoneIO Modbus helper %s .", __version__)
249
+ exit_code = run_modbus_command(
250
+ args=args,
251
+ )
252
+
116
253
  _LOGGER.info("Exiting with exit code %s", exit_code)
117
254
  return exit_code
118
255
 
boneio/helper/filter.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Filter class to adjust sensor values."""
2
+
2
3
  from __future__ import annotations
3
4
  import logging
4
5
 
@@ -22,7 +23,9 @@ class Filter:
22
23
  for filter in self._filters:
23
24
  for k, v in filter.items():
24
25
  if k not in FILTERS:
25
- _LOGGER.warn("Filter %s doesn't exists. Fix it in config.", k)
26
+ _LOGGER.warning(
27
+ "Filter %s doesn't exists. Fix it in config.", k
28
+ )
26
29
  continue
27
30
  value = FILTERS[k](value, v)
28
31
  if value is None:
boneio/helper/loader.py CHANGED
@@ -103,7 +103,9 @@ def create_adc(manager: Manager, topic_prefix: str, adc_list: list = []):
103
103
  manager=manager,
104
104
  send_message=manager.send_message,
105
105
  topic_prefix=topic_prefix,
106
- update_interval=gpio.get(UPDATE_INTERVAL, TimePeriod(seconds=60)),
106
+ update_interval=gpio.get(
107
+ UPDATE_INTERVAL, TimePeriod(seconds=60)
108
+ ),
107
109
  filters=gpio.get(FILTERS, []),
108
110
  )
109
111
  if gpio.get(SHOW_HA, True):
@@ -163,7 +165,10 @@ expander_class = {MCP: MCP23017, PCA: PCA9685, PCF: PCF8575}
163
165
 
164
166
 
165
167
  def create_expander(
166
- expander_dict: dict, expander_config: list, exp_type: ExpanderTypes, i2cbusio: I2C
168
+ expander_dict: dict,
169
+ expander_config: list,
170
+ exp_type: ExpanderTypes,
171
+ i2cbusio: I2C,
167
172
  ) -> dict:
168
173
  grouped_outputs = {}
169
174
  for expander in expander_config:
@@ -189,7 +194,7 @@ def create_expander(
189
194
 
190
195
  def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
191
196
  """Create Modbus sensor for each device."""
192
- from boneio.sensor.modbus import ModbusSensor
197
+ from boneio.modbus.sensor import ModbusSensor
193
198
 
194
199
  for sensor in sensors:
195
200
  name = sensor.get(ID)
@@ -202,7 +207,9 @@ def create_modbus_sensors(manager: Manager, sensors, **kwargs) -> None:
202
207
  manager=manager,
203
208
  model=sensor[MODEL],
204
209
  send_message=manager.send_message,
205
- update_interval=sensor.get(UPDATE_INTERVAL, TimePeriod(seconds=60)),
210
+ update_interval=sensor.get(
211
+ UPDATE_INTERVAL, TimePeriod(seconds=60)
212
+ ),
206
213
  **kwargs,
207
214
  )
208
215
  except FileNotFoundError as err:
@@ -272,7 +279,9 @@ def configure_relay(
272
279
  if restore_state
273
280
  else False
274
281
  )
275
- if output_type == NONE and state_manager.get(attr_type=RELAY, attr=relay_id):
282
+ if output_type == NONE and state_manager.get(
283
+ attr_type=RELAY, attr=relay_id
284
+ ):
276
285
  state_manager.del_attribute(attr_type=RELAY, attribute=relay_id)
277
286
  restored_state = False
278
287
 
@@ -347,7 +356,7 @@ def configure_event_sensor(
347
356
  pin: str,
348
357
  press_callback: Callable,
349
358
  send_ha_autodiscovery: Callable,
350
- input: GpioEventButtonOld | GpioEventButtonNew | None = None
359
+ input: GpioEventButtonOld | GpioEventButtonNew | None = None,
351
360
  ) -> GpioEventButtonOld | GpioEventButtonNew | None:
352
361
  """Configure input sensor or button."""
353
362
  try:
@@ -473,7 +482,9 @@ def configure_cover(
473
482
  return cover
474
483
 
475
484
 
476
- def configure_ds2482(i2cbusio: I2C, address: str = DS2482_ADDRESS) -> OneWireBus:
485
+ def configure_ds2482(
486
+ i2cbusio: I2C, address: str = DS2482_ADDRESS
487
+ ) -> OneWireBus:
477
488
  ds2482 = DS2482(i2c=i2cbusio, address=address)
478
489
  ow_bus = OneWireBus(ds2482=ds2482)
479
490
  return ow_bus
@@ -493,7 +504,9 @@ def find_onewire_devices(
493
504
  devices = ow_bus.scan()
494
505
  for device in devices:
495
506
  _addr: int = device.int_address
496
- _LOGGER.debug("Found device on bus %s with address %s", bus_id, hex(_addr))
507
+ _LOGGER.debug(
508
+ "Found device on bus %s with address %s", bus_id, hex(_addr)
509
+ )
497
510
  out[_addr] = device
498
511
  except RuntimeError as err:
499
512
  _LOGGER.error("Problem with scanning %s bus. %s", bus_type, err)
boneio/helper/mqtt.py CHANGED
@@ -1,6 +1,8 @@
1
1
  """Class to help initialize classes which uses mqtt send."""
2
+
2
3
  from typing import Callable, Union
3
4
  from boneio.helper.util import strip_accents
5
+ from typing import Optional
4
6
 
5
7
 
6
8
  class BasicMqtt:
@@ -11,7 +13,9 @@ class BasicMqtt:
11
13
  id: str,
12
14
  topic_prefix: str,
13
15
  name: str,
14
- send_message: Callable[[str, Union[str, dict], bool], None],
16
+ send_message: Callable[
17
+ [str, Union[str, int, dict, None], Optional[bool]], None
18
+ ],
15
19
  topic_type: str,
16
20
  **kwargs,
17
21
  ):
@@ -1,4 +1,5 @@
1
1
  """State files manager."""
2
+
2
3
  from __future__ import annotations
3
4
  import asyncio
4
5
  import logging
@@ -38,16 +39,19 @@ class StateManager:
38
39
  if attr_type in self._state and attribute in self._state[attr_type]:
39
40
  del self._state[attr_type][attribute]
40
41
 
41
- def save_attribute(self, attr_type: str, attribute: str, value: str) -> None:
42
+ def save_attribute(
43
+ self, attr_type: str, attribute: str, value: str
44
+ ) -> None:
42
45
  """Save single attribute to file."""
43
46
  if attr_type not in self._state:
44
47
  self._state[attr_type] = {}
45
48
  self._state[attr_type][attribute] = value
46
49
  if self._save_attributes_callback is not None:
47
- print(self._save_attributes_callback)
48
50
  self._save_attributes_callback.cancel()
49
51
  self._save_attributes_callback = None
50
- self._save_attributes_callback = self._loop.call_later(1, lambda: self._loop.create_task(self.save_state()))
52
+ self._save_attributes_callback = self._loop.call_later(
53
+ 1, lambda: self._loop.create_task(self.save_state())
54
+ )
51
55
 
52
56
  def get(self, attr_type: str, attr: str, default_value: Any = None) -> Any:
53
57
  """Retrieve attribute from json."""
@@ -60,7 +64,7 @@ class StateManager:
60
64
  def state(self) -> dict:
61
65
  """Retrieve all states."""
62
66
  return self._state
63
-
67
+
64
68
  def _save_state(self) -> None:
65
69
  with open(self._file, "w+", encoding="utf-8") as f:
66
70
  json.dump(self._state, f, indent=2)
boneio/helper/util.py CHANGED
@@ -1,4 +1,6 @@
1
1
  import unicodedata
2
+ import os
3
+ import json
2
4
  from typing import Any, Callable, TypeVar
3
5
 
4
6
  CALLABLE_T = TypeVar("CALLABLE_T", bound=Callable[..., Any])
@@ -17,5 +19,17 @@ def is_callback(func: Callable[..., Any]) -> bool:
17
19
 
18
20
 
19
21
  def strip_accents(s):
20
- return ''.join(c for c in unicodedata.normalize('NFD', s)
21
- if unicodedata.category(c) != 'Mn' and c != ' ')
22
+
23
+ return "".join(
24
+ c
25
+ for c in unicodedata.normalize("NFD", s)
26
+ if unicodedata.category(c) != "Mn" and c != " "
27
+ )
28
+
29
+
30
+ def open_json(path: str, model: str) -> dict:
31
+ """Open json file."""
32
+ file = f"{os.path.join(path)}/{model}.json"
33
+ with open(file, "r") as db_file:
34
+ datastore = json.load(db_file)
35
+ return datastore
boneio/manager.py CHANGED
@@ -74,7 +74,7 @@ from boneio.helper.loader import (
74
74
  )
75
75
  from boneio.helper.logger import configure_logger
76
76
  from boneio.helper.yaml_util import load_config_from_file
77
- from boneio.modbus import Modbus
77
+ from boneio.modbus.client import Modbus
78
78
 
79
79
  from w1thermsensor.errors import KernelModuleLoadError
80
80
 
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from .modbuscli import async_run_modbus_set
4
+
5
+ __all__ = ["async_run_modbus_set"]
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
+ import struct
5
6
  from typing import Any
6
7
 
7
8
  from pymodbus.client.sync import BaseModbusClient, ModbusSerialClient
@@ -27,6 +28,8 @@ VALUE_TYPES = {
27
28
  "U_QWORD": {"f": "decode_64bit_uint", "byteorder": Endian.Big},
28
29
  "S_QWORD": {"f": "decode_64bit_int", "byteorder": Endian.Big},
29
30
  "U_QWORD_R": {"f": "decode_64bit_uint", "byteorder": Endian.Little},
31
+ "FP32": {"f": "decode_32bit_float", "byteorder": Endian.Big},
32
+ "FP32_R": {"f": "decode_32bit_float", "byteorder": Endian.Little},
30
33
  }
31
34
 
32
35
 
@@ -73,6 +76,11 @@ class Modbus:
73
76
  except ModbusException as exception_error:
74
77
  _LOGGER.error(exception_error)
75
78
 
79
+ @property
80
+ def client(self) -> ModbusSerialClient | None:
81
+ """Return client."""
82
+ return self._client
83
+
76
84
  async def async_close(self) -> None:
77
85
  """Disconnect client."""
78
86
  async with self._lock:
@@ -94,7 +102,11 @@ class Modbus:
94
102
  return False
95
103
 
96
104
  async def read_single_register(
97
- self, unit: int, address: int, count: int = 2, method: str = "input"
105
+ self,
106
+ unit: int | str,
107
+ address: int,
108
+ count: int = 2,
109
+ method: str = "input",
98
110
  ) -> float | None:
99
111
  """Call sync. pymodbus."""
100
112
  async with self._lock:
@@ -106,7 +118,7 @@ class Modbus:
106
118
  result: ReadInputRegistersResponse = self._read_methods[method](
107
119
  address, **kwargs
108
120
  )
109
- except ModbusException as exception_error:
121
+ except (ModbusException, struct.error) as exception_error:
110
122
  _LOGGER.error(exception_error)
111
123
  return None
112
124
  if not hasattr(result, REGISTERS):
@@ -117,7 +129,11 @@ class Modbus:
117
129
  ).decode_32bit_float()
118
130
 
119
131
  async def read_multiple_registers(
120
- self, unit: int, address: int, count: int = 2, method: str = "input"
132
+ self,
133
+ unit: int | str, # device address
134
+ address: int, # modbus register address
135
+ count: int = 2, # number of registers to read
136
+ method: str = "input", # type of register: input, holding
121
137
  ) -> ModbusResponse:
122
138
  """Call sync. pymodbus."""
123
139
  async with self._lock:
boneio/modbus/cwt.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "model": "CWT Temp and Humidity sensor",
3
+ "set_base": {
4
+ "set_address_address": 2000,
5
+ "set_baudrate_address": 2001
6
+ },
7
+ "registers_base": [
8
+ {
9
+ "base": 0,
10
+ "length": 2,
11
+ "register_type": "holding",
12
+ "registers": [
13
+ {
14
+ "name": "Humidity",
15
+ "address": 0,
16
+ "unit_of_measurement": "%",
17
+ "state_class": "measurement",
18
+ "device_class": "humidity",
19
+ "value_type": "S_WORD",
20
+ "filters": [{ "multiply": 0.1 }]
21
+ },
22
+ {
23
+ "name": "Temperature",
24
+ "address": 1,
25
+ "unit_of_measurement": "°C",
26
+ "state_class": "measurement",
27
+ "device_class": "temperature",
28
+ "value_type": "S_WORD",
29
+ "filters": [{ "multiply": 0.1 }]
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,175 @@
1
+ from __future__ import annotations
2
+ import logging
3
+ import os
4
+ from ..helper.util import open_json
5
+ from boneio.const import UARTS, REGISTERS
6
+ from .client import Modbus
7
+ from .utils import REGISTERS_BASE, allowed_operations
8
+
9
+ _LOGGER = logging.getLogger(__name__)
10
+ SET_BASE = "set_base"
11
+ SET_ADDRESS = "set_address_address"
12
+ SET_BAUDRATE = "set_baudrate_address"
13
+
14
+
15
+ class ModbusHelper:
16
+ """Modbus Helper."""
17
+
18
+ baud_rates = [2400, 4800, 9600, 19200]
19
+
20
+ def __init__(
21
+ self,
22
+ device: str,
23
+ uart: str,
24
+ address: int,
25
+ baudrate: int,
26
+ model: dict,
27
+ check_record: dict,
28
+ check_record_method: str,
29
+ ) -> None:
30
+ """Initialize Modbus Helper."""
31
+ self._modbus = Modbus(
32
+ uart=UARTS[uart],
33
+ baudrate=baudrate,
34
+ stopbits=1,
35
+ bytesize=8,
36
+ parity="N",
37
+ )
38
+ self._model = model
39
+ self._device = device
40
+ self._device_address = address
41
+ self._check_record = check_record
42
+ self._check_record_method = check_record_method
43
+
44
+ async def check_connection(self) -> bool:
45
+ """Check Modbus connection."""
46
+ name = self._check_record.get("name")
47
+ address = self._check_record.get("address", 1)
48
+ value_type = self._check_record.get("value_type")
49
+ _LOGGER.info(
50
+ f"Checking connection {self._device_address}, address {address}."
51
+ )
52
+ count = 1 if value_type == "S_WORD" or value_type == "U_WORD" else 2
53
+ value = await self._modbus.read_multiple_registers(
54
+ unit=self._device_address,
55
+ address=address,
56
+ count=count,
57
+ method=self._check_record_method,
58
+ )
59
+ if not value:
60
+ _LOGGER.error("No returned value.")
61
+ return False
62
+ payload = value.registers[0:count]
63
+ decoded_value = self._modbus.decode_value(payload, value_type)
64
+ for filter in self._check_record.get("filters", []):
65
+ for key, value in filter.items():
66
+ if key in allowed_operations:
67
+ lamda_function = allowed_operations[key]
68
+ decoded_value = lamda_function(decoded_value, value)
69
+ _LOGGER.info(
70
+ f"Checked {name} with address {address} and value {decoded_value}"
71
+ )
72
+ if not decoded_value:
73
+ return False
74
+ return True
75
+
76
+ def set_connection_speed(self, new_baudrate: int):
77
+ ind = self.baud_rates.index(new_baudrate)
78
+ if ind:
79
+ result = self._modbus.client.write_register(
80
+ address=self._model[SET_BAUDRATE],
81
+ value=ind,
82
+ unit=self._device_address,
83
+ )
84
+ if result.isError():
85
+ _LOGGER.error("Operation failed.")
86
+ else:
87
+ _LOGGER.info(
88
+ "Operation succeeded. Now restart device by disconnecting it."
89
+ )
90
+
91
+ def set_new_address(self, new_address: int):
92
+ if 0 < new_address < 253:
93
+ result = self._modbus.client.write_register(
94
+ address=self._model[SET_ADDRESS],
95
+ value=new_address,
96
+ unit=self._device_address,
97
+ )
98
+ if result.isError():
99
+ _LOGGER.error("Operation failed.")
100
+ else:
101
+ _LOGGER.info(
102
+ "Operation succeeded. Now restart device by disconnecting it."
103
+ )
104
+ else:
105
+ _LOGGER.error("Invalid new address.")
106
+
107
+
108
+ async def async_run_modbus_set(
109
+ device: str,
110
+ uart: str,
111
+ address: int,
112
+ baudrate: int,
113
+ new_baudrate: int,
114
+ new_address: int,
115
+ ):
116
+ """Run Modbus Set Function."""
117
+ if new_address and new_baudrate:
118
+ _LOGGER.error("Can't set both methods new_address and new_baudrate.")
119
+ _db = open_json(path=os.path.dirname(__file__), model=device)
120
+ set_base = _db.get(SET_BASE, {})
121
+ first_reg_base = _db.get(REGISTERS_BASE, [])[0]
122
+ if not first_reg_base:
123
+ return False
124
+ first_record = first_reg_base.get(REGISTERS, [])[0]
125
+ modbus_helper = ModbusHelper(
126
+ device=device,
127
+ uart=uart,
128
+ address=address,
129
+ baudrate=baudrate,
130
+ model=set_base,
131
+ check_record=first_record,
132
+ check_record_method=first_reg_base.get("register_type", "input"),
133
+ )
134
+ if not await modbus_helper.check_connection():
135
+ _LOGGER.error("Can't connect with sensor. Exiting")
136
+ return 1
137
+ if new_baudrate:
138
+ modbus_helper.set_connection_speed(new_baudrate=new_baudrate)
139
+ return 0
140
+ if new_address:
141
+ modbus_helper.set_new_address(new_address=new_address)
142
+ return 0
143
+ return 1
144
+
145
+
146
+ async def async_run_modbus_get(
147
+ uart: str,
148
+ device_address: int,
149
+ register_address: int,
150
+ register_type: str,
151
+ baudrate: int,
152
+ value_type: str,
153
+ ):
154
+ """Run Modbus Get Function."""
155
+ _modbus = Modbus(
156
+ uart=UARTS[uart],
157
+ baudrate=baudrate,
158
+ stopbits=1,
159
+ bytesize=8,
160
+ parity="N",
161
+ )
162
+ count = 1 if value_type == "S_WORD" or value_type == "U_WORD" else 2
163
+ value = await _modbus.read_multiple_registers(
164
+ unit=device_address,
165
+ address=register_address,
166
+ count=count,
167
+ method=register_type,
168
+ )
169
+ if value:
170
+ payload = value.registers[0:count]
171
+ decoded_value = _modbus.decode_value(payload, value_type)
172
+ _LOGGER.info("Value: %s", decoded_value)
173
+ return 0
174
+ _LOGGER.error("No returned value.")
175
+ return 1
@@ -0,0 +1,20 @@
1
+ {
2
+ "model": "orno-or-we-517",
3
+ "registers_base": [
4
+ {
5
+ "base": 14,
6
+ "length": 4,
7
+ "register_type": "holding",
8
+ "registers": [
9
+ {
10
+ "name": "Napiecie_L1",
11
+ "address": 14,
12
+ "unit_of_measurement": "V",
13
+ "state_class": "measurement",
14
+ "device_class": "voltage",
15
+ "return_type": "float32"
16
+ }
17
+ ]
18
+ }
19
+ ]
20
+ }
@@ -1,11 +1,10 @@
1
1
  from __future__ import annotations
2
2
  import asyncio
3
- import json
4
3
  import logging
5
4
  import os
6
5
  from datetime import datetime
7
- from struct import unpack
8
-
6
+ from typing import Optional
7
+ from .utils import CONVERT_METHODS, REGISTERS_BASE, allowed_operations
9
8
  from boneio.const import (
10
9
  ADDRESS,
11
10
  BASE,
@@ -21,88 +20,11 @@ from boneio.helper import BasicMqtt, AsyncUpdater
21
20
  from boneio.helper.config import ConfigHelper
22
21
  from boneio.helper.events import EventBus
23
22
  from boneio.helper.ha_discovery import modbus_sensor_availabilty_message
24
- from boneio.modbus import Modbus
23
+ from .client import Modbus
24
+ from boneio.helper.util import open_json
25
25
 
26
26
  _LOGGER = logging.getLogger(__name__)
27
27
 
28
- allowed_operations = {"multiply": lambda x, y: x * y}
29
-
30
-
31
- def float32(result, base, addr):
32
- """Read Float value from register."""
33
- low = result.getRegister(addr - base)
34
- high = result.getRegister(addr - base + 1)
35
- data = bytearray(4)
36
- data[0] = high & 0xFF
37
- data[1] = high >> 8
38
- data[2] = low & 0xFF
39
- data[3] = low >> 8
40
- val = unpack("f", bytes(data))
41
- return val[0]
42
-
43
-
44
- def floatsofar(result, base, addr):
45
- """Read Float value from register."""
46
- low = result.getRegister(addr - base)
47
- high = result.getRegister(addr - base + 1)
48
- return high + low
49
-
50
-
51
- def multiply0_1(result, base, addr):
52
- low = result.getRegister(addr - base)
53
- return round(low * 0.1, 4)
54
-
55
-
56
- def multiply0_01(result, base, addr):
57
- low = result.getRegister(addr - base)
58
- return round(low * 0.01, 4)
59
-
60
-
61
- def multiply0_001(result, base, addr):
62
- low = result.getRegister(addr - base)
63
- return round(low * 0.001, 4)
64
-
65
-
66
- def multiply10(result, base, addr):
67
- low = result.getRegister(addr - base)
68
- return round(low * 10, 4)
69
-
70
-
71
- def multiply100(result, base, addr):
72
- low = result.getRegister(addr - base)
73
- return round(low * 100, 4)
74
-
75
-
76
- def multiply1000(result, base, addr):
77
- low = result.getRegister(addr - base)
78
- return round(low * 1000, 4)
79
-
80
-
81
- def regular_result(result, base, addr):
82
- return result.getRegister(addr - base)
83
-
84
-
85
- CONVERT_METHODS = {
86
- "float32": float32,
87
- "multiply0_1": multiply0_1,
88
- "multiply0_01": multiply0_01,
89
- "multiply0_001": multiply0_001,
90
- "floatsofar": floatsofar,
91
- "multiply10": multiply10,
92
- "multiply100": multiply100,
93
- "multiply1000": multiply1000,
94
- "regular": regular_result,
95
- }
96
- REGISTERS_BASE = "registers_base"
97
-
98
-
99
- def open_json(model: str) -> dict:
100
- """Open json file."""
101
- file = f"{os.path.join(os.path.dirname(__file__))}/{model}.json"
102
- with open(file, "r") as db_file:
103
- datastore = json.load(db_file)
104
- return datastore
105
-
106
28
 
107
29
  class ModbusSensor(BasicMqtt, AsyncUpdater):
108
30
  """Represent Modbus sensor in BoneIO."""
@@ -129,7 +51,7 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
129
51
  )
130
52
  self._config_helper = config_helper
131
53
  self._modbus = modbus
132
- self._db = open_json(model=model)
54
+ self._db = open_json(path=os.path.dirname(__file__), model=model)
133
55
  self._model = self._db[MODEL]
134
56
  self._address = address
135
57
  self._discovery_sent = False
@@ -164,7 +86,7 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
164
86
  )
165
87
  self._send_message(topic=topic, payload=payload)
166
88
 
167
- def _send_discovery_for_all_registers(self, register: int = 0) -> datetime:
89
+ def _send_discovery_for_all_registers(self) -> datetime:
168
90
  """Send discovery message to HA for each register."""
169
91
  for data in self._db[REGISTERS_BASE]:
170
92
  for register in data[REGISTERS]:
@@ -207,7 +129,7 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
207
129
  )
208
130
  if register is not None:
209
131
  self._discovery_sent = (
210
- self._send_discovery_for_all_registers(register)
132
+ self._send_discovery_for_all_registers()
211
133
  )
212
134
  await asyncio.sleep(2)
213
135
  break
@@ -243,10 +165,10 @@ class ModbusSensor(BasicMqtt, AsyncUpdater):
243
165
  # Let's assume device is offline.
244
166
  self.set_payload_offline()
245
167
  self._send_message(
246
- topic=f"{self._config_helper.topic_prefix}/{self._id}{STATE}",
168
+ topic=f"{self._config_helper.topic_prefix}/{self._id}aa",
247
169
  payload=self._payload_online,
248
170
  )
249
- _LOGGER.warn(
171
+ _LOGGER.warning(
250
172
  "Can't fetch data from modbus device %s. Will sleep for %s seconds",
251
173
  self.id,
252
174
  update_interval,
@@ -83,18 +83,19 @@
83
83
  {
84
84
  "name": "Total_Positive_Active_Energy",
85
85
  "address": 50946,
86
- "unit_of_measurement": "Wh",
87
- "state_class": "total_increasing",
86
+ "unit_of_measurement": "kWh",
87
+ "value_type": "U_DWORD",
88
+ "state_class": "total",
88
89
  "device_class": "energy",
89
- "return_type": "multiply0_01"
90
+ "filters": [{ "multiply": 0.01 }]
90
91
  },
91
92
  {
92
93
  "name": "Total_Negative_Active_Energy",
93
94
  "address": 50952,
94
- "unit_of_measurement": "Wh",
95
- "state_class": "total_increasing",
95
+ "unit_of_measurement": "kWh",
96
+ "state_class": "total",
96
97
  "device_class": "energy",
97
- "return_type": "multiply0_01"
98
+ "filters": [{ "multiply": 0.01 }]
98
99
  }
99
100
  ]
100
101
  }
boneio/modbus/utils.py ADDED
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+ from struct import unpack
3
+
4
+
5
+ allowed_operations = {"multiply": lambda x, y: x * y}
6
+
7
+
8
+ def float32(result, base, addr):
9
+ """Read Float value from register."""
10
+ low = result.getRegister(addr - base)
11
+ high = result.getRegister(addr - base + 1)
12
+ data = bytearray(4)
13
+ data[0] = high & 0xFF
14
+ data[1] = high >> 8
15
+ data[2] = low & 0xFF
16
+ data[3] = low >> 8
17
+ val = unpack("f", bytes(data))
18
+ return val[0]
19
+
20
+
21
+ def floatsofar(result, base, addr):
22
+ """Read Float value from register."""
23
+ low = result.getRegister(addr - base)
24
+ high = result.getRegister(addr - base + 1)
25
+ return high + low
26
+
27
+
28
+ def multiply0_1(result, base, addr):
29
+ low = result.getRegister(addr - base)
30
+ return round(low * 0.1, 4)
31
+
32
+
33
+ def multiply0_01(result, base, addr):
34
+ low = result.getRegister(addr - base)
35
+ return round(low * 0.01, 4)
36
+
37
+
38
+ def multiply0_001(result, base, addr):
39
+ low = result.getRegister(addr - base)
40
+ return round(low * 0.001, 4)
41
+
42
+
43
+ def multiply10(result, base, addr):
44
+ low = result.getRegister(addr - base)
45
+ return round(low * 10, 4)
46
+
47
+
48
+ def multiply100(result, base, addr):
49
+ low = result.getRegister(addr - base)
50
+ return round(low * 100, 4)
51
+
52
+
53
+ def multiply1000(result, base, addr):
54
+ low = result.getRegister(addr - base)
55
+ return round(low * 1000, 4)
56
+
57
+
58
+ def regular_result(result, base, addr):
59
+ return result.getRegister(addr - base)
60
+
61
+
62
+ CONVERT_METHODS = {
63
+ "float32": float32,
64
+ "multiply0_1": multiply0_1,
65
+ "multiply0_01": multiply0_01,
66
+ "multiply0_001": multiply0_001,
67
+ "floatsofar": floatsofar,
68
+ "multiply10": multiply10,
69
+ "multiply100": multiply100,
70
+ "multiply1000": multiply1000,
71
+ "regular": regular_result,
72
+ }
73
+ REGISTERS_BASE = "registers_base"
boneio/schema/schema.yaml CHANGED
@@ -154,7 +154,8 @@ modbus_sensors:
154
154
  model:
155
155
  type: string
156
156
  required: True
157
- allowed: ['sdm630', 'sdm120', 'sofar']
157
+ allowed:
158
+ ['sdm630', 'sdm120', 'sofar', 'socomec_e23', 'cwt', 'orno-or-we-517']
158
159
  meta:
159
160
  label: Model to load from database.
160
161
  update_interval:
boneio/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # flake8: noqa
2
- __version__ = "0.7.2dev4"
2
+ __version__ = "0.8.0dev2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes