Logic Machine Forum
RS485 signal collision - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: RS485 signal collision (/showthread.php?tid=4419)



RS485 signal collision - Hadeel - 02.12.2022

Hi !
I appreciate if you could give me any idea because I cannnot come up with a good one.

I use LM RS485 port to communicate with the slave and the following is what I do:
- [event script] send the request to the slave to open/close the water valve
- [event script] send the request to the slave to open/close the drain valve
- [resident script] send a read request to the slave to get the slave's current status every 1 minute

The complicated thing is that I need to leave 0.5sec in between each every command.
Is there a way to wait 0.5 sec between each event script and the resident script?

Thank you for your help in advance!


RE: RS485 signal collision - Daniel - 02.12.2022

Everything should work in single resident script. You can have only one open connection at the time.


RE: RS485 signal collision - Hadeel - 02.12.2022

Thank you Daniel!

I am wondering how to open/close whenever I want in a single resident script... does that mean I call a resident script from a event script ?
(In my case, the group address 14/2/0 is for opening/closing the water valve, 14/2/1 for opening/closing the drain valve)


RE: RS485 signal collision - Daniel - 02.12.2022

You can set this script to run with 0 interval only make sure everything is on change of values. No need for event script.


RE: RS485 signal collision - Hadeel - 02.12.2022

Oh I get it !

