Skip to content

Commit

Permalink
Feature release 2024.03.1
Browse files Browse the repository at this point in the history
  • Loading branch information
mazocode committed Mar 29, 2024
1 parent 51fa1f8 commit bc9c1ce
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 7 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## [2024.03.1] - 2024-03-28 Feature Release

- Read float values from input registers

- Specify byte- and wordorder

- Eastron example

## [2024.02.1] - 2024-02-28 Feature Release

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ schema:
substract: 0 # <--- (optional) Value to substract before publishing (default is 0)
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)
typereg: holding # <--- (optional) Read holding or input register (default is holding)
littleendian: 0 # <--- (optional) Byte order (default is 0)
format: integer # <--- (optional) Read integer or float value (default is integer)
byteorder: big # <--- (optional) Specify the byteorder as little or big (default is big)
wordorder: big # <--- (optional) Wordorder (if length > 2) as little or big (default is big)
littleendian: 0 # <--- (optional) Shortcut for byteorder and wordorder as little if true

# Coils

Expand Down
65 changes: 65 additions & 0 deletions examples/eastron_sdm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
mqtt:
host: "mqtt.broker"
port: 1883
tls: false
username: "username"
password: "password"

schema:
- name: eastron
readings:
- name: "Voltage"
topic: "meter/voltage"
unitid: 14
register: 0
length: 2
signed: 0
divide: 1
decimals: 2
format: float
byteorder: big
wordorder: big
typereg: input
- name: "Power"
topic: "meter/power"
unitid: 14
register: 12
length: 2
signed: 0
divide: 1
decimals: 2
format: float
byteorder: big
wordorder: big
typereg: input
- name: "Current"
topic: "meter/current"
unitid: 14
register: 6
length: 2
signed: 1
divide: 1
decimals: 2
format: float
byteorder: big
wordorder: big
typereg: input
- name: "Frequency"
topic: "meter/frequency"
unitid: 14
register: 70
length: 2
signed: 1
divide: 1
decimals: 2
format: float
byteorder: big
wordorder: big
typereg: input
sources:
- name: "plc1"
host: "10.128.25.199"
port: 502
pollms: 1000
schema: eastron
topic_prefix: "room"
36 changes: 36 additions & 0 deletions examples/sht20.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
mqtt:
host: "mqtt.broker"
port: 1883
tls: false
username: "username"
password: "password"

schema:
- name: sensors
readings:
- name: "Temperature (SHT20)"
topic: "temperature"
unitid: 12
register: 1
length: 1
signed: 1
divide: 10.0
decimals: 1
typereg: input
- name: "Humidity (SHT20)"
topic: "humidity"
unitid: 12
register: 2
length: 1
signed: 1
divide: 10.0
decimals: 1
typereg: input

sources:
- name: "plc1"
host: "10.128.25.199"
port: 502
pollms: 1000
schema: sensors
topic_prefix: "room"
32 changes: 26 additions & 6 deletions modbus2mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
from pymodbus.client import ModbusTcpClient
from pymodbus.exceptions import ModbusException
from pymodbus.pdu import ExceptionResponse
# from pymodbus.constants import Endian
# from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.transaction import ModbusSocketFramer
from paho.mqtt import client as mqtt_client

Expand Down Expand Up @@ -237,21 +238,25 @@ 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,
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.signed = signed
self.typereg = typereg
self.littleendian = littleendian
self.format = "float" if format.lower() == "float" else "integer"
self.byteorder = Endian.LITTLE if (byteorder.lower() == "little" or littleendian) else Endian.BIG
self.wordorder = Endian.LITTLE if (wordorder.lower() == "little" or littleendian) else Endian.BIG
self.littleendian = True if (littleendian or (byteorder.lower() == "little" and wordorder.lower() == "little")) else False

def get_value(self, src):
unitid = self.unitid
if unitid is None:
unitid = src.unitid
if (self.typereg == "holding"):
if (self.typereg.lower() == "holding"):
rr = src.client.read_holding_registers(self.start, self.length, slave=unitid)
else:
rr = src.client.read_input_registers(self.start, self.length, slave=unitid)
Expand All @@ -262,13 +267,18 @@ def get_value(self, src):
if isinstance(rr, ExceptionResponse):
raise ModbusException(f"Received Modbus library exception ({rr}).")

if ((self.littleendian)):
if (self.format == "float"):
decoder = BinaryPayloadDecoder.fromRegisters(rr.registers, self.byteorder, wordorder=self.wordorder)
val = decoder.decode_32bit_float()

elif (self.littleendian):
# Read multiple bytes in little endian mode
h = ""
for i in range(0, self.length):
h = hex(rr.registers[i]).split('x')[-1].zfill(4) + h
log.debug(f"Got Value {h} from {self.typereg} register {self.start} with length {self.length} from unit {unitid} in little endian mode.")
val = int(h, 16)

else:
# Read multiple bytes in big endian mode
h = ""
Expand All @@ -277,13 +287,23 @@ def get_value(self, src):
log.debug(f"Got Value {h} from {self.typereg} register {self.start} with length {self.length} from unit {unitid} in big endian mode.")
val = int(h, 16)

if self.format == "float":
if self.decimals > 0:
fmt = '{0:.' + str(self.decimals) + 'f}'
val = float(fmt.format((float(val) - float(self.substract)) / float(self.divide)))
else:
val = int(((float(val) - float(self.substract)) / float(self.divide)))
return val

if self.signed and int(val) >= 32768:
val = int(val) - 65535

if self.decimals > 0:
fmt = '{0:.' + str(self.decimals) + 'f}'
val = float(fmt.format((int(val) - float(self.substract)) / float(self.divide)))
else:
val = int(((int(val) - float(self.substract)) / float(self.divide)))

return val


Expand Down

0 comments on commit bc9c1ce

Please sign in to comment.