Doubts with Modbus

Hello All,

Where can I find the types of Modbus Register Tables supported by OpenEMS?
I’m very new to using energy management systems and some googling says there are Coils, Discrete Inputs, Input Registers and Holding Registers used to store data. But nothing on the OpenEMS side about what is used and how.

I have read some of the other implementations for the ModbusProtocol, and have a few questions:

  1. What are the different FC tasks?
  2. In some implementations, the starting address is hardcoded, while others use this.offset.apply(0). What is the difference and which is the better practise?
  3. How do you pick the start address. Or is it the device ID?
  4. What is the ModBusSlaveNatureTable and why do some of the implementations use it?

Assuming we have an OpenEMS Edge instance running and some physical devices available in the network, how do the two communicate via the Modbus protocol implementation?
The implement device tutorial isn’t really helping. I have tried reading some implementations but I’m afraid there’s no documentation to understand what is going on.

Any links, resources or additional material would be very helpful.

Warm Regards,

Hi,

for some basic knowledge about how Modbus works, I recommend the Simply Modbus page. They also describe the different function codes (FC) there:

In general I recommend hardcoding the starting address. But there are advanced cases when the Modbus protocol is generated dynamically - e.g. for SunSpec compliant devices or dynamic number of battery modules in a tower.

The Device-, Slave- or Modbus-Unit-ID is different from a start address. Modbus addresses are defined in modbus tables by the device manufacturer. For example see the Modbus table by SOCOMEC and its implementation in OpenEMS.

OpenEMS Edge supports two variants of Modbus.

  • If you use Bridge.Modbus.Serial or Bridge.Modbus.Tcp, OpenEMS is a Modbus Slave, i.e. it reads data from other devices, like a meter.
  • If you use Controller.Api.ModbusTcp.ReadWrite or Controller.Api.ModbusTcp.ReadOnly, OpenEMS is a Modbus Master, i.e. another Modbus Slave can read data registers from OpenEMS Edge. The registers that OpenEMS supplies, are defined via ModbusSlaveNatureTables.

I hope Simply Modbus and other general documentation available on the internet can clarify your doubts. Modbus in general is a uni-directional communication protocol, i.e. one side opens up a connection (via TCP/IP or RS485-bus) and polls data e.g. once per second. When OpenEMS Edge receives data via Modbus, it is then writing the data into “Channels” so they are available throughout OpenEMS e.g. for Controllers or visualisation in OpenEMS UI.

Regards,
Stefan

Hello Stefan,

Just wanted to update here. Thank you for the links! They were very helpful.

Best,

1 Like

Hi @stefan.feilmeier ,
I got a doubt from your clarifications :sweat_smile:.

OpenEMS Edge supports two variants of Modbus.

  • If you use Bridge.Modbus.Serial or Bridge.Modbus.Tcp, OpenEMS is a Modbus Slave, i.e. it reads data from other devices, like a meter.

  • If you use Controller.Api.ModbusTcp.ReadWrite or Controller.Api.ModbusTcp.ReadOnly, OpenEMS is a Modbus Master, i.e. another Modbus Slave can read data registers from OpenEMS Edge. The registers that OpenEMS supplies, are defined via ModbusSlaveNatureTables.

What I understand is Controller.Api.ModbusTcp.ReadWrite makes OpenEMS a Mosbus Slave/Server and Bridge.Modbus.Tcp/Serial makes it a Modbus Master.

So, Controller.Api.ModbusTcp.ReadWrite gives a list of register addresses that a Modbus Master/Client device can read and can also write to it in order to lets say control Active Power.

Could you help me resolve this confusion please?

P.S.: I was having trouble communicating to two openems instances both running Modbus TCP servers simultaneously on different devices. I configured a unique unit ID for each of them and was able to communicate to each of them once at a time but not both together. I was using a RTU master to query from these devices using a modbus TCP to RTU bridge and I think it was causing bus conflicts because the id check was happening after the converter in openems. So, both the converters werer trying to respond to the request sent from the Modbus RTU Master.
I then realized, that Controller.Modbus.Api.Rtu has been implemented by the team and that can also be used. Will try that now and hopefully the issue will get resolved. This clarification of yours will help me realize the architecture better.

Thanks

Best Regards
Hafiz

Your understanding is correct.

I was having trouble communicating to two openems instances both running Modbus TCP servers simultaneously on different devices. I configured a unique unit ID for each of them and was able to communicate to each of them once at a time but not both together.

Controller.Api.ModbusTcp.ReadWrite defaults to Unit-ID 1, because it is usually not relevant. The Server is already uniquely identified by the IP-Address of the host and the configured port.

If that does not work with your TCP-to-RTU-converter, you could try changing the default Unit-ID here: openems/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusApi.java at develop · OpenEMS/openems · GitHub

Indeed, if you need Modbus/RTU and you have the required physical RS485 hardware (or use a USB-adapter), you can directly use Controller.Api.ModbusRtu.ReadWrite. I am curious to receive your feedback on that, because we have not used and tested it extensively yet.

1 Like

Hi Stefan,
Acutally for now, I used a modbus tcp to rtu bridge as this was needed to be done quick.
Will surely share feedback when I use the new RTU API.

Thanks for the quick response!

Have a good day!