Reading data from OB737-CT via Modbus TCP Interfacer

I have installed the changes @bwduncan has made to EmonModbusTcpInterfacer.py.

Sys log: syslog.txt (1.6 KB)

emonHub logs below with various options tried, none have been successful unfortuantely.

Settings:

[[ModbusTCP]]     
    # this interfacer retrieves register information from modbusTCP clients 
    Type = EmonModbusTcpInterfacer
    [[[init_settings]]]
        modbus_IP = 192.168.1.60   # ip address of client to retrieve data from
        modbus_port = 9999        # Portclient listens on
    [[[runtimesettings]]]
        # List of starting registers for items listed above
        register = 16,18
        # nodeid used to match with node definition in nodes section below. Can be set to any integer value not previously used.
        nodeId = 9334
        # Channel to publish data to should leave as ToEmonCMS
        pubchannels = ToEmonCMS,
        # time in seconds between checks, This is in addition to emonhub_interfacer.run() sleep time of .01
        # use this value to set the frequency of data retrieval from modbus client
        interval = 10      

[[9334]]
    nodename = USR
    [[[rx]]]
        names = Voltage L1,Voltage L1
        datacodes = i,i
        scales = 0.1,0.1
        units = V,V

Log:

2021-03-27 16:09:24,680 INFO     ModbusTCP  Not connected, retrying connect 
{'modbus_IP': '192.168.1.60', 'modbus_port': '9999'}
2021-03-27 16:09:24,682 INFO     ModbusTCP  Opening modbusTCP connection: 9999 @ 
192.168.1.60
2021-03-27 16:09:24,683 DEBUG    ModbusTCP  expected bytes number after encoding: 
8
2021-03-27 16:09:24,684 DEBUG    ModbusTCP  datacode i
2021-03-27 16:09:24,684 DEBUG    ModbusTCP  reading register #: 16, qty #: 2, unit #: 1
2021-03-27 16:09:24,749 ERROR    ModbusTCP  Connection failed on read of register: 16 :

Settings:

[[ModbusTCP]]     
    # this interfacer retrieves register information from modbusTCP clients 
    Type = EmonModbusTcpInterfacer
    [[[init_settings]]]
        modbus_IP = 192.168.1.60   # ip address of client to retrieve data from
        modbus_port = 9999        # Portclient listens on
    [[[runtimesettings]]]
        # List of starting registers for items listed above
        register = 0x0010,0x0012
        # nodeid used to match with node definition in nodes section below. Can be set to any 
integer value not previously used.
        nodeId = 9334
        # Channel to publish data to should leave as ToEmonCMS
        pubchannels = ToEmonCMS,
        # time in seconds between checks, This is in addition to emonhub_interfacer.run() 
sleep time of .01
        # use this value to set the frequency of data retrieval from modbus client
        interval = 10              

[[9334]]
    nodename = USR
    [[[rx]]]
        names = Voltage L1,Voltage L1
        datacodes = i,i
        scales = 0.1,0.1
        units = V,V

Log:

2021-03-27 16:16:20,400 WARNING  MainThread ModbusTCP thread is dead.
2021-03-27 16:16:20,401 WARNING  MainThread Attempting to restart thread 
ModbusTCP (thread has been restarted 1 times...)
2021-03-27 16:16:20,402 INFO     MainThread Creating EmonModbusTcpInterfacer 
'ModbusTCP'
2021-03-27 16:16:20,403 INFO     MainThread pymodbus installed
2021-03-27 16:16:20,404 DEBUG    MainThread EmonModbusTcpInterfacer args: 
192.168.1.60 - 9999
2021-03-27 16:16:20,406 INFO     MainThread Opening modbusTCP connection: 9999 @ 
192.168.1.60
2021-03-27 16:16:20,406 INFO     MainThread Modbustcp client Connected
2021-03-27 16:16:20,407 DEBUG    MainThread Setting ModbusTCP register: ['0x0010', 
'0x0012']
2021-03-27 16:16:20,408 DEBUG    MainThread Setting ModbusTCP nodeId: 9334
2021-03-27 16:16:20,408 DEBUG    MainThread Setting ModbusTCP pubchannels: 
['ToEmonCMS']
2021-03-27 16:16:20,409 DEBUG    MainThread Setting ModbusTCP interval: 10
2021-03-27 16:16:30,419 DEBUG    ModbusTCP  expected bytes number after encoding: 
 8
 2021-03-27 16:16:30,421 WARNING  ModbusTCP  Exception caught in ModbusTCP 
 thread. Traceback (most recent call last):
File "/opt/openenergymonitor/emonhub/src/emonhub_interfacer.py", line 32, in wrapper
return func(*args)
File "/opt/openenergymonitor/emonhub/src/emonhub_interfacer.py", line 99, in run
rxc = self.read()
File "/opt/openenergymonitor/emonhub/src/interfacers/EmonModbusTcpInterfacer.py", line 
154, in read
register = int(registers[idx])
ValueError: invalid literal for int() with base 10: '0x0010'

Settings:

[[ModbusTCP]]     
    # this interfacer retrieves register information from modbusTCP clients 
    Type = EmonModbusTcpInterfacer
    [[[init_settings]]]
        modbus_IP = 192.168.1.60   # ip address of client to retrieve data from
        modbus_port = 9999        # Portclient listens on
    [[[runtimesettings]]]
        # List of starting registers for items listed above
        register = 10,12
        # nodeid used to match with node definition in nodes section below. Can be set to any 
integer value not previously used.
        nodeId = 9334
        # Channel to publish data to should leave as ToEmonCMS
        pubchannels = ToEmonCMS,
        # time in seconds between checks, This is in addition to emonhub_interfacer.run() 
sleep time of .01
        # use this value to set the frequency of data retrieval from modbus client
        interval = 10 
[[9334]]
    nodename = USR
    [[[rx]]]
        names = Voltage L1,Voltage L1
        datacodes = i,i
        scales = 0.1,0.1
        units = V,V

Log:

2021-03-27 16:26:38,243 INFO     MainThread Creating EmonModbusTcpInterfacer 
'ModbusTCP'
2021-03-27 16:26:38,244 INFO     MainThread pymodbus installed
2021-03-27 16:26:38,245 DEBUG    MainThread EmonModbusTcpInterfacer args:         
192.168.1.60 - 9999
2021-03-27 16:26:38,247 INFO     MainThread Opening modbusTCP connection: 9999 @     
192.168.1.60
2021-03-27 16:26:38,248 INFO     MainThread Modbustcp client Connected
2021-03-27 16:26:38,249 DEBUG    MainThread Setting ModbusTCP register: ['10', '12']
2021-03-27 16:26:38,249 DEBUG    MainThread Setting ModbusTCP nodeId: 9334
2021-03-27 16:26:38,250 DEBUG    MainThread Setting ModbusTCP pubchannels:         
 ['ToEmonCMS']
2021-03-27 16:26:38,250 DEBUG    MainThread Setting ModbusTCP interval: 10
2021-03-27 16:26:38,251 INFO     MainThread Creating EmonHubMqttInterfacer 'MQTT'
2021-03-27 16:26:38,254 DEBUG    MainThread Setting MQTT pubchannels: ['ToRFM12']
2021-03-27 16:26:38,255 DEBUG    MainThread Setting MQTT subchannels: 
 ['ToEmonCMS']
2021-03-27 16:26:38,255 INFO     MainThread Setting MQTT node_format_enable: 1
2021-03-27 16:26:38,256 INFO     MainThread Setting MQTT nodevar_format_enable: 1
2021-03-27 16:26:38,256 INFO     MainThread Setting MQTT nodevar_format_basetopic: 
 emon/
2021-03-27 16:26:38,258 INFO     MainThread Creating     
  EmonHubEmoncmsHTTPInterfacer 'emoncmsorg'
2021-03-27 16:26:38,259 DEBUG    MainThread Setting emoncmsorg pubchannels:     
  ['ToRFM12']
2021-03-27 16:26:38,259 DEBUG    MainThread Setting emoncmsorg subchannels: 
 ['ToEmonCMS']
2021-03-27 16:26:38,260 WARNING  MainThread Setting emoncmsorg apikey: obscured
2021-03-27 16:26:38,260 INFO     MainThread Setting emoncmsorg url: 
 https://emoncms.org
2021-03-27 16:26:38,261 INFO     MainThread Setting emoncmsorg senddata: 1
2021-03-27 16:26:38,261 INFO     MainThread Setting emoncmsorg sendstatus: 1
2021-03-27 16:26:48,253 DEBUG    ModbusTCP  expected bytes number after encoding: 
 8
