Skip to content

Commit 106f930

Browse files
committed
Add some goof-proofing on the scan_batching setting.
1 parent 38ec4d1 commit 106f930

5 files changed

Lines changed: 30 additions & 7 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ scan_batching: 100
5050

5151
`variant` (Optional) Allows variants of the ModbusTcpClient library to be used. Setting this to 'sungrow' enables support of SungrowModbusTcpClient. This library transparently decrypts the modbus comms with sungrow SH inverters running newer firmware versions.
5252

53-
`scan_batching` (Optional: default 100) Modbus read operations are more efficient in bigger batches of contiguous registers, but different devices have different limits on the size of the batched reads. This setting can also be helpful when building a modbus register map for an uncharted device. In some modbus devices a single invalid register in a read range will fail the entire read operation. By setting `scan_batching` to `1` each register will be scanned individually. This will be very inefficient and should not be used in production as it will saturate the link with many read operations.
53+
`scan_batching` (Optional: default 100) Must be between 1 and 100 inclusive. Modbus read operations are more efficient in bigger batches of contiguous registers, but different devices have different limits on the size of the batched reads. This setting can also be helpful when building a modbus register map for an uncharted device. In some modbus devices a single invalid register in a read range will fail the entire read operation. By setting `scan_batching` to `1` each register will be scanned individually. This will be very inefficient and should not be used in production as it will saturate the link with many read operations.
5454

5555
```yaml
5656
registers:

modbus4mqtt/modbus_interface.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
DEFAULT_SCAN_RATE_S = 5
99
DEFAULT_SCAN_BATCHING = 100
10+
MIN_SCAN_BATCHING = 1
11+
MAX_SCAN_BATCHING = 100
1012
DEFAULT_WRITE_BLOCK_INTERVAL_S = 0.2
1113
DEFAULT_WRITE_SLEEP_S = 0.05
1214
DEFAULT_READ_SLEEP_S = 0.05
@@ -26,10 +28,16 @@ def __init__(self, ip, port=502, update_rate_s=DEFAULT_SCAN_RATE_S, variant=None
2628
self._planned_writes = Queue()
2729
self._writing = False
2830
self._variant = variant
29-
if scan_batching is None:
30-
self._scan_batching = DEFAULT_SCAN_BATCHING
31-
elif 1 <= scan_batching <= 100:
32-
self._scan_batching = scan_batching
31+
self._scan_batching = DEFAULT_SCAN_BATCHING
32+
if scan_batching is not None:
33+
if scan_batching < MIN_SCAN_BATCHING:
34+
logging.warning("Bad value for scan_batching: {}. Enforcing minimum value of {}".format(scan_batching, MIN_SCAN_BATCHING))
35+
self._scan_batching = MIN_SCAN_BATCHING
36+
elif scan_batching > MAX_SCAN_BATCHING:
37+
logging.warning("Bad value for scan_batching: {}. Enforcing maximum value of {}".format(scan_batching, MAX_SCAN_BATCHING))
38+
self._scan_batching = MAX_SCAN_BATCHING
39+
else:
40+
self._scan_batching = scan_batching
3341

3442
def connect(self):
3543
# Connects to the modbus device

package_and_upload.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
rm ./dist/modbus4mqtt*.whl
33
rm ./dist/modbus4mqtt*.tar.gz
44
python3 setup.py sdist bdist_wheel
5-
python3 -m twine upload dist/*
5+
python3 -m twine upload dist/*

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="modbus4mqtt",
8-
version="0.3.2",
8+
version="0.3.3",
99
author="Travis Howse",
1010
author_email="tjhowse@gmail.com",
1111
description="A YAML-defined bidirectional Modbus to MQTT interface",

tests/test_modbus.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,18 @@ def test_scan_batching_of_one(self):
195195
mock_modbus().read_holding_registers.assert_any_call(6, 1, unit=1)
196196
mock_modbus().read_input_registers.assert_any_call(6, 1, unit=1)
197197
mock_modbus().read_input_registers.assert_any_call(7, 1, unit=1)
198+
199+
def test_scan_batching_bad_value(self):
200+
with patch('modbus4mqtt.modbus_interface.ModbusTcpClient') as mock_modbus:
201+
with self.assertLogs() as mock_logger:
202+
mock_modbus().connect.side_effect = self.connect_success
203+
mock_modbus().read_input_registers.side_effect = self.read_input_registers
204+
mock_modbus().read_holding_registers.side_effect = self.read_holding_registers
205+
206+
bad_scan_batching = 101
207+
modbus_interface.modbus_interface('1.1.1.1', 111, 2, scan_batching=bad_scan_batching)
208+
self.assertIn("Bad value for scan_batching: {}. Enforcing maximum value of {}".format(bad_scan_batching, modbus_interface.MAX_SCAN_BATCHING), mock_logger.output[-1])
209+
210+
bad_scan_batching = 0
211+
modbus_interface.modbus_interface('1.1.1.1', 111, 2, scan_batching=bad_scan_batching)
212+
self.assertIn("Bad value for scan_batching: {}. Enforcing minimum value of {}".format(bad_scan_batching, modbus_interface.MIN_SCAN_BATCHING), mock_logger.output[-1])

0 commit comments

Comments
 (0)