Skip to content

Modbus Support

Modbus is an alternative data communication protocol commonly used by certain pieces of equipment like electric meters. Unlike BACnet, it has very limited support for complex data types or automatic discovery; generally, a device profile is required in order to interpret the data from a Modbus device.

A device profile specifies the data type for each Modbus register as well as provides a useful name. Each device is integrated with a connection, which pairs a device address and unit ID with a profile. NF ships a library of built-in profiles and can discover devices and match them to a profile automatically; for other devices, you can create your own profile.

Auto-discovery

3.10.11

On Modbus > Connections, click Auto-detect and enter the hosts to scan: IP addresses or hostnames, ranges (10.0.1.10-40) or subnets (10.0.2.0/24), up to 1024 addresses in total. Choose the transport (Modbus TCP, or RTU over TCP for devices behind a transparent serial gateway), the port (default 502), the per-request timeout, and the range of unit IDs to probe on each host. Devices connected directly over TCP usually use unit 1; behind a serial gateway, scan 1--247 (each absent unit costs up to two timeouts).

Discovery only reads from devices. Each host and unit ID that answers is identified using Read Device Identification (FC43), Report Server ID (FC17), the SunSpec common model, or vendor signature registers, and matched to a profile. NF then reads a preview of the matched profile's registers and checks them for plausibility (for example, that line frequency is between 45 and 65 Hz). Each device is shown with one of:

Match Meaning
Matched A profile matched and the preview looks plausible. Selected for import by default.
Check values A profile matched but the preview failed a plausibility check, or the match is inferred rather than documented by the vendor. The reason is shown; if the preview looks right, select the device, otherwise pick another profile.
No profile matched The device answers Modbus but wasn't recognized. Pick a profile and check the preview.

You can change the profile for any device; the preview is re-read with the chosen profile. Devices that already have a connection are marked Already configured and can't be selected. Edit the connection names if needed, optionally choose a site, and click Import selected to create a connection for each selected device.

Discovery is also available through the Modbus API (StartDiscovery, GetDiscovery, CancelDiscovery; normalgw.modbus.v1), and PreviewDevice reads a profile's registers from a device once without creating a connection.

Built-in Profiles

3.10.11

NF includes built-in profiles for common meters, drives, boilers, VRF gateways, PDUs, I/O modules and sensors; they are listed on Modbus > Profiles with a Built-in badge and, where the vendor publishes one, a link to the register map. Built-in profiles can't be deleted or overwritten; Duplicate makes a custom copy.

Built-in meter profiles use the same point names and units for the same quantity on every meter, e.g. voltage_an (V), current_a (A), power_real_total (kW), power_factor_total, frequency (Hz) and energy_real_import (kWh). Points are read-only measurements; the profiles don't include configuration or command registers.

SunSpec

SunSpec devices (inverters, meters and other DER equipment) need no library entry. When discovery finds a SunSpec device, it reads the device's model chain and generates a profile containing every read-only numeric point of its models, with SunSpec scale factors and not-implemented values handled automatically. The generated profile is saved as a regular (not built-in) profile, and the same kind of device rediscovered reuses it.

Creating a Modbus Profile

A device profile contains a list of register addresses along with data types and associated human-readable names for these registers. Profiles may be created directly using the Modbus API, or imported from a csv file using Import Profile on Modbus > Profiles or nfcli.

A profile is simply a CSV file with the required columns, as shown below. Additionally, some configuration variables such as the endianness may be set in the header.

# this file is named skylogger.csv
# uuid: d4a12bx8-03a9-11ed-a97c-a30ea19188b1
# profileName: 170321_skytron_ModbusList
# endianness: ENDIAN_BIG
# highWordFirst: true
Register Type,Name,Address,Data Type,Units
3,Temp. Channel 1 "Module temperature",10,FLOAT32,°C
3,Temp. Channel 2 "Ambient temperature",12,FLOAT32,°C
3,Radiation Channel 1,20,FLOAT32,W/m2
3,Radiation yield Channel 1,22,FLOAT32,Wh/m2
$ nfcli create-modbus-profile skylogger.csv

Once the profile has been created, you may create a connection to it; you can also see the currently installed profiles using nfcli list-modbus-profiles.

Devices usually come with documentation including the modbus register map for your device. You may also be able to fine one someone else has created and convert it to this format; for instance, Contemporary Controls publishes many maps in a similar format.

Connecting to a Modbus device

Once you have created a profile for device, you must create a connection for each instance of a device.

$ nfcli create-modbus-connection -p d4a12bb8-03a9-11ed-a97c-a30ea19188b1 -a tcp://192.168.103.190:502 -n "test"

In this example, the UUID must be the ID of a profile you have importted; and the url string is the address of the Modbus device. You may also provide a human readable name to help identify the connection.

Profile Format

A profile file consists of two sections: a header with commented lines; and a body consisting of a list of registers. The header allows configuration of several device parameters. Although the profiles are usually loaded to and from CSV files, the format is defined by CreateDeviceProfile.

Header parameter Description
uuid A uuid to uniquely identify this profile
profileName A user-friendly name for the profile
endianness The endianness to use when converting registers. Either ENDIAN_BIG (default) or ENDIAN_LITTLE.
highWordFirst When converting types which span multiple registers, if the first register contains the high word. Default true; or false

The body consists of a header, followed by zero or more registers. The possible column headers are:

Header Name Description
Register Type The type of modbus register: 1 (coil), 2 (discrete), 3 (holding), or 4 (input) register
Data Type The data type of the register data. Valid values are: INT16, UINT16, UINT32, INT32, FLOAT32, FLOAT64. Note that conversion for raw registers are controlled by the endianness and highWordFirst parameters in the header.
Address The Modbus register index
Scale Factor A floating-point scale factor to multiple the raw register value by. Default 1.0.
Offset An offset value to add to the raw value, after the scale factor has been applied. Default 0.0
Name A string providing a user-visible name for the register
Units A string containing an non-normalized units name.

Scale Registers and Not-available Values

3.10.11

Some devices keep a register's scale in another register that can change at runtime (a SunSpec scale factor, or a meter's scale exponent), or use a reserved raw value to mean "no reading". A register in a profile may set:

  • scale_registers -- one or more registers read with the value on every poll. Each is SCALE_POWER_OF_TEN (multiply by 10^raw, the default) or SCALE_MULTIPLY (multiply by raw), may use only some of the register's bits (bit_offset, bit_width) and may be negated (negate). Their multipliers are applied together, before the static scale factor and offset.
  • not_available -- raw values that mean "not available", compared before any scaling. Matching readings (and NaN floats) are reported as point errors instead of values.

These fields are set through the API; the CSV format doesn't carry them, so exporting such a profile to CSV and importing it again drops them. To customize one, fetch it with GetDeviceProfiles (content=true), edit it, and save it under a new UUID with CreateDeviceProfile.

Writing to Modbus Points

Coils and holding registers are writable; writes to input registers and discrete inputs fail. Coils accept only 0 or 1 (or a boolean). For holding registers, the profile's scale factor and offset are reversed before writing, integer values are rounded to the nearest integer, and a value outside the register's data type range (or NaN or infinity) fails instead of being written. Registers with a scale register are read-only; writes to them fail.