Skip to content

Commit

Permalink
Feature release 2024.03.2
Browse files Browse the repository at this point in the history
  • Loading branch information
mazocode committed Mar 29, 2024
1 parent 5e41a8a commit 08f30bb
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 10 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@

## [2024.03.2] - 2024-03-29 Feature Release

- Ignore values out of range using min and max configuration option

- Specify independent control_topic for RPC commands and online state

- Use soruce name if neither control_topic nor topic_prefix as specified

- Fix wrong topic path if source topic_prefix was not specified


## [2024.03.1] - 2024-03-28 Feature Release

- Read float values from input registers
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ schema:
signed: 1 # <--- (optional) True/false for signed/unsigned value (default is 0)
divide: 1 # <--- (optional) Value to divide by before publishing (default is 1)
decimals: 0 # <--- (optional) Number of decimal places in output value (default is 0)
min: # <--- (optional) Expected minimum value (otherwise read is ignored, default is None)
max: # <--- (optional) Expected maximum value (otherwise read is ignored, default is None)
typereg: holding # <--- (optional) Read holding or input register (default is holding)
format: integer # <--- (optional) Read integer or float value (default is integer)
byteorder: big # <--- (optional) Specify the byteorder as little or big (default is big)
Expand Down Expand Up @@ -79,6 +81,8 @@ sources:
port: 502 # <--- (optional) Port your gateway is listening on (default is 502)
unitid: 1 # <--- (optional) Modbus device id to read from (default is 1)
topic_prefix: "abc" # <--- (optional) Appened after <mqtt.topic_prefix>/
control_topic: "abc" # <--- (optional) Topic to publish online state and listen to rpc messages on
Appened after <mqtt.topic_prefix>/. Dfault is name
pollms: 1000 # <--- (optional) Modbus polling interval in ms (default is 1000)
```
Expand Down
38 changes: 29 additions & 9 deletions modbus2mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ def publish(self, topic: str, value: str, retain: bool = True):
return True

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

def rpc_unsubscribe(self, src):
t = src.topic_prefix
t = src.control_topic
if self.topic_prefix is not None:
t = self.topic_prefix + '/' + t
if self.subscribers.get(t.lower() + '/rpc', None) is not None:
Expand Down Expand Up @@ -237,13 +237,15 @@ class HoldingRegister(Register):
# 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)

def __init__(self, name: str, topic: str, register: int, typereg: str = "holding", littleendian: bool = False, length: int = 1,
mode: str = "r", substract: float = 0, divide: float = 1,
mode: str = "r", substract: float = 0, divide: float = 1, min: float = None, max: float = None,
format: str = "integer", byteorder: str = "big", wordorder: str = "big",
decimals: int = 0, signed: bool = False, unitid: int = None, **kvargs):
super().__init__(name, topic, register, length, mode, unitid=unitid)
self.divide = divide
self.decimals = decimals
self.substract = substract
self.minvalue = min
self.maxvalue = max
self.signed = signed
self.typereg = typereg
self.format = "float" if format.lower() == "float" else "integer"
Expand Down Expand Up @@ -292,6 +294,9 @@ def get_value(self, src):
val = float(fmt.format((float(val) - float(self.substract)) / float(self.divide)))
else:
val = int(((float(val) - float(self.substract)) / float(self.divide)))

if (self.maxvalue and val > self.maxvalue) or (self.minvalue and val < self.minvalue):
return None
return val

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

if (self.maxvalue and val > self.maxvalue) or (self.minvalue and val < self.minvalue):
return None

return val


Expand All @@ -317,6 +325,7 @@ class ModbusSource:

def __init__(self, name: str, broker: MqttBroker, host: str, port: int,
schema: Schema, unitid: int = 1, topic_prefix: str = None,
control_topic: str = None,
pollms: int = 100, enabled: bool = True):
self.mqtt = broker
self.host = host
Expand All @@ -341,10 +350,13 @@ def __init__(self, name: str, broker: MqttBroker, host: str, port: int,
self.pollms = pollms
self.is_online = False
self.was_online = None
if topic_prefix:
self.topic_prefix = topic_prefix
self.topic_prefix = topic_prefix
if control_topic:
self.control_topic = control_topic
elif self.topic_prefix:
self.control_topic = self.topic_prefix
else:
self.topic_prefix = re.sub(r'/\s\s+/g', '_', self.name.strip().lower())
self.control_topic = re.sub(r'/\s\s+/g', '_', self.name.strip().lower())

self.mqtt.rpc_subscribe(self)

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

try:
val = r.get_value(self)
if val is None:
continue
except ModbusException as e:
log.error(f"Received exception({e}) while trying to read from modbus slave.")
self.is_online = False
Expand Down Expand Up @@ -415,7 +429,7 @@ def poller_thread(self):
finally:
try:
self.client.close()
topic = self.topic_prefix + '/online'
topic = self.control_topic + '/online'
if self.mqtt.is_connected:
self.mqtt.publish(topic, str(False).lower())
self.mqtt.rpc_unsubscribe(self)
Expand All @@ -427,7 +441,7 @@ def publish_changes(self):
return

if self.was_online is None or self.was_online != self.is_online:
topic = self.topic_prefix + '/online'
topic = self.control_topic + '/online'
if self.mqtt.publish(topic, str(True).lower()):
self.was_online = self.is_online

Expand All @@ -436,12 +450,17 @@ def publish_changes(self):
rid = id(r)
if not self.track.get(rid, False):
continue
topic = self.topic_prefix + '/' + r.topic

topic = r.topic
if self.topic_prefix:
topic = self.topic_prefix + '/' + topic

val = None
if isinstance(self.cache[rid], dict):
val = json.dumps(self.cache[rid])
else:
val = str(self.cache[rid])

if self.mqtt.publish(topic, val):
self.track[rid] = False
else:
Expand Down Expand Up @@ -500,6 +519,7 @@ def main(argv):
int(source.get("unitid", 1)),
pollms=int(source.get("pollms", 1000)),
topic_prefix=source.get("topic_prefix", None),
control_topic=source.get("control_topic", None),
enabled=bool(source.get("enabled", True))
)
)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "modbus2mqtt"
version = "2024.02.1"
version = "2024.03.1"
description = "Gateway between Modbus TCP devices and MQTT."
authors = ["Marcus Zoller <[email protected]>"]
license = "MIT"
Expand Down

0 comments on commit 08f30bb

Please sign in to comment.