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 whether you accept or reject these cookies being set.

Cancel event-scripts
#1
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
Reply
#2
Here Erwin is using os.kill() to stop the running PID
https://forum.logicmachine.net/showthrea...6#pid11116
Reply
#3
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()
Reply
#4
Thanks for repliesWink 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
Reply
#5
You don't need PID as the point is to use resident script instead of event.
Reply
#6
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
Reply
#7
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 Smile
Reply
#8
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
Reply
#9
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 fixes 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()
Reply
#10
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
Reply
#11
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.
Reply
#12
There is another option:
-- At script begin
script.disable(_SCRIPTNAME)

-- some code

-- at script end

script.enable(_SCRIPTNAME)
Reply
#13
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 adminWink
Done is better than perfect
Reply
#14
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.
Reply


Forum Jump: