The Modbus protocol has been around forever (since 1979 to be exact) and is used by many industrial systems, but also energy systems like heat pumps and solar converters. Initially it was used via serial communications, then – in 2007 – a TCP based version was created that communicates via TCP, usually using port 502.
The following article explains how Modbus/TCP works and shows how I can monitor Modbus/TCP enabled devices with PRTG Network Monitor using a simple PowerShell script.
I wish I could share a one-size-fits-all script that just works for most people. But unfortunately this task usually requires some hacking and coding…
What makes Modbus special
The Modbus protocol allows a client to request numeric values from a device using a TCP request. The data is organized in numbered “registers” and the data format is almost crude.
Compared to many other (more sophisticated) communication standards the Modbus/TCP standard stands out for several reasons:
- It is simple and has an almost microscopic bandwidth usage: a usual data request only consists of two handful of bytes sent and about two or three handful of bytes received. Here is a sample communication trace:
- It has no authentication: If I can access the TCP port 502 of a device over the network I can read (and write!) device data using Modbus which does make it a potential security challenge
- It has no encryption
- The standard is quite lax: The vendors can define the format of the returned data as they wish, so it is the receiver’s problem to adapt to the data format.
The last fact makes it hard for monitoring systems to digest the data in a standardized way. The original protocol only allows 16-bit integers. But many vendors encode the data as word, or int16, or uint16, or uint32, or unit64, or float, or string, etc., often mixing the formats as it fits the data. Some vendors send the high byte first, other the low byte. Some vendors send the high word first, other the low word.
Sometimes the vendor documentations are not very exact and it can require some “hacking” and guessing to find out what that stream of bytes actually means. And after successfully interpreting the byte code it may still be necessary to finally process the data further. E.g. sometimes a value of 37.2 is transferred as 372 and you are expected to divide that by 10 before using it.
Interpreting Modbus data can be a mess
This mess makes it necessary for the receiver of the data to surrender to the vendors’ will. In PRTG this means that most of the time I have to write a specific script for each device so I can translate the data for PRTG individually for each device(-type).
I need the following things to set up Modbus monitoring:
- The documentation from the vendor
- Access to the device (for hacking/experimentation)
- An interactive Modbus software
- A script editor and a demo script to start with
- And some time
Let’s get started
I started with the free QModMaster software (SourceForge download). First I clicked on the Ethernet icon and entered the Slave IP address of my device (502 is the standard port for Modbus):
Then I …
- selected the Modbus Mode “TCP”
- entered the Slave Address (you get this from the device, some devices even ignore it)
- Selected the Function Code as “Read Input Registers (0x04)”
- Entered a value for Start Address (from vendor documentation)
- Selected the Number of Registers I want to read (again from vendor documentation)
In this screenshot I read the battery charge level from my solar battery, which is 26%. OK, that wasn’t actually so hard.
Short Note: Some vendors start numbering their registers at 1, others start with number 40001 (which was the initial start address in the protocol). One vendor showed the number 1 in the documentation which I had to convert into 40001+1 to actually make it work.
Interpreting the data
The next register I wanted to access was a counter for the total energy produced by my solar panels. This value is stored as 32-bit integer in the two 16-bit registers #30529 and #30530.
I got $00c1 and $6022 which as int32 translates to 12.673.058 or 12.673 MWh, which I could compare to the data by the solar system itself.
Yes, this work is ugly… I did this for all the metrics I wanted to get from the device the I was ready to…
Write a monitoring script for PRTG
In the Windows Powershell ISE I can edit and test the script:
Please look at the following aspects when you edit the script for your needs:
- You may need to set the “Unit ID” (line 17 of the script, this is set in the device’s settings)
- You may need to adapt the data processing and conversion (modbusread() function)
- You must set the IP address
- For each metric you must add and edit one of the lines with the function calls to onedataset()
Adding Metrics to the script
You can add/rename metrics in these code lines:
The parameters of the onedataset function() are:
- name: The name of the metric (which is shown in PRTG’s UI)
- theid: the number of the modbus register
- unit: The unit string (which is shown in PRTG’s UI, e.g. °C, W, Byte)
- divider: A number the metric needs to be divided by
- type: This can be “Absolute” (for most metrics, uses the value as it is) or “Difference” (for counters, PRTG calculates the difference to the previous sensor value and displays it on a “per time” basis, e.g. bytes/sec, see PRTG’s documentation)
- signed: Must be “signed” if the metric is a signed int32, otherwise the registers’ data will be interpreted as unsigned int32.
When I run this script in the IDE I get:
==== Power from PV ====
Reading Register #30775
Received int= -260
==== Solar Energy Total ====
Reading Register #30529
Received uint= 12673058
==== Solar Energy Today ====
Reading Register #30535
Received uint= 6896
And the output sent to PRTG a XML is:
Finally I needed to copy the script file Modbus Sample Script.ps1 into the folder
C:\Program Files\PRTG Network Monitor\Custom Sensors\EXEXML
and I set the Execution Policy properly. In PRTG’s UI I set up a EXE/Script Advanced Sensor
and I am finished.
Finally, here is my script, feel free to use and adapt it for your needs (the code is also available on GitHub: https://github.com/dirkpaessler/sensors_for_prtg):
I found the following links helpful for this work:
- Code on Github: https://github.com/dirkpaessler/sensors_for_prtg
- QModMaster Software: https://sourceforge.net/projects/qmodmaster/
- Modbus for Field Technicians: http://www.modbusbacnet.com/includes/pdf/MODBUS_2010Nov12.pdf
- “Simply Modbus” documentation: http://www.simplymodbus.ca/TCP.htm
- Pluggit Monitoring for PRTG (my script is based on this script): https://www.msxfaq.de/tools/prtg/prtg-pluggit.htm