Tag Archive: modbus

http://cloutieronline.net/

The JNIOR is used in a variety of industries. Here the JNIOR is used in a clean energy solution, a residential Solar installation. This solar installation went live in the evening of July 7th, 2022. This is the second solar installation for this owner. The previous installation generated power for over a decade. It is still in operation but for a new owner.

How?

The JNIOR is tasked with communicating with the four inverters to collect the amount of power that they produce. Once every 10 seconds the application on the JNIOR sequentially communicates with each inverter to request the current power, daily yield and total yield. The communication is done via MODBUS TCP. Once the data is read, it is tucked away in 2 locations as individual reading and totalized. The data is stored in the registry as a system key that is used for real-time reporting. The data is also stored in a readings.dat log file. This file is moved to the flash filesystem at the end of every day for historical analysis. Only the previous 7 days are maintained in the flash filesystem. The files are numbered by the day of the week to ensure that Sunday overwrites last Sunday, Monday overwrites last Monday and so on.

The real-time data is served from the registry using a php script that generates a JSON format.  That JSON response is requested and consumed by a linux server that is responsible for collecting and storing that data in a MYSQL database for long term storage.

Why?

Fun!Ā  While the data can be used to check that the power company is paying you for the kWhs generated beyond what is consumed by the house, this page is generally watched as a sort of game to see how days throughout the year stack up against each other.

MODBUS client is not able to connect to the JNIOR

The MODBUS server running on the JNIOR is a separate application from the Operating System. It does not run by default when the JNIOR is shipped. It is installed by default. It must be activated by the end user before the the MODBUS connection can be successful.

To activate it go to the DCP, click on the Configuration tab. Half way down the left side click on Applications. You will see a list of applications that are loaded on the JNIOR. Check the box next to Modbus Server. This will tell the JNIOR to run the application when the JNIOR boots up. You will need to reboot the JNIOR at this point to get the MODBUS Server to start.

To verify that the MODBUS server is running we can list the listening network sockets using the netstat command.

Lastly, you can change a few configuration parameters for the MODBUS server under the registry tab.

Port 502 is the default MODBUS port. Most likely this will NOT need to be changed. The Timeout setting is the number of milliseconds to wait for a MODBUS client to poll the server. If a request is not made within this amount of time then the JNIOR will close the connection. If any configuration needs to be changed it will probably be the Login setting. Not very many MODBUS clients implement a login. If they dont log in then you will see the following in the Modbus Server log…

Setting the Login key to false will allow this device to connect successfully.

This sample requires that the MODBUS Server is running.

This sample is meant to show you how to gain access to the MODBUS scratch memory space. You can see in theĀ MODBUS manualĀ that the MODBUS addressing assigns a “scratch” address space starting at WORD 256.

Modbus Registry Bit Address Ranges

Since WORDs are 2 bytes we know that the starting address is going to be 512. We can gain access to the “scratch” area by opening theĀ Modbus00Ā immutable block. TheĀ Modbus00Ā immutable block does not exist until the MODBUS server has been started on the unit at least once in its lifetime. You can use theĀ nvĀ command to discover whether theĀ Modbus00Ā block exists or not.

If theĀ Modbus00Ā block does not exist then execute the MODBUS Server. Once the MODBUS Server has been executed theĀ Modbus00Ā will exist.

The immutable example shown in theĀ Immutable ClassĀ example uses an array of long values. We will use a byte array in this example.

package modbussample;  
  
import com.integpg.system.ArrayUtils;  
import com.integpg.system.Immutable;  
  
  
  
public class ModbusSample {  
  
    public static void main(String[] args) throws InterruptedException {  
        // open the Modbus00 immutable block  
        System.out.println("Open the MODBUS Store");  
        byte[] modbusStore = Immutable.getByteArray("Modbus00");  
  
        // if the block does not exist then alert the user and exit.  it is not our responsibility to create it  
        if (modbusStore == null) {  
            System.out.println("MODBUS store has not been created.  Please run the MODBUS Server application.");  
            System.exit(0);  
        }  
  
  
        // the modbus store must exist.  loop so that external changes by a client are seen by our application  
        while (true) {  
            // get and print the first 4 WORDs in our scratch area  
            short[] value = new short[]{  
                ArrayUtils.getShort(modbusStore, 512),  
                ArrayUtils.getShort(modbusStore, 514),  
                ArrayUtils.getShort(modbusStore, 516),  
                ArrayUtils.getShort(modbusStore, 518)  
            };  
            System.out.println("WORDs @0256: " + value[0] + ", " + value[1] + ", " + value[2] + ", " + value[3]);  
  
  
            // get and print the first 8 bytes that represent the first 4 WORDs in our scratch area  
            byte[] b = new byte[8];  
            ArrayUtils.arraycopy(modbusStore, 512, b, 0, b.length);  
            System.out.println("bytes @0512: " + hexDump(b, 0, b.length));  
  
  
            // sleep a little before checking again  
            Thread.sleep(1000);  
        }  
    }  
  
  
  
    public static String hexDump(byte[] bytes, int offset, int length) {  
        StringBuffer sb = new StringBuffer();  
        StringBuffer chars = new StringBuffer();  
  
        int i;  
        for (i = offset; i  
                < length; i++) { if (i % 16 == 0) { if (chars.length() > 0) {  
                    sb.append("  ");  
                    sb.append(chars.toString());  
                    chars  
                            = new StringBuffer();  
                    sb.append("\r\n");  
                }  
  
            } else if (i % 16 == 8) {  
                chars.append(" ");  
                sb.append("  ");  
            }  
  
            if (bytes[i] >= 32) {  
                chars.append((char) bytes[i]);  
            } else {  
                chars.append('.');  
            }  
  
            int p = sb.length();  
            sb.append(Integer.toHexString((bytes[i] & 0xff) / 16));  
            sb.append(Integer.toHexString((bytes[i] & 0xff) % 16));  
            sb.append(" ");  
        }  
  
        int mod = i % 16;  
        if (mod != 0) {  
            if (mod <= 8) { sb.append(" "); } for (i = 16 - (mod); i > 0; i--) {  
                sb.append("   ");  
            }  
  
            sb.append("  ");  
            sb.append(chars.toString());  
        }  
  
        return sb.toString();  
    }  
  
}  

Here is some sample output from our application. We used a PC MODBUS client to adjust the values of the registers in the MODBUS scratch address space. You can see the values changing during the execution of our application.