Skip to content

Commit 08f30bb

Browse files
committed
Feature release 2024.03.2
1 parent 5e41a8a commit 08f30bb

File tree

4 files changed

+46
-10
lines changed

4 files changed

+46
-10
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
2+
## [2024.03.2] - 2024-03-29 Feature Release
3+
4+
- Ignore values out of range using min and max configuration option
5+
6+
- Specify independent control_topic for RPC commands and online state
7+
8+
- Use soruce name if neither control_topic nor topic_prefix as specified
9+
10+
- Fix wrong topic path if source topic_prefix was not specified
11+
12+
113
## [2024.03.1] - 2024-03-28 Feature Release
214

315
- Read float values from input registers

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ schema:
4444
signed: 1 # <--- (optional) True/false for signed/unsigned value (default is 0)
4545
divide: 1 # <--- (optional) Value to divide by before publishing (default is 1)
4646
decimals: 0 # <--- (optional) Number of decimal places in output value (default is 0)
47+
min: # <--- (optional) Expected minimum value (otherwise read is ignored, default is None)
48+
max: # <--- (optional) Expected maximum value (otherwise read is ignored, default is None)
4749
typereg: holding # <--- (optional) Read holding or input register (default is holding)
4850
format: integer # <--- (optional) Read integer or float value (default is integer)
4951
byteorder: big # <--- (optional) Specify the byteorder as little or big (default is big)
@@ -79,6 +81,8 @@ sources:
7981
port: 502 # <--- (optional) Port your gateway is listening on (default is 502)
8082
unitid: 1 # <--- (optional) Modbus device id to read from (default is 1)
8183
topic_prefix: "abc" # <--- (optional) Appened after <mqtt.topic_prefix>/
84+
control_topic: "abc" # <--- (optional) Topic to publish online state and listen to rpc messages on
85+
Appened after <mqtt.topic_prefix>/. Dfault is name
8286
pollms: 1000 # <--- (optional) Modbus polling interval in ms (default is 1000)
8387
```
8488

modbus2mqtt.py

+29-9
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ def publish(self, topic: str, value: str, retain: bool = True):
9494
return True
9595

9696
def rpc_subscribe(self, src):
97-
t = src.topic_prefix
97+
t = src.control_topic
9898
if self.topic_prefix is not None:
9999
t = self.topic_prefix + '/' + t
100100
self.subscribers[t.lower() + '/rpc'] = src
101101
log.info(f"Subscribing to rpc topic {t}/rpc.")
102102
self.client.subscribe(t + '/rpc', 0)
103103

104104
def rpc_unsubscribe(self, src):
105-
t = src.topic_prefix
105+
t = src.control_topic
106106
if self.topic_prefix is not None:
107107
t = self.topic_prefix + '/' + t
108108
if self.subscribers.get(t.lower() + '/rpc', None) is not None:
@@ -237,13 +237,15 @@ class HoldingRegister(Register):
237237
# pass the parameter "littleendian" with the value False or true (little endian) to define the endianness of the register to read. (Solax use little endian)
238238

239239
def __init__(self, name: str, topic: str, register: int, typereg: str = "holding", littleendian: bool = False, length: int = 1,
240-
mode: str = "r", substract: float = 0, divide: float = 1,
240+
mode: str = "r", substract: float = 0, divide: float = 1, min: float = None, max: float = None,
241241
format: str = "integer", byteorder: str = "big", wordorder: str = "big",
242242
decimals: int = 0, signed: bool = False, unitid: int = None, **kvargs):
243243
super().__init__(name, topic, register, length, mode, unitid=unitid)
244244
self.divide = divide
245245
self.decimals = decimals
246246
self.substract = substract
247+
self.minvalue = min
248+
self.maxvalue = max
247249
self.signed = signed
248250
self.typereg = typereg
249251
self.format = "float" if format.lower() == "float" else "integer"
@@ -292,6 +294,9 @@ def get_value(self, src):
292294
val = float(fmt.format((float(val) - float(self.substract)) / float(self.divide)))
293295
else:
294296
val = int(((float(val) - float(self.substract)) / float(self.divide)))
297+
298+
if (self.maxvalue and val > self.maxvalue) or (self.minvalue and val < self.minvalue):
299+
return None
295300
return val
296301

297302
if self.signed and int(val) >= 32768:
@@ -303,6 +308,9 @@ def get_value(self, src):
303308
else:
304309
val = int(((int(val) - float(self.substract)) / float(self.divide)))
305310

311+
if (self.maxvalue and val > self.maxvalue) or (self.minvalue and val < self.minvalue):
312+
return None
313+
306314
return val
307315

308316

@@ -317,6 +325,7 @@ class ModbusSource:
317325

318326
def __init__(self, name: str, broker: MqttBroker, host: str, port: int,
319327
schema: Schema, unitid: int = 1, topic_prefix: str = None,
328+
control_topic: str = None,
320329
pollms: int = 100, enabled: bool = True):
321330
self.mqtt = broker
322331
self.host = host
@@ -341,10 +350,13 @@ def __init__(self, name: str, broker: MqttBroker, host: str, port: int,
341350
self.pollms = pollms
342351
self.is_online = False
343352
self.was_online = None
344-
if topic_prefix:
345-
self.topic_prefix = topic_prefix
353+
self.topic_prefix = topic_prefix
354+
if control_topic:
355+
self.control_topic = control_topic
356+
elif self.topic_prefix:
357+
self.control_topic = self.topic_prefix
346358
else:
347-
self.topic_prefix = re.sub(r'/\s\s+/g', '_', self.name.strip().lower())
359+
self.control_topic = re.sub(r'/\s\s+/g', '_', self.name.strip().lower())
348360

349361
self.mqtt.rpc_subscribe(self)
350362

@@ -370,6 +382,8 @@ def poller_thread(self):
370382

371383
try:
372384
val = r.get_value(self)
385+
if val is None:
386+
continue
373387
except ModbusException as e:
374388
log.error(f"Received exception({e}) while trying to read from modbus slave.")
375389
self.is_online = False
@@ -415,7 +429,7 @@ def poller_thread(self):
415429
finally:
416430
try:
417431
self.client.close()
418-
topic = self.topic_prefix + '/online'
432+
topic = self.control_topic + '/online'
419433
if self.mqtt.is_connected:
420434
self.mqtt.publish(topic, str(False).lower())
421435
self.mqtt.rpc_unsubscribe(self)
@@ -427,7 +441,7 @@ def publish_changes(self):
427441
return
428442

429443
if self.was_online is None or self.was_online != self.is_online:
430-
topic = self.topic_prefix + '/online'
444+
topic = self.control_topic + '/online'
431445
if self.mqtt.publish(topic, str(True).lower()):
432446
self.was_online = self.is_online
433447

@@ -436,12 +450,17 @@ def publish_changes(self):
436450
rid = id(r)
437451
if not self.track.get(rid, False):
438452
continue
439-
topic = self.topic_prefix + '/' + r.topic
453+
454+
topic = r.topic
455+
if self.topic_prefix:
456+
topic = self.topic_prefix + '/' + topic
457+
440458
val = None
441459
if isinstance(self.cache[rid], dict):
442460
val = json.dumps(self.cache[rid])
443461
else:
444462
val = str(self.cache[rid])
463+
445464
if self.mqtt.publish(topic, val):
446465
self.track[rid] = False
447466
else:
@@ -500,6 +519,7 @@ def main(argv):
500519
int(source.get("unitid", 1)),
501520
pollms=int(source.get("pollms", 1000)),
502521
topic_prefix=source.get("topic_prefix", None),
522+
control_topic=source.get("control_topic", None),
503523
enabled=bool(source.get("enabled", True))
504524
)
505525
)

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "modbus2mqtt"
3-
version = "2024.02.1"
3+
version = "2024.03.1"
44
description = "Gateway between Modbus TCP devices and MQTT."
55
authors = ["Marcus Zoller <mazocode@users.noreply.github.com>"]
66
license = "MIT"

0 commit comments

Comments
 (0)