Read from serial modbus device

I am trying to read from a serial modbus device. The modbus device was installed and connected to a Pi in my fleet that is not readily accessible. So I am trying to do this via the ssh console in BalenaCloud. Not ideal, but that’s what I have to deal with. (And it is not working.)

There is a lot of fuzziness in my understanding of the elements presented below. Is there anything else that I should be looking at here? Any help is appreciated.

Device dev path

The device is connected via USB with a modbus/USB convertor. It is connected on /dev/ttyACM0. At least, I think this is true. I was able to deduce this by running a script like this one on the Host OS, which yielded something like the following when run :

/dev/ttyACM0 - Exar_Corp._XR21B1411_Q0499556051

When I run that script from within my container, I am not able to get that device information, though the /dev/ttyACM0 device still appears to be present.

Reading from the device

When I try the following Node.js script (from my running container), I am unable to read a value. (The timeout kicks in.)

const ModbusRTU = require('modbus-serial');
const client = new ModbusRTU();
client.setTimeout(10000);
const run = async () => {
  await client.connectRTUBuffered('/dev/ttyACM0', { baudRate: 115200 });
  const opened = await client.open();
  const v = await client.readInputRegisters(0x3100,6);
  console.info('value:', v);
};

run();

I realize that there could be some issue with my code. (I am using this as a model for my application, without a lot of supporting information or experience with the modbus-serial library.) But the code does seem to connect and open before getting hung up on the “read” command.

Balena Device configuration

I tried to enable Serial by toggling the “Enable / Disable UART” option in “Device Configuration” in BalenaCloud for the device, which I assume is the same as doing what it is described in this documentation. But I did not notice any difference and am not clear that it is needed for this case.

Hi eczajkowski, I have a setup like yours working. In my case I had to run it in privileged mode since I wanted to support plugging and unplugging multiple USB to Serial converters. In your case you can give your container access to just that device (/dev/ttyACM0) since this is a more secure approach. You can read more in this link: https://www.balena.io/docs/learn/develop/hardware/

The link that you posted is about enabling the internal UART to be used for the serial port on the GPIO, if my memory doesn’t fail me, this UART can be used for the internal Bluetooth OR the internal serial port. The configuration mentioned would enable the use of the UART for the internal serial port.

Hope it helps!

1 Like

Thanks @gmerciel.

I should mention that my testing has been done with a single-container application in classic mode.

So, my understanding is that the application is already running in priveliged mode, with access to /dev interfaces.

The internal UART, as mentioned, isn’t for anything USB related. I would follow the guidance of @gmerciel above also. Do you have a known-good working setup outside of balenaOS prior to confirm it isn’t something container-related and that your code is indeed good? Just some ideas :+1:

1 Like

Did you make it work? If not, can you paste the logs you get from the container? Also, you could try to ssh into the container and see if the device path exists.

Still not working, but I am looking into another issue related to the hardware.

When I run lsusb from the container, I get:

> lsusb
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 004: ID 04e2:1411 Exar Corp. 
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Device 004 is my device.

I would suggest trying with a different converter, I have succesfully used converters based on CH340 (amazon link) and CP210X chips (amazon link). Also, in this post they seemed to find a solution for that particular converter.

Hope it helps :slight_smile:

Thanks. I thought I had arrived at an understanding that this is basically a driver issue. So I tried remotely installing the driver, but was still was not able to read from the device.

I tried to install by downloading the drivers to the device and using the method suggested in the kernel-module-build repo, with help from this thread. When I use lsmod, I see my driver:

> lsmod
Module                  Size  Used by
xr_usb_serial_common    40960  0

But I still have the same issue when I try to read from my device using my script from my original post. Maybe there is something else I am missing (very possible).

@gmerciel has it been your experience that you need to install drivers for CH340 or CP210X? Or are these already present because they are so common? Pardon my ignorance.

I can confirm neither of the converters required installing drivers to work with balenaOS.

What are you getting from the script that shows you the USB devices attached you mentioned on your first post? Also, check the permission on the /dev/ttyxxxx file, it could be lacking write permissions (you may need to perform a “sudo chmod 777 /dev/ttyxxxx”)

I tried to change permission, but no change. lsusb shows the same result.

The readme for the driver says the following for AFTER the driver is installed:

* Plug the device into the USB host.  You should see up to four devices created,
  typically /dev/ttyXRUSB[0-3].

But, I am not physically near the device right now. So I cannot unplug/plug in the USB. And I do not see the ttyXRUSB[0-3] devices currently.

In any case, we will try with one of the devices you mention, which should hopefully simplify things greatly.

Thanks for your help.

So we have replaced the USB converter to use this one. I am still having trouble reading from the device, but have made some progress, I think.

I had not previously enabled udevd, which I have now done by setting the UDEV env variable to 1 (link). Note that I am still running a single-container project, so I do not believe the “privileged” setting applies to me. Also note that I rebooted the device after setting the env var.

Now, if I run a script such as this one, I actually get useful information about the serial port, whereas this information was previously available only from host (but not from within the container):

/dev/ttyUSB0 - 1a86_USB2.0-Serial

So that helps. But reading from the device still does not work. I still get timeout issues from the JavaScript library I mentioned earlier. And if I try this Python script (borrowed from this site), I get an “incomplete message received” error:

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
client = ModbusClient(method = 'rtu', port = '/dev/ttyUSB0', baudrate = 115200)
client.connect()
result = client.read_input_registers(0x3100,6,unit=1)
print(result.message)
# [Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 2 bytes (0 received)

Have you tried your scripts (JS or Pythton) in your computer? Are you able to connect to the Modbus Slave device in any other way? When I’ve received a timeout in my application, it has always been caused by a disconnected device on the other end (slave). The connect and open methods imply operations on your serial port only, they don’t send any bytes over the wire, so I would suggest checking out the connections, and maybe run some tests using your script or other modbus master in your development machine.

Got it! Testing directly with my computer was indeed my next step.

As of yesterday, I was able to determine that there was a wiring issue with the new USB converter. Once we sorted that out, things appear to be working as expected.

Thanks @gmerciel and everyone!

Glad to hear is working now :slight_smile:

1 Like