2021-03-27 16:26:48,254 DEBUG    ModbusTCP  datacode i
2021-03-27 16:26:48,254 DEBUG    ModbusTCP  reading register #: 10, qty #: 2, unit #: 1
2021-03-27 16:26:48,325 ERROR    ModbusTCP  Connection failed on read of register: 10 : 
2021-03-27 16:26:58,437 INFO     ModbusTCP  Not connected, retrying connect     
  {'modbus_IP': '192.168.1.60', 'modbus_port': '9999'}
2021-03-27 16:26:58,439 INFO     ModbusTCP  Opening modbusTCP connection: 9999 @ 
 192.168.1.60
2021-03-27 16:26:58,440 DEBUG    ModbusTCP  expected bytes number after encoding: 
 8
2021-03-27 16:26:58,441 DEBUG    ModbusTCP  datacode i
2021-03-27 16:26:58,441 DEBUG    ModbusTCP  reading register #: 10, qty #: 2, unit #: 1
2021-03-27 16:26:58,515 ERROR    ModbusTCP  Connection failed on read of register: 10 

After each change in the settings (in the emonhub.conf file) I have restarted the emonHub service before capturing the log files.

I have also tried chnaging the function in EmonModbusTcpInterfacer.py to read the

read_input_registers()

and changed the config in the .conf file datatype to f from i as per the guidance in the original pdf but see similar errors in the logs.

[[9334]]
    nodename = USR
    [[[rx]]]
        names = Voltage L1,Voltage L1
        datacodes = f,f
        scales = 0.1,0.1
        units = V,V

Any ideas what I need to do next please? Thank you.

I have also tried using Transparent mode on the USR device:

image

Log:

2021-03-27 17:17:16,860 INFO     ModbusTCP  Opening modbusTCP connection: 9999 @ 
192.168.1.60
2021-03-27 17:17:16,861 DEBUG    ModbusTCP  expected bytes number after encoding: 
8
2021-03-27 17:17:16,861 DEBUG    ModbusTCP  datacode i
2021-03-27 17:17:16,862 DEBUG    ModbusTCP  reading register #: 16, qty #: 2, unit #: 1
2021-03-27 17:17:19,867 ERROR    ModbusTCP  Connection failed on read of register: 16 
: 'ModbusIOException' object has no attribute 'function_code'

My previous post has the data mode like this:

image

Which i think is required as EmonModbusTcpInterfacer.py does not use:

from pymodbus.transaction import ModbusRtuFramer as ModbusFramer

I am absolutely no expert here but…

I presume you got the register number from the PDF

image

Note the register is 0010 HEX not decimal.The code looks like emonhub uses a decimal register number.

also, further along on the PDF row, it suggests the register is a float not an integer.

Don’t ask me how that decoding is done by emonhub though :laughing:

[edit] - Oh I see you tried 16 first time. I should stick to what I know…

1 Like

Don’t think it is an issue yet, but the names are both the same - L1

1 Like

It seems like you must be the only person using this module, since it appears quite broken… Also the name EmonModbusTcpInterfacer.py has annoyed me for years. It should be EmonHubModbusTcpInterfacer.py… Apart from the fact that “EmonHub” and “Interfacter” are redundant in the emonhub/src/interfacers directory :laughing: but still: consistency.

Once again, an overly broad except Exception swallows the error message… On line 170, please can you change self._log.error to self._log.exception and run it again? It will still fail but hopefully with a useful traceback this time.

1 Like

It is in use here TCP interfacer not running?

[edit]
I will also note that the config of that is different, using different config items like rName.

2 Likes

Using the power of reading the logs more closely after sending a reply I noticed this:

'ModbusIOException' object has no attribute 'function_code'

