This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

write to modbus with bitmask
#1
Hi can anybody give me some tips for modbus writing with a bitmask?
The case is resetting an alarm on a cooling machine (Eliwell ST500 controller). Attached is the relevant part of the Modbus manual of the ST500 controller.

As I consulted the forum I tried this:
---
require('luamodbus')
mb = luamodbus.rtu()
mb:open('/dev/RS485', 9600, 'N', 8, 1, 'H')
mb:connect()
mbConfusedetslave(3) -- Enter the correct Modbus slave address of Airco


function setbit(value, nr)
  return bit.bor(value, bit.lshift(1, nr))
end

value = 1

value = setbit(value, 2)

mb:writeregisters(33471, value)


----

But I doesn't seem to work. The error stays. Any other things like reading values or writing setpoints work like a charm.


What do I do wrong?

Attached Files Thumbnail(s)
   
Reply
#2
The value that you are writing has both bits 0 and 2 set which the Modbus device might reject. Log the returned write result. It might have an error indication.
Code:
value = 4 -- bit 2 set to 1
res, err = mb:writeregisters(33471, value)
log(res, err)

Also keep in mind that using scripts can lead to random errors if two scripts try to access the same serial port in parallel. It is recommended to use profiles instead.
Reply
#3
(09.02.2022, 07:52)admin Wrote: The value that you are writing has both bits 0 and 2 set which the Modbus device might reject. Log the returned write result. It might have an error indication.
Code:
value = 4 -- bit 2 set to 1
res, err = mb:writeregisters(33471, value)
log(res, err)

Also keep in mind that using scripts can lead to random errors if two scripts try to access the same serial port in parallel. It is recommended to use profiles instead.

Hi Admin,

I tried the above and this is the result in de errorlog:
"* arg: 1
  * nil
* arg: 2
  * string: Illegal function"

Do you have tips where to move ahead? 
I also have a modbus profile in place (attached) and this works great for reading values, I didn't yet try to use this for writing values.

Greets,
Jeroen
* arg: 1
  * nil
* arg: 2
  * string: Illegal function
* arg: 1
  * nil
* arg: 2
  * string: Illegal function

Attached Files
.json   Clint_test_modbus.json (Size: 3.51 KB / Downloads: 11)
Reply
#4
Hi,

You can use your setbit script but instead of writing direct to modbus by script you should write the output value of your script to a virtual object and use the modbus template mapped to this virtual object.
Reply
#5
Try using multiple register write instead:
Code:
value = 4 -- bit 2 set to 1
res, err = mb:writemultipleregisters(33471, value)
log(res, err)
Reply
#6
(10.02.2022, 08:25)admin Wrote: Try using multiple register write instead:
Code:
value = 4 -- bit 2 set to 1
res, err = mb:writemultipleregisters(33471, value)
log(res, err)

I get this output now:
* arg: 1
  * number: 1
* arg: 2
  * nil
I see the alarms are reset this way. Thanks.

(10.02.2022, 07:48)Erwin van der Zwart Wrote: Hi,

You can use your setbit script but instead of writing direct to modbus by script you should write the output value of your script to a virtual object and use the modbus template mapped to this virtual object.

Hi Erwin,

The reset works with the writemultipleregisters in the script. Now I want to move on to the profile way as you suggested.
1/ Is it sufficient to add to the modbus profile something like this:
    {
      "name": "reset flow error (err 20)",
      "bus_datatype": "int16",
      "datatype": "int16",
      "type": "register",
      "address": 33471,
      "writable": 1,
      "value_bitmask": 0x4
    }
and then link that to a virtual object?
2/ I've set the polling interval of that device to 55 seconds. Is then the value of the object written to the device every time? I'm asking because now I use a script to write values, but only when they change (like the setpoint for the cooling depending on the dewpoint).

Greets
Reply
#7
You need to add write_only and write_multiple fields. Also you can simply map it a boolean object. Setting it to true will reset the error state.
Code:
{
  "name": "reset flow error (err 20)",
  "bus_datatype": "bool",
  "datatype": "int16",
  "type": "register",
  "address": 33471,
  "writable": true,
  "write_only": true,
  "write_multiple": true,
  "value_bitmask": 4
}

Poll interval only affects reading. Writing is done as soon as possible.

As I've said before using scripts together with profile will lead to random errors. If you need scripts then you should use mbproxy instead of accessing the port directly. Examples: https://forum.logicmachine.net/showthrea...7#pid22637
Reply
#8
(11.02.2022, 08:03)admin Wrote: You need to add write_only and write_multiple fields. Also you can simply map it a boolean object. Setting it to true will reset the error state.
Code:
{
  "name": "reset flow error (err 20)",
  "bus_datatype": "bool",
  "datatype": "int16",
  "type": "register",
  "address": 33471,
  "writable": true,
  "write_only": true,
  "write_multiple": true,
  "value_bitmask": 4
}

Poll interval only affects reading. Writing is done as soon as possible.

As I've said before using scripts together with profile will lead to random errors. If you need scripts then you should use mbproxy instead of accessing the port directly. Examples: https://forum.logicmachine.net/showthrea...7#pid22637
I works with this in de modbus profile:
{
      "name": "reset flow error (err 20)",
      "bus_datatype": "int16",
      "datatype": "int16",
      "type": "register",
      "address": 33471,
      "writable": true,
      "write_only": true,
      "write_multiple": true,
      "write_bitmask": true,
      "value_bitmask": 0x4
    }

Thanks for the help
Reply


Forum Jump: