Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
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!
Posts: 4814
Threads: 25
Joined: Aug 2017
Reputation:
217
Everything should work in single resident script. You can have only one open connection at the time.
------------------------------
Ctrl+F5
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
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)
Posts: 4814
Threads: 25
Joined: Aug 2017
Reputation:
217
You can set this script to run with 0 interval only make sure everything is on change of values. No need for event script.
------------------------------
Ctrl+F5
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
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 (: !
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
03.12.2022, 10:57
(This post was last modified: 03.12.2022, 10:58 by Hadeel.)
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)
Posts: 7931
Threads: 43
Joined: Jun 2015
Reputation:
454
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()
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
05.12.2022, 18:58
(This post was last modified: 05.12.2022, 18:58 by Hadeel.)
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?
Posts: 7931
Threads: 43
Joined: Jun 2015
Reputation:
454
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
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
Dear admin
I really appreciate your solution !
This looks so beautiful
I will try this in the site
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
23.03.2023, 02:31
(This post was last modified: 23.03.2023, 03:12 by Hadeel.)
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
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
Posts: 7931
Threads: 43
Joined: Jun 2015
Reputation:
454
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?
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
23.03.2023, 07:48
(This post was last modified: 23.03.2023, 07:50 by Hadeel.)
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.
Posts: 7931
Threads: 43
Joined: Jun 2015
Reputation:
454
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
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
28.03.2023, 08:35
(This post was last modified: 28.03.2023, 08:39 by Hadeel.)
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 !
Posts: 7931
Threads: 43
Joined: Jun 2015
Reputation:
454
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.
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
Thank you admin! We will try both of your suggestion
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
20.01.2025, 04:22
(This post was last modified: 20.01.2025, 04:24 by Hadeel.)
Dear admin,
It's been two years since we implemented your suggestion and so far it's working fine.
but there are a few concern coming up from our client.
Their requirents are:
- Use TCP instead of UDP to collect the data inside LM as TCP is more reliable than UDP (UPD could miss the signal)
- When the signal loss or unreachable signal occurs, our client wants the error log.
Can we use TCP instead of UDP and add error logging ?
Or do you have any other way than TCP and UDP?
Thank you so much for your advice in advance
Posts: 7931
Threads: 43
Joined: Jun 2015
Reputation:
454
No point in using TCP here because the communication happens internally via a virtual network. The only way for a UDP message to be dropped is buffer overflow - when a receiving script does not consume the messages quickly enough. But the same thing will happen if TCP is used.
Posts: 91
Threads: 30
Joined: Feb 2022
Reputation:
0
27.01.2025, 12:10
(This post was last modified: 27.01.2025, 12:10 by Hadeel.)
Thank you admin! I get back to my client and discussed about your point and what I got as a request is:
Ideally our client wants to log the error when transmitter error or any kind of error related to TCP happans (probably they happen because of buffer overflow also).
The idea is to take a record when the signals does not get processeed as they are supposed to.
Can we do this in LM?
Again I appreciate your advice in advance!
|