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.

Remaining time or counter
#1
Hi

I am wondering if there could be a possibility to get a timer working. Its a client that want to visualize the staircase timer.
So like a clock or something else to count the time remaining. 


with value from the detector triggers the count down and new "1" retriggers the remaining time?

Any one got any ideas?
Reply
#2
Hi,

This is an old script i created when i was learning LUA so probably can be improved (:
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
-- ** Staircase logic with external time object and retriggering on input object Version 3.1 ** -- -- ****************************** Created by Erwin van der Zwart **************************** -- -- ************************************** SET PARAMETERS ************************************ -- -- Set input address AddressInput = '6/0/0' -- Set output address AddressOutput = '6/0/1' -- Set external time address (optional) AddressExternalTime = '6/0/2' -- Use time left indication UseTimeLeft = true -- Set to false if no time left indication is used -- Set feedback adress of time left indication (optional) AddressTimeLeft = '6/0/3' -- Set time delay (Used when external time is not available) SetDelay = 10 -- Seconds or Minutes SetSec = true -- Set to false for Minutes -- Set factor delay (Multiplies Delay) SetFac = 1 -- Set unique name for staircase timer (to avoid same storage name usage) StaircaseName = 'Staircase_1' -- Logic can be turned of by value 0 Off_by_Value_Zero = false -- ************************************** END PARAMETERS ************************************ -- -- *************************** DON'T CHANGE ANYTHING UNDER THIS LINE ************************ -- inputvalue = event.getvalue if Off_by_Value_Zero == false and (event.getvalue() == false or event.getvalue() == 0) then  -- Exit script  return end ValueInput = grp.getvalue(AddressInput) ValueOutput = grp.getvalue(AddressOutput) ValueExternalTime = grp.getvalue(AddressExternalTime) if SetSec == true then  SetSeconds = 1 else  SetSeconds = 60 end if ValueExternalTime == nil then ValueExternalTime = 0 end if ValueExternalTime > 0 then  StairCaseTime = ValueExternalTime * SetSeconds * SetFac else  StairCaseTime = SetDelay * SetSeconds * SetFac end if ValueInput == true then  --check for earlier started scrips  --check storage for stpid value  stpid = storage.get(StaircaseName)    --check if stpid has a value  if stpid == nil then          pid = os.getpid()          storage.set(StaircaseName, pid)  else          -- kill earlier running script              os.kill(stpid, signal.SIGKILL)        -- create new pid for next time to kill          pid = os.getpid()            storage.set(StaircaseName, pid)     end  if ValueOutput == false then    grp.write(AddressOutput, true)    ValueOutput = true  end  -- Check time left indication is used  if UseTimeLeft == true then    if StairCaseTime > 0 then        grp.update(AddressTimeLeft, StairCaseTime)        repeat          StairCaseTime = StairCaseTime - 1          grp.update(AddressTimeLeft, StairCaseTime)          os.sleep(1)        until StairCaseTime == 0    end      else    os.sleep(StairCaseTime)  end  ValueOutput = grp.getvalue(AddressOutput)  if ValueOutput == true then    ValueInput = grp.getvalue(AddressInput)    if ValueInput == true then        grp.write(AddressInput, false)      ValueInput = false    end    if Off_by_Value_Zero == false then      if ValueOutput == true then            grp.write(AddressOutput, false)        ValueOutput = false          end    else      -- Do nothing, this will trigger else condition below on next run    end  end   else  --check for earlier started scrips  --check storage for stpid value  stpid = storage.get(StaircaseName)    --check if stpid has a value  if stpid == nil then  else      -- kill earlier running script          os.kill(stpid, signal.SIGKILL)    grp.update(AddressTimeLeft, 0)    pid = nil    storage.set(StaircaseName, pid)     end  if ValueOutput == true then    grp.write(AddressOutput, false)  end end
BR,

Erwin
Reply
#3
(16.12.2018, 00:08)Erwin van der Zwart Wrote: Hi,

This is an old script i created when i was learning LUA so probably can be improved (:
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
-- ** Staircase logic with external time object and retriggering on input object Version 3.1 ** -- -- ****************************** Created by Erwin van der Zwart **************************** -- -- ************************************** SET PARAMETERS ************************************ -- -- Set input address AddressInput = '6/0/0' -- Set output address AddressOutput = '6/0/1' -- Set external time address (optional) AddressExternalTime = '6/0/2' -- Use time left indication UseTimeLeft = true -- Set to false if no time left indication is used -- Set feedback adress of time left indication (optional) AddressTimeLeft = '6/0/3' -- Set time delay (Used when external time is not available) SetDelay = 10 -- Seconds or Minutes SetSec = true -- Set to false for Minutes -- Set factor delay (Multiplies Delay) SetFac = 1 -- Set unique name for staircase timer (to avoid same storage name usage) StaircaseName = 'Staircase_1' -- Logic can be turned of by value 0 Off_by_Value_Zero = false -- ************************************** END PARAMETERS ************************************ -- -- *************************** DON'T CHANGE ANYTHING UNDER THIS LINE ************************ -- inputvalue = event.getvalue if Off_by_Value_Zero == false and (event.getvalue() == false or event.getvalue() == 0) then  -- Exit script  return end ValueInput = grp.getvalue(AddressInput) ValueOutput = grp.getvalue(AddressOutput) ValueExternalTime = grp.getvalue(AddressExternalTime) if SetSec == true then  SetSeconds = 1 else  SetSeconds = 60 end if ValueExternalTime == nil then ValueExternalTime = 0 end if ValueExternalTime > 0 then  StairCaseTime = ValueExternalTime * SetSeconds * SetFac else  StairCaseTime = SetDelay * SetSeconds * SetFac end if ValueInput == true then  --check for earlier started scrips  --check storage for stpid value  stpid = storage.get(StaircaseName)    --check if stpid has a value  if stpid == nil then          pid = os.getpid()          storage.set(StaircaseName, pid)  else          -- kill earlier running script              os.kill(stpid, signal.SIGKILL)        -- create new pid for next time to kill          pid = os.getpid()            storage.set(StaircaseName, pid)     end  if ValueOutput == false then    grp.write(AddressOutput, true)    ValueOutput = true  end  -- Check time left indication is used  if UseTimeLeft == true then    if StairCaseTime > 0 then        grp.update(AddressTimeLeft, StairCaseTime)        repeat          StairCaseTime = StairCaseTime - 1          grp.update(AddressTimeLeft, StairCaseTime)          os.sleep(1)        until StairCaseTime == 0    end      else    os.sleep(StairCaseTime)  end  ValueOutput = grp.getvalue(AddressOutput)  if ValueOutput == true then    ValueInput = grp.getvalue(AddressInput)    if ValueInput == true then        grp.write(AddressInput, false)      ValueInput = false    end    if Off_by_Value_Zero == false then      if ValueOutput == true then            grp.write(AddressOutput, false)        ValueOutput = false          end    else      -- Do nothing, this will trigger else condition below on next run    end  end   else  --check for earlier started scrips  --check storage for stpid value  stpid = storage.get(StaircaseName)    --check if stpid has a value  if stpid == nil then  else      -- kill earlier running script          os.kill(stpid, signal.SIGKILL)    grp.update(AddressTimeLeft, 0)    pid = nil    storage.set(StaircaseName, pid)     end  if ValueOutput == true then    grp.write(AddressOutput, false)  end end
BR,

Erwin

Thanks alot. Will not be improved by me, because Lua is not my strong side at all. But will definitly test it.. Thanks alot.

I gonna create three virtual objects and then  i am wondering whats the correct datatype. Is it 10 Time/date. ?
Reply
#4
Hi,

I just checked the code and the time left is just a integer in seconds, so a 2 byte int should be used.

BR,

Erwin
Reply
#5
Erwin,
sorry, should it be a resident script? If yes wich delay should be used?
Can you pls a little more in detail describe your script data types? Is it correct:

6/0/0 Boolean
6/0/1 Boolean
6/0/2 2 bytes unsigned int
6/0/3 2 bytes unsigned int

I tried to make resident script with 1 sec delay and have error:

Resident script:38: attempt to index global 'event' (a nil value)
stack traceback:
Reply
#6
Hi,

Here is a improved version: (event based on trigger object "32/1/100" of light switch) 
Code:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
-- ** Staircase logic with external time object and retriggering on input object Version 3.2 ** -- -- ****************************** Created by Erwin van der Zwart **************************** -- -- ************************************** SET PARAMETERS ************************************ -- -- Set output address AddressOutput = '32/1/101'  -- 01. 1 bit (boolean) -- Set external time address (optional) AddressExternalTime = '32/1/102' -- 07. 2 byte unsigned integer -- Use time left indication UseTimeLeft = true -- Set to false if no time left indication is used -- Set feedback adress of time left indication (optional) AddressTimeLeft = '32/1/103' -- 10. 3 byte time/day -- Set time delay (Used when external time is not available) SetDelay = 300 -- 5 minutes -- Seconds or Minutes SetSec = true -- Set to false for Minutes -- Set factor delay (Multiplies Delay) SetFac = 1 -- Logic can be turned of by value 0 Off_by_Value_Zero = false -- ************************************** END PARAMETERS ************************************ -- -- *************************** DON'T CHANGE ANYTHING UNDER THIS LINE ************************ -- Input_Value = event.getvalue() if Off_by_Value_Zero == false and (Input_Value == false or Input_Value == 0) then  return else  tpid = storage.get('PID:' .. _SCRIPTNAME)  if tpid == nil then      pid = os.getpid()      storage.set('PID:' .. _SCRIPTNAME, pid)  else    pid = os.getpid()      storage.set('PID:' .. _SCRIPTNAME, pid)    os.kill(tpid, signal.SIGKILL)  end   function Calculate_Time(StairCaseTime)     if StairCaseTime > (86400 -1) then        StairCaseTime = (86400 -1)     end     local hours = math.floor(StairCaseTime / 3600 % 24)     local minutes = math.floor(StairCaseTime / 60 % 60)     local seconds = math.floor(StairCaseTime % 60)     time = {       day = 0,       hour = hours,       minute = minutes,       second = seconds,     }     return time   end  if Input_Value == true or Input_Value == 1 then    ValueExternalTime = grp.getvalue(AddressExternalTime) or SetDelay    if SetSec == true then      Multiply_Seconds = 1    else      Multiply_Seconds = 60    end    StairCaseTime = ValueExternalTime * Multiply_Seconds * SetFac    ValueOutput = grp.getvalue(AddressOutput)    if ValueOutput == false then      grp.write(AddressOutput, true)    end    if UseTimeLeft == true then      if StairCaseTime > 0 then        time = Calculate_Time(StairCaseTime)        grp.update(AddressTimeLeft, time)        repeat          StairCaseTime = StairCaseTime - 1          time = Calculate_Time(StairCaseTime)          grp.update(AddressTimeLeft, time)          os.sleep(1)        until StairCaseTime == 0      end        else      os.sleep(StairCaseTime)    end    grp.write(AddressOutput, false)  elseif Input_Value == false or Input_Value == 0 then    ValueOutput = grp.getvalue(AddressOutput)    if ValueOutput == true then      if UseTimeLeft == true then        time = Calculate_Time(0)        grp.update(AddressTimeLeft, time)      end      grp.write(AddressOutput, false)    end  end  storage.delete('PID:' .. _SCRIPTNAME) end
Use these objects types:
   
BR,

Erwin
Reply
#7
Erwin BIG THANKS Smile
Reply
#8
Erwin, any idea why i get 1 hour before my time. The minutes is correct and the output changes after minutes are elapsed. 

But the hour says 1 and not 00 like your picture Smile

Attached Files Thumbnail(s)
   
Reply
#9
Hi guys, I have in front hour = 2 Smile Just now started this script for testing...
Erwin, what it could be? (May be time difference? I have eastern Europe time zone (+2 hours), but how it can influence here??) I think error in in time calculation function..
Reply
#10
Hi,

Yes there was a small issue with timezones, i did not take that into account, sorry (:

I updated the sample so use the new one or replace this function in your current script:
Code:
123456789101112131415
 function Calculate_Time(StairCaseTime)    if StairCaseTime > (86400 -1) then      StairCaseTime = (86400 -1)    end    local hours = math.floor(StairCaseTime / 3600 % 24)    local minutes = math.floor(StairCaseTime / 60 % 60)    local seconds = math.floor(StairCaseTime % 60)    time = {      day = 0,      hour = hours,      minute = minutes,      second = seconds,    }    return time  end
BR,

Erwin
Reply
#11
Hi
I see this code potentially dangerous. I think there is small but still chance you hit a different running process with the same PID after LM restart. Isn't there more "clean" solution? Mutexes, semaphores etc?
How about adding new function script.NumActive() which returns number of parallel running instances of the same script? And call this function in the loop cycle after sleep and exit the cycle after the returned value is bigger than 1?

Code:
123456789
tpid = storage.get('PID:' .. _SCRIPTNAME)  if tpid == nil then      pid = os.getpid()      storage.set('PID:' .. _SCRIPTNAME, pid)  else    pid = os.getpid()      storage.set('PID:' .. _SCRIPTNAME, pid)    os.kill(tpid, signal.SIGKILL)  end
LM5Lp, firmware: 2018.08.22 and 2021.12.15, FlashSYS v2, ARMv7 Processor rev 5 (v7l), kernel 4.4.151 and 4.4.259
Reply
#12
Event scripts are not the best approach for timers. Either scheduled for resolution of 1 minute or more, or resident for more precise timers.

Semaphores for event script locking are already present: http://openrb.com/docs/semaphore.htm
Reply
#13
Great work as always Erwin. 

Any idea why yhe mosaic wont show the value of the 3 byte value. Showed it when i used the 2 byte value in seconds and in minutes.
But when i changed the adress and upgraded the mosaic it wont show the value any longer.

Just tested it with time so definitly now showing 3 byte values.

Attached Files Thumbnail(s)
   
Reply
#14
(20.12.2018, 22:27)Tokatubs Wrote: Great work as always Erwin. 

Any idea why yhe mosaic wont show the value of the 3 byte value. Showed it when i used the 2 byte value in seconds and in minutes.
But when i changed the adress and upgraded the mosaic it wont show the value any longer.

Just tested it with time so definitly now showing 3 byte values.

Date/time object is not supported in this widget, convert it to string and use 250byte
------------------------------
Ctrl+F5
Reply
#15
(21.12.2018, 08:42)Daniel. Wrote:
(20.12.2018, 22:27)Tokatubs Wrote: Great work as always Erwin. 

Any idea why yhe mosaic wont show the value of the 3 byte value. Showed it when i used the 2 byte value in seconds and in minutes.
But when i changed the adress and upgraded the mosaic it wont show the value any longer.

Just tested it with time so definitly now showing 3 byte values.

Date/time object is not supported in this widget, convert it to string and use 250byte

OK. Cant seem to find converter for that under the converter in FBEDITOR. Then i maybe need to search for a script to convert the value.
Thanks for input.
Reply
#16
Hi
Before each
grp.update(AddressTimeLeft, time)

paste this

Code:
1
time =string.format('%02d:%02d:%02d',time.hour,time.min,time.sec)


It will convert time to string so just change this object DPT to 250 string

BR
------------------------------
Ctrl+F5
Reply
#17
Hi Daniel,

Change StairCaseTime.hour to time.hour etcetera

And put it in the function just before: return time

BR,

Erwin
Reply
#18
(21.12.2018, 12:31)Erwin van der Zwart Wrote: Hi Daniel,

Change StairCaseTime.hour to time.hour etcetera

And put it in the function just before: return time

BR,

Erwin

true, thanks updated
------------------------------
Ctrl+F5
Reply
#19
(21.12.2018, 13:11)Daniel. Wrote:
(21.12.2018, 12:31)Erwin van der Zwart Wrote: Hi Daniel,

Change StairCaseTime.hour to time.hour etcetera

And put it in the function just before: return time

BR,

Erwin

true, thanks updated
Code:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
-- ** Staircase logic with external time object and retriggering on input object Version 3.2 ** -- -- ****************************** Created by Erwin van der Zwart **************************** -- -- ************************************** SET PARAMETERS ************************************ -- -- Set output address AddressOutput = '32/1/21'  -- 01. 1 bit (boolean) -- Set external time address (optional) AddressExternalTime = '32/1/22' -- 07. 2 byte unsigned integer -- Use time left indication UseTimeLeft = true -- Set to false if no time left indication is used -- Set feedback adress of time left indication (optional) AddressTimeLeft = '32/1/23' -- 10. 3 byte time/day -- Set time delay (Used when external time is not available) SetDelay = 300 -- 5 minutes -- Seconds or Minutes SetSec = false -- Set to false for Minutes -- Set factor delay (Multiplies Delay) SetFac = 1 -- Logic can be turned of by value 0 Off_by_Value_Zero = false -- ************************************** END PARAMETERS ************************************ -- -- *************************** DON'T CHANGE ANYTHING UNDER THIS LINE ************************ -- Input_Value = event.getvalue() if Off_by_Value_Zero == false and (Input_Value == false or Input_Value == 0) then  return else  tpid = storage.get('PID:' .. _SCRIPTNAME)  if tpid == nil then      pid = os.getpid()      storage.set('PID:' .. _SCRIPTNAME, pid)  else    pid = os.getpid()      storage.set('PID:' .. _SCRIPTNAME, pid)    os.kill(tpid, signal.SIGKILL)  end  function Calculate_Time(StairCaseTime)    if StairCaseTime > (86400 -1) then      StairCaseTime = (86400 -1)    end    local hours = math.floor(StairCaseTime / 3600 % 24)    local minutes = math.floor(StairCaseTime / 60 % 60)    local seconds = math.floor(StairCaseTime % 60)    time = {      day = 0,      hour = hours,      minute = minutes,      second = seconds,    }    time =string.format('%02d:%02d:%02d',time.hour,time.min,time.sec)    return time  end  if Input_Value == true or Input_Value == 1 then    ValueExternalTime = grp.getvalue(AddressExternalTime) or SetDelay    if SetSec == true then      Multiply_Seconds = 1    else      Multiply_Seconds = 60    end    StairCaseTime = ValueExternalTime * Multiply_Seconds * SetFac    ValueOutput = grp.getvalue(AddressOutput)    if ValueOutput == false then      grp.write(AddressOutput, true)    end    if UseTimeLeft == true then      if StairCaseTime > 0 then        time = Calculate_Time(StairCaseTime)        grp.update(AddressTimeLeft, time)        repeat          StairCaseTime = StairCaseTime - 1          time = Calculate_Time(StairCaseTime)          grp.update(AddressTimeLeft, time)          os.sleep(1)        until StairCaseTime == 0      end        else      os.sleep(StairCaseTime)    end    grp.write(AddressOutput, false)  elseif Input_Value == false or Input_Value == 0 then    ValueOutput = grp.getvalue(AddressOutput)    if ValueOutput == true then      if UseTimeLeft == true then        time = Calculate_Time(0)        grp.update(AddressTimeLeft, time)      end      grp.write(AddressOutput, false)    end  end  storage.delete('PID:' .. _SCRIPTNAME) end

Is this somewhat correct then? Not getting anything on the remaining time block..
Reply
#20
I think above just copy of previous post...

Guys, can you please post here final script?? I tried to make changes mentioned but not work for me..
Reply


Forum Jump: