Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
Is there a way to cancel running events scripts e.g.
button for day scene and night scene which sends 0 or 1.
Every execute of command first cancel all instances of this script and after run new instances which run code.
Every script executes ~20 commands and waits 0.5s(pause between commands) or until one zone ends the motion. Whole scene continues a few minutes.
So I think this is something different from not allowing to start new same script by semaphore lock. I can save process id and then kill all existing processes which would be stored in some place but then probably there would be some problems with race condition.
Maybe there is some more elegant way.
Done is better than perfect
Posts: 4572
Threads: 23
Joined: Aug 2017
Reputation:
206
Here Erwin is using os.kill() to stop the running PID
https://forum.logicmachine.net/showthrea...6#pid11116
------------------------------
Ctrl+F5
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
Saving current PID might still lead to race conditions if two scripts execute in really short time period. The more elegant way is to use a resident script with two copas threads - one for bus monitoring and another for sequence.
Code: if not client then
require('copas')
function eventhandler(...)
log('event', ...)
end
client = require('localbus').new()
client:sethandler('groupwrite', eventhandler)
client:sethandler('groupresponse', eventhandler)
copas.addserver(client.sock, function()
client.sock = copas.wrap(client.sock)
while true do
client:step()
end
end, 1)
copas.addthread(function()
while true do
copas.sleep(0.5)
end
end)
end
copas.step()
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
Thanks for replies Second solution is nice but how can I get pid in eventhandler? I have only an event object withou pid.
Done is better than perfect
Posts: 4572
Threads: 23
Joined: Aug 2017
Reputation:
206
You don't need PID as the point is to use resident script instead of event.
------------------------------
Ctrl+F5
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
I don't understand why it should has 2 threads, it looks like 2 servers. I thinked that it is because that 1st monitor a bus and deals with cancelling events and another receives adress and pid from events via udp which collects in tables.
I've commented this code and I don't recognize any change:
Code: copas.addthread(function()
while true do
copas.sleep(0.5)
end
end)
Done is better than perfect
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
This is a single resident script for bus monitoring and sequence execution. If you provide a more detailed info on your task I can provide a better example
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
10.02.2019, 12:18
(This post was last modified: 10.02.2019, 12:20 by buuuudzik.)
I have reusable code for day/night scene which controls blinds. This scene doesn't run immediately but continues for e.g. 5 minutes, it depends on which zones are switched on and other conditions.
Above scenes are running by sun event and also by a user which can sent it one by one but the most important is the last and before it starts it should cancel all old instances.
Perfect solution would be:
Code: -- event start
cancelOldInstances()
day = event.getvalue()
if day then scenes.day() else scenes.night() end
I think that possible option is also adding additional GA which would storage the newest event pid and in event I can check before every step if that event has same pid.
But this will add another unnecessary requests to DB, and adding unnecessary GA to project is also not good.
I think this is missed in events mechanism which is great. There is a possibility to not run new event which is currently running but there is no in same elegant way tell to LM that it should run only the newest instance.
But your mechanism is very, very good and in comparison to e.g. eibPort it is nice that in your solution there is no time limit for script.
Done is better than perfect
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
Here's a complete example with two sequences - one for "on" event, another for "off". 32/1/1 is the object that triggers execution. Delay between each command is fixed at 0.5 seconds. This can be made adjustable via sequence table, but it must not be 0, otherwise sequence thread won't be able to pass control to localbus monitor thread.
Code: if not client then
require('copas')
seqon = {
{ address = '1/1/1', value = true },
{ address = '32/1/2', value = 42 },
{ address = '32/1/3', value = 43 },
{ address = '32/1/4', value = 44 },
{ address = '32/1/5', value = 45 },
}
seqoff = {
{ address = '1/1/1', value = false },
{ address = '32/1/2', value = 53 },
{ address = '32/1/3', value = 54 },
{ address = '32/1/4', value = 55 },
{ address = '32/1/5', value = 56 },
}
function eventhandler(event)
if event.dst == '32/1/1' then
local val = busdatatype.decode(event.datahex, dt.bool)
sequence = val and seqon or seqoff
seqpos = 1
copas.wakeup(seqthread)
end
end
client = require('localbus').new()
client:sethandler('groupwrite', eventhandler)
copas.addserver(client.sock, function()
client.sock = copas.wrap(client.sock)
while true do
client:step()
end
end, 1)
seqthread = copas.addthread(function()
copas.sleep(-1) -- put thread to sleep until wakeup is called
while true do
local curr = sequence[ seqpos ]
grp.write(curr.address, curr.value)
seqpos = seqpos + 1
-- end of sequence
if seqpos > #sequence then
copas.sleep(-1)
else
copas.sleep(0.5)
end
end
end)
end
copas.step()
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
Thank you admin for your effort. Maybe it will help also for other user which will search something similar.
But for me it should be a parameter of event-scripts like "Execute on read".
There should be 3 options:
- unlimited (default),
- only first,
- only last.
This would end using of semaphore and add this missed property of event script.
Done is better than perfect
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
Good suggestion, though semaphores still have to be used to prevent parallel execution and to create an event queue for things that require exclusive access like serial ports.
Posts: 12
Threads: 1
Joined: Jan 2017
Reputation:
0
There is another option:
-- At script begin
script.disable(_SCRIPTNAME)
-- some code
-- at script end
script.enable(_SCRIPTNAME)
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
I've tested this code but it doesn't work, you can try in such way. Please create 2 objects "C1" and "C2".
"C1" should has such event script:
Code: value = event.getvalue()
-- At script begin
script.disable(_SCRIPTNAME)
-- some code
os.sleep(5)
grp.update("C2", value)
-- at script end
script.enable(_SCRIPTNAME)
And please fast(<5s) send to "C1" 1 and 2.
"C2" should be changed only to 2, but is changed to 1 and isn't changed into 2. And this is little strange for me because I don't know why it isn't changed then into 2. Could you explain admin
Done is better than perfect
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
This example is similar to using semaphores, it executes only the first instance. But it can still have race condition: if C1 is updated really fast (before script.disable happens) two instances will execute in parallel. Semaphores guarantee locking on OS level.
Posts: 5
Threads: 1
Joined: May 2022
Reputation:
0
07.01.2023, 00:14
(This post was last modified: 07.01.2023, 00:14 by JASK.)
(11.02.2019, 12:45)admin Wrote: Here's a complete example with two sequences - one for "on" event, another for "off". 32/1/1 is the object that triggers execution. Delay between each command is fixed at 0.5 seconds. This can be made adjustable via sequence table, but it must not be 0, otherwise sequence thread won't be able to pass control to localbus monitor thread.
Code: if not client then
require('copas')
seqon = {
{ address = '1/1/1', value = true },
{ address = '32/1/2', value = 42 },
{ address = '32/1/3', value = 43 },
{ address = '32/1/4', value = 44 },
{ address = '32/1/5', value = 45 },
}
seqoff = {
{ address = '1/1/1', value = false },
{ address = '32/1/2', value = 53 },
{ address = '32/1/3', value = 54 },
{ address = '32/1/4', value = 55 },
{ address = '32/1/5', value = 56 },
}
function eventhandler(event)
if event.dst == '32/1/1' then
local val = busdatatype.decode(event.datahex, dt.bool)
sequence = val and seqon or seqoff
seqpos = 1
copas.wakeup(seqthread)
end
end
client = require('localbus').new()
client:sethandler('groupwrite', eventhandler)
copas.addserver(client.sock, function()
client.sock = copas.wrap(client.sock)
while true do
client:step()
end
end, 1)
seqthread = copas.addthread(function()
copas.sleep(-1) -- put thread to sleep until wakeup is called
while true do
local curr = sequence[ seqpos ]
grp.write(curr.address, curr.value)
seqpos = seqpos + 1
-- end of sequence
if seqpos > #sequence then
copas.sleep(-1)
else
copas.sleep(0.5)
end
end
end)
end
copas.step()
This script was nice
It's it possible to have different sleep (delay) between each command?
Posts: 321
Threads: 72
Joined: Jan 2021
Reputation:
0
(11.02.2019, 14:14)buuuudzik Wrote: Thank you admin for your effort. Maybe it will help also for other user which will search something similar.
But for me it should be a parameter of event-scripts like "Execute on read".
There should be 3 options:
- unlimited (default),
- only first,
- only last.
This would end using of semaphore and add this missed property of event script.
Hello Dear Admin
Does the new firmware consider this in the event based script with the three options:
Normal
First instance only
Last instance only
Best Regards,
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
@JASK, you can use scenes for this. You can set a custom delay after each command there.
@khalil, new firmware has these 3 options for event script execution.
Posts: 5
Threads: 1
Joined: May 2022
Reputation:
0
(09.01.2023, 07:49)admin Wrote: @JASK, you can use scenes for this. You can set a custom delay after each command there.
@khalil, new firmware has these 3 options for event script execution.
@admin
The commands don't seem to get interrupted when I use scenes. I thought about using this to control windows for ventilation when the thermostat is in cooling mode. 15 minute delay between when opening and 5 minutes when they close.
Posts: 7720
Threads: 42
Joined: Jun 2015
Reputation:
446
Scenes have a different behavior which might not suit your task. Scenes mapped to the same trigger address with a different value don't cancel each other.
You can use an event script in either "First instance only" or "Last instance only" mode instead.
|