Getting Workflow Error trying to write 32767 to holding register using MODBUS write

Hi

I am trying to write a value of 32767 to a Holding register and I am getting a Workflow Error

ValidationError
holding registers can only hold up to 16 bits of signed integers.

  • “heartbeat”: 32767

But 32767 is a valid (maximum) signed integer.

(As an aside it would be nice to be used unsigned or signed as many devices store unsigned values and to be honest most devices we deal with store unsigned for most register values and only some are signed :wink:

Thanks

Tim

Thanks for the report, I’m betting we are off by one in terms of our validation. If that is the case, we will get it fixed and get a hotfix of the agent out tomorrow.

For signed vs unsigned, that makes sense, I’ll file a ticket to add that as an option for both the read and write workflow nodes. Would you want that as an option for the node as a whole (like the endianness option), or for each individual read/write instruction?

Doing some more investigation, with a particular PLC (Cruzet M4). All of the registers are unsigned (though some are treated as signed).

Using the Edge Agent when I try and write -1000 for instance which is a valid Signed 16bit value I get the following modbus error

  • “message”:

“"value" argument is out of bounds”

  • “type”:

“MODBUS_WRITE_ERROR”

Now my experience in the past has been that the real value is a 16bit unsigned value which you have to interpret as Signed/Unsigned as appropriate

From simply modbus

The example for FC03 shows that register 40108 contains AE41
which converts to the 16 bits 1010 1110 0100 0001
Great! But what does it mean? Well, it could mean a few things.
Register 40108 could be defined as any of these 16-bit data types:

 A 16-bit unsigned integer (a whole number between 0 and 65535)
                register 40108 contains AE41 = 44,609 (hex to decimal conversion)

 A 16-bit signed integer (a whole number between -32768 and 32767)
                                                    AE41 = -20,927
          (hex to decimal conversion that wraps, if its over 32767 then subtract 65536)

Now using Python (modbus_tk lib) to read/write to the same device we see expected behaviour

In [8]: c.execute(1,cst.READ_HOLDING_REGISTERS,25,1)
Out[8]: (32000,)

In [9]: c.execute(1,cst.WRITE_SINGLE_REGISTER,25,output_value=1)
Out[9]: (25, 1)

In [10]: c.execute(1,cst.READ_HOLDING_REGISTERS,25,1)
Out[10]: (1,)

In [11]: c.execute(1,cst.WRITE_SINGLE_REGISTER,25,output_value=32767)
Out[11]: (25, 32767)

In [12]: c.execute(1,cst.READ_HOLDING_REGISTERS,25,1)
Out[12]: (32767,)

In [13]: c.execute(1,cst.WRITE_SINGLE_REGISTER,25,output_value=32768)
Out[13]: (25, 32768)

In [14]: c.execute(1,cst.READ_HOLDING_REGISTERS,25,1)
Out[14]: (32768,)

In [15]: c.execute(1,cst.WRITE_SINGLE_REGISTER,25,output_value=-100)
Out[15]: (25, 65436)

In [17]: c.execute(1,cst.WRITE_SINGLE_REGISTER,25,output_value=65436)
Out[17]: (25, 65436)

So at the moment due to the Edge Agent modbus implementation it appears the maximum value that can be written is 32766, firstly due to the validation error, and the secondly because of the format of negative signed integers being written is being rejected by the MODBUS device.

Cheers

T

HI Michael.

Please see my further investigation. I think a few things are wrong with the implementation.
My belief is everything should be Unsigned by default.

We typically have to perform a number of transformations on the data after the fact for instance from a BBA pump to interpret oil temperature we need to apply a scale factor of 0.03125 and then apply an offset of -273.

I think moving forward the least surpise to running code would be to set Signed / Unsigned at the connection level and leave the default to Signed, so it doesn’t upset existing workflows.

However you should be turning the negative value into unsigned before writing as I can’t write -1000 using the Edge Agent, but I can using python.

See my earlier comment on writing values from Python as a comparison.

At the moment am finding it impossible to implement a 32bit unsigned incrementing counter that can be written to 2 contiguous registers (MSB/LSB), given the current behaviour.

Thanks for the prompt response.

T

We did some some investigation on our end, and you are quite right. We can’t change the default behavior of the read node, so it will continue to read as signed integers for the moment - but we are planning to add an option to read the values as unsigned integers in a future release. For the write node, though, because negative numbers didn’t work at all previously (essentially we were only allowing 15 bit integers), we went ahead and fixed the agent to treat writes as unsigned and allow the full 16 bit unsigned range. We have released version 1.2.5 of the Edge Agent with this fix.

Excellent news.

Thanks for sorting this so quickly

Hi Michael

Any word when the ability to read unsigned will be available ?

Thanks

Tim

Reading unsigned, as well as the ability to set custom modbus read & write timeouts, are both in our next release, which is planned for next month.

Thanks for the update

T