I think this means that read_holding_registers returned an error (it doesn’t raise an exception, it returns an error object, which we presumably should be checking for. Using the power of Google I found this rather daunting thread:

I’m happy to help solve this issue but without the hardware it could be a slow process… You in?

2 Likes

Then my inner pedant will just have to suffer for longer…

2 Likes

Thank you very much. In for a penny, in for a pound right? I am happy to open ports up to your ip if that would help?

Some info from the meter manufacturer which may be helpful:

“”“class EmonModbusTcpInterfacer
Monitors Modbus devices using modbus tcp
At this stage, only read_holding_registers() is implemented in the read() method
if needed, please change the function to read_input_registers()
“””

the meter returns requests as per the following:

holding registers (function code 3) Return = HEX
(the software should decode to 32bit_int then you need to adjust for decimal point.)

Input registers (function Code 4) Return = 32bit_float.

in their decoder they are multiplying it then by 10??? see below
rValD = decoder.decode_32bit_float() * 10

this should not be required for float. But may need to /10 or /100 or /1000 for 32bit(int) to resolve decimal point.

Edit:

Hex Dec Function Code Data Format Emon Datacode Function Code Data Format Emon Datacode Units Name
10 16 04 Float f 03 Hex i V Voltage L1
12 18 04 Float f 03 Hex i V Voltage L2
14 20 04 Float f 03 Hex i V Voltage L3
4E 78 04 Float f 03 Hex i Hz Frequency
50 80 04 Float f 03 Hex i A Current L1
52 82 04 Float f 03 Hex i A Current L2
54 84 04 Float f 03 Hex i A Current L3
56 86 04 Float f 03 Hex i A Current Neutral
58 88 04 Float f 03 Hex i A Current Total
90 144 04 Float f 03 Hex i kW Power L1
92 146 04 Float f 03 Hex i kW Power L2
94 148 04 Float f 03 Hex i kW Power L3
96 150 04 Float f 03 Hex i kW Power Total
D0 208 04 Float f 03 Hex i kVA Apparent Power L1
D2 210 04 Float f 03 Hex i kVA Apparent Power L2
D4 212 04 Float f 03 Hex i kVA Apparent Power L3
D6 214 04 Float f 03 Hex i kVA Apparent Power Total
110 272 04 Float f 03 Hex i kvar Reactive Power L1
112 274 04 Float f 03 Hex i kvar Reactive Power L2
114 276 04 Float f 03 Hex i kvar Reactive Power L3
116 278 04 Float f 03 Hex i kvar Reactive Power Total
150 336 04 Float f 03 Hex i Power Factor L1
152 338 04 Float f 03 Hex i Power Factor L2
154 340 04 Float f 03 Hex i Power Factor L3
156 342 04 Float f 03 Hex i Power Factor Total
160 352 04 Float f 03 Hex i KWh Import Active Energy
162 354 04 Float f 03 Hex i KWh Import Reactive Energy
166 358 04 Float f 03 Hex i KWh Export Active Energy
168 360 04 Float f 03 Hex i KWh Export Reactive Energy
618 1560 04 Float f 03 Hex i KWh Total Energy
800 2048 04 Float f KWh Import Active Energy
900 2304 04 Float f KWh Export Active Energy
700 1792 04 Float f KWh Total Active Energy
A00 2560 04 Float f Kvarh Import Reactive Energy
B00 2816 04 Float f Kvarh Export Active Energy
524 1316 04 Float f 06 16 bit Modbus slave address number
525 1317 04 Float f 06 16 bit Modbus slave Baud rate
read_input_registers() read_holding_registers() Hex is auto converted to 32 bit integer?

As they are so helpful, do they have any example scripts?

As a slight aside, there is a Telegraf plugin for ModBus telegraf/plugins/inputs/modbus/README.md at release-1.18 · influxdata/telegraf · GitHub. Since @Bill.Thomson pointed me this way, I have had quite good success with using Telegraf. It will then output the data received via MQTT so easily then passed to emoncms with no need for InfluxDB.

1 Like

I have asked them :slight_smile:

I have made some progress, see log:

2021-03-28 11:48:22,765 INFO     MainThread Exit completed
    2021-03-28 11:49:39,263 INFO     MainThread EmonHub emonHub (emon-pi variant) v2.1.5
    2021-03-28 11:49:39,264 INFO     MainThread Opening hub...
    2021-03-28 11:49:39,265 INFO     MainThread Logging level set to DEBUG
    2021-03-28 11:49:39,265 INFO     MainThread Creating EmonHubJeeInterfacer 'RFM2Pi'
    2021-03-28 11:49:39,266 DEBUG    MainThread Opening serial port: /dev/ttyAMA0 @ 38400 bits/s
    2021-03-28 11:49:41,269 WARNING  MainThread Device communication error - check settings
    2021-03-28 11:49:41,270 INFO     MainThread Setting RFM2Pi baseid: 5 (5i)
    2021-03-28 11:49:42,664 INFO     MainThread EmonHub emonHub (emon-pi variant) v2.1.5
    2021-03-28 11:49:42,664 INFO     MainThread Opening hub...
    2021-03-28 11:49:42,665 INFO     MainThread Logging level set to DEBUG
    2021-03-28 11:49:42,665 INFO     MainThread Creating EmonHubJeeInterfacer 'RFM2Pi'
    2021-03-28 11:49:42,667 DEBUG    MainThread Opening serial port: /dev/ttyAMA0 @ 38400 bits/s
    2021-03-28 11:49:44,669 WARNING  MainThread Device communication error - check settings
    2021-03-28 11:49:44,670 INFO     MainThread Setting RFM2Pi baseid: 5 (5i)
    2021-03-28 11:49:45,672 INFO     MainThread Setting RFM2Pi frequency: 433 (4b)
    2021-03-28 11:49:46,674 INFO     MainThread Setting RFM2Pi group: 210 (210g)
    2021-03-28 11:49:47,676 INFO     MainThread Setting RFM2Pi quiet: 1 (1q)
    2021-03-28 11:49:48,678 INFO     MainThread Setting RFM2Pi calibration: 230V (1p)
    2021-03-28 11:49:49,680 DEBUG    MainThread Setting RFM2Pi pubchannels: ['ToEmonCMS']
    2021-03-28 11:49:49,681 DEBUG    MainThread Setting RFM2Pi subchannels: ['ToRFM12']
    2021-03-28 11:49:49,682 INFO     MainThread Creating EmonModbusTcpInterfacer 'ModbusTCP'
    2021-03-28 11:49:49,683 INFO     MainThread pymodbus installed
    2021-03-28 11:49:49,684 DEBUG    MainThread EmonModbusTcpInterfacer args: 192.168.1.60 - 9999
    2021-03-28 11:49:49,686 INFO     MainThread Opening modbusTCP connection: 9999 @ 192.168.1.60
    2021-03-28 11:49:49,686 INFO     MainThread Modbustcp client Connected
    2021-03-28 11:49:49,687 DEBUG    MainThread Setting ModbusTCP register: ['10', '12', '14']
    2021-03-28 11:49:49,687 DEBUG    MainThread Setting ModbusTCP nodeId: 9334
    2021-03-28 11:49:49,688 DEBUG    MainThread Setting ModbusTCP pubchannels: ['ToEmonCMS']
    2021-03-28 11:49:49,688 DEBUG    MainThread Setting ModbusTCP interval: 10
    2021-03-28 11:49:49,689 INFO     MainThread Creating EmonHubMqttInterfacer 'MQTT'
    2021-03-28 11:49:49,691 DEBUG    MainThread Setting MQTT pubchannels: ['ToRFM12']
    2021-03-28 11:49:49,692 DEBUG    MainThread Setting MQTT subchannels: ['ToEmonCMS']
    2021-03-28 11:49:49,692 INFO     MainThread Setting MQTT node_format_enable: 1
    2021-03-28 11:49:49,693 INFO     MainThread Setting MQTT nodevar_format_enable: 1
    2021-03-28 11:49:49,693 INFO     MainThread Setting MQTT nodevar_format_basetopic: emon/
    2021-03-28 11:49:49,694 INFO     MainThread Creating EmonHubEmoncmsHTTPInterfacer 'emoncmsorg'
    2021-03-28 11:49:49,695 DEBUG    MainThread Setting emoncmsorg pubchannels: ['ToRFM12']
    2021-03-28 11:49:49,696 DEBUG    MainThread Setting emoncmsorg subchannels: ['ToEmonCMS']
    2021-03-28 11:49:49,696 WARNING  MainThread Setting emoncmsorg apikey: obscured
    2021-03-28 11:49:49,696 INFO     MainThread Setting emoncmsorg url: https://emoncms.org
    2021-03-28 11:49:49,697 INFO     MainThread Setting emoncmsorg senddata: 1
    2021-03-28 11:49:49,697 INFO     MainThread Setting emoncmsorg sendstatus: 1
    2021-03-28 11:49:59,700 DEBUG    ModbusTCP  expected bytes number after encoding: 12
    2021-03-28 11:49:59,700 DEBUG    ModbusTCP  datacode f
    2021-03-28 11:49:59,701 DEBUG    ModbusTCP  reading register #: 10, qty #: 2, unit #: 1
    2021-03-28 11:49:59,771 DEBUG    ModbusTCP  Encoded value: (45, 206, 21, 69)
    **2021-03-28 11:49:59,772 DEBUG    ModbusTCP  value: 2396.885986328125**
    2021-03-28 11:49:59,773 DEBUG    ModbusTCP  datacode f

In order to get it to read this value I have had to specify the register address manually in hex, and enable the:

from pymodbus.transaction import ModbusRtuFramer as ModbusFramer

Here’s a link to the code: emonhub/src/interfacers/EmonModbusTcpInterfacer.py at master · snerd9334/emonhub · GitHub

@bwduncan are we able to make a change somewhere to allow the emonhub.conf file to pass hex values instead of integers?

Progress update.

I have been able to use hex values in the emonhub.conf file and have the interfacer use them. It will read the first two values, but not the third. Or if there are only two values listed, it will read the first one and not the second…

I have managed to get this working. Link to code: emonhub/EmonModbusTcpInterfacer.py at master · snerd9334/emonhub · GitHub

Not sure if you want me to do a pull request?

Don’t forget to update pymodbus:

pip install -U pymodbus

Example config:

[[ModbusTCP]]     
    # this interfacer retrieves register information from modbusTCP clients 
    Type = EmonModbusTcpInterfacer
    [[[init_settings]]]
        modbus_IP = 192.168.1.60   # ip address of client to retrieve data from
        modbus_port = 9999        # Portclient listens on
    [[[runtimesettings]]]
        # List of starting registers for items listed above
        register = 0x0010,0x0012,0x0014,0x004E
        # nodeid used to match with node definition in nodes section below. Can be set to any integer value not previously used.
        nodeId = 9334
        # Channel to publish data to should leave as ToEmonCMS
        pubchannels = ToEmonCMS,
        # time in seconds between checks, This is in addition to emonhub_interfacer.run() sleep time of .01
        # use this value to set the frequency of data retrieval from modbus client
        interval = 10     

[[9334]]
        nodename = USR
        [[[rx]]]
            names = Voltage L1,Voltage L2,Voltage L3,Frequency
            datacodes = f,f,f,f
            scales = 0.1,0.1,0.1,0.1
            units = V,V,V,Hz

Ensure you have UART Autoframe enabled:

image

Good work! Yes please make a PR, there a couple of things we can tidy up there.

The previous code was looking for register - 1. Your code isn’t doing the subtraction. This will break existing installations, if there are any…

I don’t know what a framer does. Will this also break deployed installations?

Hi Bruce,

The inclusion of the framer will break existing installations that are expecting the TCP server to be performing the Modbus TCP <=> Modbus RTU confusingly called in the industry (or so it would seem) TCPIP.

I’m sure the register -1 for people using integers and not hex values in their emonhub.conf file would also cause a problem.

Perhaps this would be better as a ‘new’ interfacer for Modbus RTU over IP which is what it seems to be called when using the framer?

OK, we can probably make one interfacer do both jobs. It would be a tremendous about of duplication to create another one with these small changes. The hardest part will be thinking of a good name :laughing: Something that is obvious from the setup menu of the device would be good.

Hex values are also integers. I’m not sure why specifying a decimal value would require you to subtract one from it. Can you enlighten me?

Sounds like a plan. :sweat_smile: so it would seem! Could we include a boolean in the config file for the choice between using the framer or not?

I wish I could, but I couldn’t understand why it was subtracting 1 either. Initially, I thought this was for it to process the loop (limited python knowledge) but eventually realised it had nothing to do with that.

Just a thought but if using python3 this should be pip3 - not sure if it does make any difference.

The other thing is that the installer pulls this in from Debian rather pip. Installing from both locations can cause problems IIRC.

1 Like

@snerd9334 @bwduncan : I do use this module a lot and happy to see yu get it work
Yes you need to make register-1 and it was a design choice of the original github author @cjthuys
It was originally coded like that because some manufacturers do +1

as mentionned by @borpin, pymodbus is now installed via apt and from my side, the apt package works fine

1 Like