Skip to content

Commit

Permalink
Allow reading Modbus TCP holding registers from multiple units
Browse files Browse the repository at this point in the history
This adds a configuration setting of nUnit that allows specifying a Modbus TCP unit ID.
If it is ommitted, it defaults to the previous behavior of passing '1' as the unit to read_holding_registers().

Solaredge inverters can communicate with each other using a proprietary protocol (see https://github.com/jbuehl/solaredge) over RS485.
When connecting to an inverter over Modbus TCP, you can read holding registers for any RS485 networked inverter by changing the unit ID.
You do not need to connect to the inverter that is the RS485 master, any inverter with Modbus TCP enabled can be used.
Unit 1 will be the RS485 master, regardless of which inverter you have connected to.

```
[[ModbusTCP]]
        Type = EmonModbusTcpInterfacer
        [[[init_settings]]]
            modbus_IP = 192.168.1.10    # ip address of client to retrieve data from
            modbus_port = 502                # Portclient listens on
        [[[runtimesettings]]]
            # The model registers are strings and are not passed to the node, they're just here to confirm the inverter in the emonhub log
            rName = SE7600_Model, SE7600_AC_Power, SE10000_Model, SE10000_AC_Power
            register = 40021, 40084, 40021, 40084
            nReg = 16,1,16,1
            rType = string, uint16, string, uint16
            nUnit = 1,1,2,2
            nodeId = 11
            pubchannels = ToEmonCMS,
            interval = 5
```
  • Loading branch information
btm committed Dec 26, 2017
1 parent 001120d commit d1fd8c2
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/interfacers/EmonModbusTcpInterfacer.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,24 @@ def read(self):
registerList = self._settings["register"]
nRegList = self._settings["nReg"]
rTypeList = self._settings["rType"]
if "nUnit" in self._settings:
nUnitList = self._settings["nUnit"]
else:
nUnitList = None

for idx, rName in enumerate(rNameList):
register = int(registerList[idx])
qty = int(nRegList[idx])
rType = rTypeList[idx]
self._log.debug("register # : " + str(register))
if nUnitList is not None:
unitId = int(nUnitList[idx])
else:
unitId = 1

self._log.debug("register # :" + str(register) + ", qty #: " + str(qty) + ", unit #: " + str(unitId))

try:
self.rVal = self._con.read_holding_registers(register-1,qty,unit=1)
self.rVal = self._con.read_holding_registers(register-1,qty,unit=unitId)
assert(self.rVal.function_code < 0x80)
except Exception as e:
self._log.error("Connection failed on read of register: " +str(register) + " : " + str(e))
Expand Down Expand Up @@ -119,6 +128,7 @@ def read(self):
f = f + list(t)
elif rType == "string":
rValD = decoder.decode_string(qty*2)
t = rValD
elif rType == "float32":
rValD = decoder.decode_32bit_float()*10
t = emonhub_coder.encode('f',rValD)
Expand Down

0 comments on commit d1fd8c2

Please sign in to comment.