Remaining time or counter - Tokatubs - 15.12.2018
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?
RE: Remaining time or counter - Erwin van der Zwart - 16.12.2018
Hi,
This is an old script i created when i was learning LUA so probably can be improved (:
Code: -- ** 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
RE: Remaining time or counter - Tokatubs - 16.12.2018
(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: -- ** 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. ?
RE: Remaining time or counter - Erwin van der Zwart - 16.12.2018
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
RE: Remaining time or counter - AlexLV - 16.12.2018
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:
RE: Remaining time or counter - Erwin van der Zwart - 16.12.2018
Hi,
Here is a improved version: (event based on trigger object "32/1/100" of light switch)
Code: -- ** 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
RE: Remaining time or counter - AlexLV - 16.12.2018
Erwin BIG THANKS
RE: Remaining time or counter - Tokatubs - 18.12.2018
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
RE: Remaining time or counter - AlexLV - 19.12.2018
Hi guys, I have in front hour = 2 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..
RE: Remaining time or counter - Erwin van der Zwart - 20.12.2018
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: 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
RE: Remaining time or counter - Thomas - 20.12.2018
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: 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
RE: Remaining time or counter - admin - 20.12.2018
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
RE: Remaining time or counter - Tokatubs - 20.12.2018
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.
RE: Remaining time or counter - Daniel - 21.12.2018
(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
RE: Remaining time or counter - Tokatubs - 21.12.2018
(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.
RE: Remaining time or counter - Daniel - 21.12.2018
Hi
Before each
grp.update(AddressTimeLeft, time)
paste this
Code: 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
RE: Remaining time or counter - Erwin van der Zwart - 21.12.2018
Hi Daniel,
Change StairCaseTime.hour to time.hour etcetera
And put it in the function just before: return time
BR,
Erwin
RE: Remaining time or counter - Daniel - 21.12.2018
(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
RE: Remaining time or counter - Tokatubs - 21.12.2018
(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: -- ** 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..
RE: Remaining time or counter - AlexLV - 24.12.2018
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..
|