So I create a resident script with 0 interval and listen to the group address event for 14/2/0 , 14/2/1
I will try this way, thank you Daniel (: !


RE: RS485 signal collision - Hadeel - 03.12.2022

Dear Daniel 

I tried this in a resident script with 0 interval like this but it seems this script does not get executed every second...
When I remove the last line "res, err = port:read(17)" it gets executed every second.
Could you tell me if I am doing anything wrong?

Code:
if not port then
  require('serial')
  port =  serial.open('/dev/RS485-1', {
  baudrate = 19200,
  databits = 8,
  stopbits = 1,
  parity = 'none',
  duplex = 'half'
})
end

log('executed')


if storage.get('coldBathAutoStartCommand') ~= nil  then
port:write(storage.get('coldBathAutoStartCommand'))
os.sleep(1)
port:write(':RR\r\n')
storage.set('coldBathAutoStartCommand', nil)
end


port:flush()
res, err = port:read(17)



RE: RS485 signal collision - admin - 05.12.2022

port:read(17) is a blocking read. It won't return until 17 bytes are read.
For one-way communication you can use UDP for data transport between scripts:
Code:
if not server then
  require('socket')
  server = socket.udp()
  server:setsockname('127.0.0.1', 5485)
  server:settimeout(60)
end

if not port then
  require('serial')
  port = serial.open('/dev/RS485-1', {
    baudrate = 19200,
    databits = 8,
    stopbits = 1,
    parity = 'none',
    duplex = 'half'
  })
end

data = server:receive()
if data then
  port:write(data)
  os.sleep(1)
  port:write(':RR\r\n')
end

Send commands like this:
Code:
data = '123456'

sock = require('socket').udp()
sock:sendto(data, '127.0.0.1', 5485)
sock:close()



RE: RS485 signal collision - Hadeel - 05.12.2022

Thank you Admin!

So I write sock : sendto(data, '127.0.0.1', 5485) in the event script and receive them in resident script.

port:write(':RR\r\n') is a command to request the slave to give LM the status so it is not one-way communication....can I include "port:read(17)" in the same resident script?


RE: RS485 signal collision - admin - 06.12.2022

Then you will need something like this. It will request the status after each write or socket read timeout so it can happen faster than once every 60 seconds. But I don't think that it will be an issue.
Code:
if not server then
  require('socket')
  server = socket.udp()
  server:setsockname('127.0.0.1', 5485)
  server:settimeout(60)
end

if not port then
  require('serial')
  port = serial.open('/dev/RS485-1', {
    baudrate = 19200,
    databits = 8,
    stopbits = 1,
    parity = 'none',
    duplex = 'half'
  })
end

data = server:receive()
if data then
  port:write(data)
  os.sleep(0.5)
end

port:write(':RR\r\n')
data = port:read(17, 1) -- read 17 bytes for up to 1 second
if data and #data == 17 then
  -- parse data response here
end



RE: RS485 signal collision - Hadeel - 07.12.2022

Dear admin
I really appreciate your solution !
This looks so beautiful Smile
I will try this in the site Smile


RE: RS485 signal collision - Hadeel - 23.03.2023

Dear admin,

I am running the code in the site, and I want to add 2 features....could you tell me how I do these?

1. Is there a way to execute port:write(':RR\r\n') every 60 sec even if port:read(17) does not return anything? As you said before, port:read(17) is blocking the script. If there's no response from the slave, the script is not going to be executed anymore  Sad

2. I want to alart the system admin if there's no response from the slave(port:read(17)) for 5 min....can I do that in this script?

Code:
if not server then
  require('socket')
  server = socket.udp()
  server:setsockname('127.0.0.1', 5485)
  server:settimeout(60)
end

if not port then
  require('serial')
  port = serial.open('/dev/RS485-1', {
    baudrate = 19200,
    databits = 8,
    stopbits = 1,
    parity = 'none',
    duplex = 'half'
  })
end

data = server:receive()
if data then
  port:write(data)
  os.sleep(0.5)
end

port:flush()
port:write(':RR\r\n')
data, err = port:read(17, 1) -- read 17 bytes for up to 1 second
if data and #data == 17 then
  -- parse data response here
end



RE: RS485 signal collision - admin - 23.03.2023

Do you have a description of the protocol? Is the response fixed to 17 chars or can it be different? Apart from the status request does the device send something back when a command is written to it?


RE: RS485 signal collision - Hadeel - 23.03.2023

Dear admin,
Thank you for your response!
It's a special protocol that we(the bath system builder and we) made to meet the control requirement for this project.
Response lengh is fixed to 17 ASCII chars for sure, and apart from the status request the device does not send anything back to LM. Smile


RE: RS485 signal collision - admin - 23.03.2023

Ok then the script is already more or less correct. Use this to add an alert if 5 timeouts in a row happen.
Code:
if not server then
  require('socket')
  server = socket.udp()
  server:setsockname('127.0.0.1', 5485)
  server:settimeout(60)
end

if not port then
  require('serial')
  port = serial.open('/dev/RS485-1', {
    baudrate = 19200,
    databits = 8,
    stopbits = 1,
    parity = 'none',
    duplex = 'half'
  })

  timeouts = 0
end

data = server:receive()
if data then
  port:write(data)
  os.sleep(0.5)
end

port:flush()
port:write(':RR\r\n')
data, err = port:read(17, 1) -- read 17 bytes for up to 1 second

if data and #data == 17 then
  timeouts = 0
  -- parse data response here
else
  timeouts = timeouts + 1

  if timeouts == 5 then
    -- send alert
  end
end



RE: RS485 signal collision - Hadeel - 28.03.2023

Dear admin,
Thank you for providing the code, it's working on the site!

However there was one problem we could not solve on the site.
Even though this script intend to wait at least for 0.5 sec between each command,
when the bath system builder checked their command reception log on the slave side,
it seems that sometimes LM sends commmand with 0 sec in between (between the actual command port:write(data) and the status read port:write(':RR\r\n')).
It does not happen every time, it happened just 3 times in a day.


I just changed the timeout to 20 from 1 but everything else is same with your last script.
Code:
data, err = port:read(17, 20) -- read 17 bytes for up to 20 second


Could you think of any reason why this happen ?

Thank you !


RE: RS485 signal collision - admin - 30.03.2023

Try increasing the sleep time after writing a command from 0.5 seconds to a larger value. You can also add a short sleep after a successful status read.


RE: RS485 signal collision - Hadeel - 30.03.2023

Thank you admin! We will try both of your suggestion Smile