| 
		
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		I use the Staircase script frequently. Thanks again! 
Now I would like to use it also in rooms where by default a dimmed lamp burns softly (e.g. 30%), for example in the hallway. When the motion detector of the alarm detects someone in the hallway, I would like the lamp to burn brighter for a defined time (e.g. 90% for 60 seconds). And then back to the old dimming value (30%). 
If the lamp is turned off in the meantime, it should go out and turn on again the next time in the dimming mode (30%). I've tried all kinds of things, but can't get it to work properly. 
Every time it seems to work, but then there is still an error somewhere. And I have solved it with three different scripts. It is complex to explain. Can someone please modify the script in such a way that this does work properly? Hopefully more people will enjoy this enhanced script     .
 
Thanks in advance!
	
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		Can you post the scripts that you are using now?
	 
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
		
		
		19.05.2022, 18:52 
(This post was last modified: 19.05.2022, 18:57 by Dirk79.)
		
	 
		 (16.03.2022, 09:25)admin Wrote:  Can you post the scripts that you are using now? 
Thanks for the question and apologies for not responding sooner. I did not notice your response.
 
I created two different scripts. The first one responds to the PIR. For that, I modified the beautiful Staircase logic. See my explanation in the script. I added a lot of logs to find for myself why it doesn't work properly.
 
With the second script I want to achieve that if the lamp is turned off (manually or by a program or by another script), that the running first script then stops, that the lamp goes off, and the next time it comes on again dimmed.
 
In practice, it works well, until we go to bed. Usually the lamp goes off first and then on again. Also, regularly the lamp goes directly on at the brighter setting. So then the brighter setting is the same as the standard setting.
 
It would be best if this could work with just 1 script. I would like to use this script in more places in the house (and especially outside).
 
Here are the scripts:
 
SCRIPT 1:
 Code: -- Note that at 3/0/7 there is also a script, which should stop this staircase if the lamp is turned on/off.
 -- Only react to PIR going on, not going off:
 inputvalue = event.getvalue
 if (event.getvalue() == false or event.getvalue() == 0) then
 return
 end
 
 -- ** 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 = '9/0/1'
 
 -- Set output address
 AddressOutput = '1/1/7'
 
 -- Set unique name for staircase timer (to avoid same storage name usage)
 StaircaseName = 'PIR_LAMP_HAL'
 
 -- Set external time address (optional)
 AddressExternalTime = ''
 
 -- Use time left indication
 UseTimeLeft = false -- Set to true if time left indication will be used
 
 -- Set feedback adress of time left indication (optional)
 AddressTimeLeft = ''
 
 -- Set time delay (Used when external time is not available)
 SetDelay = 15
 
 -- 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
 
 
 -- Additions for brightening the lamp on motion dd 14-01-2022:
 
 Schemer = grp.getvalue('6/0/6') -- If it is dusk, this is set to 1.
 
 AanStandHal = grp.getvalue('3/0/7') -- This indicates whether lamp is on when the script starts.
 DimStandHal = grp.getvalue('3/2/7') -- This is the dimming value at the start of the script.
 
 AdressOpgeslagenBeginStandHal = '1/2/7'-- Dim value field especially for this script to save initial state (I don't manage to keep this in memory)
 OpgeslagenBeginStandHal = grp.getvalue(AdressOpgeslagenBeginStandHal)
 
 TijdelijkHarderHal = grp.getvalue('39/1/1') -- This contains the (brighter) dimming value that the lamp should temporarily be at (e.g. 90%)
 
 -- If DimStandHal is set to 0, the lamp is off, and nothing needs to happen. Nothing needs to happen when there is no twilight either.
 if (DimStandHal) == 0 or (Schemer) == false then
 --log('return because hall lamp not on or no dusk')
 return
 end
 
 -- If DimStandHal == TemporaryHarderHal, then the script has run before. Then nothing should happen. Otherwise save current value.
 if DimStandHal == TijdelijkHarderHal then
 --log ('DimStandHal gelijk aan TijdelijkeHarderHal')
 --log ('OpgeslagenBeginStandHal is'..OpgeslagenBeginStandHal)
 --log ('TijdelijkHarderHal is'..TijdelijkHarderHal)
 -- do nothing
 else
 grp.write(AdressOpgeslagenBeginStandHal, DimStandHal)
 OpgeslagenBeginStandHal = grp.getvalue(AdressOpgeslagenBeginStandHal)
 --log ('Nieuwe start script (Else)')
 --log ('OpgeslagenBeginStandHal is'..OpgeslagenBeginStandHal)
 --log ('DimStandHal is'..DimStandHal)
 --log ('TijdelijkHarderHal is'..TijdelijkHarderHal)
 end
 
 -- ************************************** 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 < TijdelijkHarderHal then
 grp.write(AddressOutput, TijdelijkHarderHal)
 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 == TijdelijkHarderHal 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 == TijdelijkHarderHal then
 grp.write(AddressOutput, OpgeslagenBeginStandHal) -- value here was 0, but to OpgeslagenBeginStandHal to set it back to this position.
 ValueOutput = 0
 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
 
 -- Terugschrijven naar beginstand
 if ValueOutput == TijdelijkHarderHal then
 --log ('ValueOutput == TijdelijkHarderHal')
 grp.write(AddressOutput, OpgeslagenBeginStandHal)
 end
 
 end
SCRIPT 2:
 Code: --When switching this lamp, any running script on the hall PIR (9/0/1) is stopped.--This script is activacted at 3/0/7 and 0/1/1 (group lighting downstairs)
 
 StaircaseName = 'PIR_LAMP_HAL'
 stpid = storage.get(StaircaseName)
 os.kill(stpid, signal.SIGKILL)
 grp.update(AddressTimeLeft, 0)
 pid = nil
 storage.set(StaircaseName, pid)
 
 -- If script is turned off, while the lamp is louder during the PIR script, then the "old" DimValue must be written over the feedback.
 -- The idea is that the lamp then starts up the next time with the harder setting (on which it went out) and then automatically dims back to the old dimming value.
 
 OpgeslagenDimWaarde = grp.getvalue('1/2/7')
 grp.write('3/2/7', OpgeslagenDimWaarde)
 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		This is easier to do via a resident script (0 sleep time). 
Single script can be used for multiple timers by adding more entries to the timers table. The script uses current dimmer control value to determine what level to set, only values set by other sources (not the script itself) are used. There are two points - high and low, if the current value is less than low then low value is used, otherwise high value is used. The status value cannot be used here because it's impossible to tell who change the value that caused the status update.
 
An alternative solution is to create a day/night object to have two different sets of values for movement/no movement.
 Code: if not client thentimers = {
 {
 input = '1/1/1', -- binary PIR status
 output = '1/1/3', -- dimmer control (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 30, -- low output value in %
 timeout = 60, -- in seconds
 }
 }
 
 function setinputvalue(timer, event)
 local value = busdatatype.decode(event.datahex, dt.bool)
 
 if not value then
 return
 end
 
 if timer.outvalue < timer.onvaluelow then
 value = timer.onvaluelow
 elseif timer.outvalue < timer.onvaluehigh then
 value = timer.onvaluehigh
 else
 value = nil
 end
 
 if not timer.ticks and value then
 grp.write(timer.output, value, dt.scale)
 end
 
 timer.ticks = timer.timeout
 end
 
 function setoutputvalue(timer, event)
 timer.outvalue = busdatatype.decode(event.datahex, dt.scale)
 timer.ticks = nil -- stop timer
 end
 
 for _, timer in ipairs(timers) do
 timer.outvalue = grp.getvalue(timer.output)
 end
 
 sender = 'tm'
 grp.sender = sender
 
 client = require('localbus').new(0.1)
 client:sethandler('groupwrite', function(event)
 if event.sender == sender then
 return
 end
 
 for _, timer in ipairs(timers) do
 if timer.input == event.dst then
 setinputvalue(timer, event)
 elseif timer.output == event.dst then
 setoutputvalue(timer, event)
 end
 end
 end)
 end
 
 client:loop(1)
 
 for _, timer in ipairs(timers) do
 if timer.ticks then
 timer.ticks = timer.ticks - 1
 
 if timer.ticks == 0 then
 grp.write(timer.output, timer.outvalue, dt.scale)
 timer.ticks = nil
 end
 end
 end
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		This script is more complex than I can make myself. Very cool to see that you made this one so for me. Thank you, thank you!
 I have adopted the script as resident script with 0 sleep time.
 I also deleted my own scripts.
 I filled in the table as follows:
 
 {
 input = '9/0/1', -- binary PIR status
 output = '1/1/7', -- dimmer control (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 10, -- low output value in %
 timeout = 5, -- in seconds
 }
 
 And I also tried filling in the status object 3/1/7 as output instead of 1/1/7.
 After two weeks, I tried one more time of all. Sometimes you then suddenly see what is going wrong. Unfortunately, I am not able to get this script to work.
 Can you give any advice...?
 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		Post your full script listing. Also enable logging for mapped object and see if they change values. Check Error logs as well.
	 
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		 (09.06.2022, 15:33)admin Wrote:  Post your full script listing. Also enable logging for mapped object and see if they change values. Check Error logs as well. 
Thanks. Here is my answer: 
Sorry for not noticing the error log. There are errors:
 
--- 
Resident script:19: attempt to compare nil with number 
stack traceback: 
Resident script:19: in function 'setinputvalue' 
Resident script:54: in function <Resident script:47> 
Library localbus: in function '' 
Library localbus: in function '' 
Library localbus: in function 'loop' 
---
 
'1/1/7' is the object of the dimming value. 
I have logged 1/1/7. No logs registered.
 Code: if not client thentimers = {
 {
 input = '9/0/1', -- binary PIR status
 output = '1/1/7', -- dimmer control (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 10, -- low output value in %
 timeout = 5, -- in seconds
 }
 }
 
 function setinputvalue(timer, event)
 local value = busdatatype.decode(event.datahex, dt.bool)
 
 if not value then
 return
 end
 
 if timer.value < timer.onvaluelow then
 value = timer.onvaluelow
 elseif timer.outvalue < timer.onvaluehigh then
 value = timer.onvaluehigh
 else
 value = nil
 end
 
 if not timer.ticks and value then
 grp.write(timer.output, value, dt.scale)
 end
 
 timer.ticks = timer.timeout
 end
 
 function setoutputvalue(timer, event)
 timer.outvalue = busdatatype.decode(event.datahex, dt.scale)
 timer.ticks = nil -- stop timer
 end
 
 for _, timer in ipairs(timers) do
 timer.outvalue = grp.getvalue(timer.output)
 end
 
 sender = 'tm'
 grp.sender = sender
 
 client = require('localbus').new(0.1)
 client:sethandler('groupwrite', function(event)
 if event.sender == sender then
 return
 end
 
 for _, timer in ipairs(timers) do
 if timer.input == event.dst then
 setinputvalue(timer, event)
 elseif timer.output == event.dst then
 setoutputvalue(timer, event)
 end
 end
 end)
 end
 
 client:loop(1)
 
 for _, timer in ipairs(timers) do
 if timer.ticks then
 timer.ticks = timer.ticks - 1
 
 if timer.ticks == 0 then
 grp.write(timer.output, timer.outvalue, dt.scale)
 timer.ticks = nil
 end
 end
 end
 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		Line 19 should have timer.outvalue  instead of timer.value :
 Code: if timer.outvalue < timer.onvaluelow then
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		 (13.06.2022, 07:00)admin Wrote:  Line 19 should have timer.outvalue instead of timer.value:
 Code: if timer.outvalue < timer.onvaluelow then
 
Thanks for reaction. I have changed this, but error is the same:
 Code: if not client thentimers = {
 {
 input = '9/0/1', -- binary PIR status
 output = '1/1/7', -- dimmer control (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 10, -- low output value in %
 timeout = 5, -- in seconds
 }
 }
 
 function setinputvalue(timer, event)
 local value = busdatatype.decode(event.datahex, dt.bool)
 
 if not value then
 return
 end
 
 if timer.outvalue < timer.onvaluelow then
 value = timer.onvaluelow
 elseif timer.outvalue < timer.onvaluehigh then
 value = timer.onvaluehigh
 else
 value = nil
 end
 
 if not timer.ticks and value then
 grp.write(timer.output, value, dt.scale)
 end
 
 timer.ticks = timer.timeout
 end
 
 function setoutputvalue(timer, event)
 timer.outvalue = busdatatype.decode(event.datahex, dt.scale)
 timer.ticks = nil -- stop timer
 end
 
 for _, timer in ipairs(timers) do
 timer.outvalue = grp.getvalue(timer.output)
 end
 
 sender = 'tm'
 grp.sender = sender
 
 client = require('localbus').new(0.1)
 client:sethandler('groupwrite', function(event)
 if event.sender == sender then
 return
 end
 
 for _, timer in ipairs(timers) do
 if timer.input == event.dst then
 setinputvalue(timer, event)
 elseif timer.output == event.dst then
 setoutputvalue(timer, event)
 end
 end
 end)
 end
 
 client:loop(1)
 
 for _, timer in ipairs(timers) do
 if timer.ticks then
 timer.ticks = timer.ticks - 1
 
 if timer.ticks == 0 then
 grp.write(timer.output, timer.outvalue, dt.scale)
 timer.ticks = nil
 end
 end
 end
Resident script:19: attempt to compare nil with number 
stack traceback: 
 Resident script:19: in function 'setinputvalue' 
 Resident script:54: in function <Resident script:47> 
 Library localbus: in function '' 
 Library localbus: in function '' 
Libbrarary localbus: in function 'loop'
	 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		The same script works for me. Does 9/0/1 exist? 
I've added some logging, check what you get in the Logs tab:
 Code: if not client thentimers = {
 {
 input = '9/0/1', -- binary PIR status
 output = '1/1/7', -- dimmer control (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 10, -- low output value in %
 timeout = 5, -- in seconds
 }
 }
 
 function setinputvalue(timer, event)
 local value = busdatatype.decode(event.datahex, dt.bool)
 
 if not value then
 return
 end
 
 log('pir trigger', timer.outvalue)
 
 if timer.outvalue < timer.onvaluelow then
 value = timer.onvaluelow
 elseif timer.outvalue < timer.onvaluehigh then
 value = timer.onvaluehigh
 else
 value = nil
 end
 
 if not timer.ticks and value then
 grp.write(timer.output, value, dt.scale)
 end
 
 timer.ticks = timer.timeout
 end
 
 function setoutputvalue(timer, event)
 timer.outvalue = busdatatype.decode(event.datahex, dt.scale)
 timer.ticks = nil -- stop timer
 log('output change', timer.outvalue)
 end
 
 for _, timer in ipairs(timers) do
 timer.outvalue = grp.getvalue(timer.output)
 log('timer init', timer.outvalue)
 end
 
 sender = 'tm'
 grp.sender = sender
 
 client = require('localbus').new(0.1)
 client:sethandler('groupwrite', function(event)
 if event.sender == sender then
 return
 end
 
 for _, timer in ipairs(timers) do
 if timer.input == event.dst then
 setinputvalue(timer, event)
 elseif timer.output == event.dst then
 setoutputvalue(timer, event)
 end
 end
 end)
 end
 
 client:loop(1)
 
 for _, timer in ipairs(timers) do
 if timer.ticks then
 timer.ticks = timer.ticks - 1
 
 if timer.ticks == 0 then
 log('timer stop', timer.outvalue)
 grp.write(timer.output, timer.outvalue, dt.scale)
 timer.ticks = nil
 end
 end
 end
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		I modified the code and it still did not work. I searched for a while, until I found the ultimate solution: reboot the device. After that, the error messages were immediately gone, and the script works. I can't explain it, but fortunately it's solved. Thank you, thank you!
 I'm still running into a problem, and I also have a question about applying this script to other lamps inside and outside the house:
 
 Problem:
 If the script is running and has turned the lamp up when there is movement, and then within the set time period the lamp is turned off (for example, because we are going to bed), then the script turns the lamp - after the set time has expired - back on to its original dimming status. Unfortunately, this was not the intention. The lamp should then remain off. Is there a solution for this?
 
 Question:
 Is it possible to indicate in the script for each PIR via a separate object whether it is active or not?
 And is it possible to include a PIR twice in the timers table. For example, an outdoor lamp in the backyard in winter has a different behaviour than in summer?
 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		A separate timer on/off object can be added as well as another on/off object to monitor manual lamp operation. What should happen when the lamp is turned on manually? Which level should the script use?
	 
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
		
		
		17.06.2022, 17:01 
(This post was last modified: 17.06.2022, 17:22 by Dirk79.)
		
	 
		 (17.06.2022, 14:18)admin Wrote:  A separate timer on/off object can be added as well as another on/off object to monitor manual lamp operation. What should happen when the lamp is turned on manually? Which level should the script use? 
Super that this is possible! 
Preferably, the lamp returns to its last initial position. That is, the position the lamp was in the last time, before movement was detected. 
E.g. the lamp is on 35%, it is turned to 90% by the script and is then turned off manually or by another script or a scene. The next time the lamp is turned on manually (or by a scene), it should start at 35%. 
But if that results in a very complex script, then a fixed value, e.g. 30%, is also good.
 
Thanks.
	 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		Updated version with an optional timer on/off object and status monitoring. For this to work the dimmer must have a status output active and should report the status as soon as possible (some dimmers have an option to report status when only after a transition). When the script writes its output value it will ignore the status report for 1 second. This can be lowered (line 53) to prevent possible issues when a manual control is performed at the same moment as the scripted control. Code: if not client thentimers = {
 {
 input = '1/1/1', -- binary PIR status
 enable = '1/1/2', -- enable timer on/off
 output = '1/1/3', -- dimmer control (0..100%)
 status = '1/1/4', -- dimmer status (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 10, -- low output value in %
 timeout = 5, -- in seconds
 }
 }
 
 function setoutputvalue(timer, value)
 timer.ignoresec, timer.ignoreusec = os.microtime()
 grp.write(timer.output, value, dt.scale)
 end
 
 function settimerstate(timer, event)
 timer.enabled = busdatatype.decode(event.datahex, dt.bool)
 timer.ticks = nil
 
 log('timer enabled', timer.enabled)
 end
 
 function setinputvalue(timer, event)
 local value = busdatatype.decode(event.datahex, dt.bool)
 
 if not value or not timer.enabled then
 return
 end
 
 log('pir trigger', timer.statvalue)
 
 if timer.statvalue < timer.onvaluelow then
 value = timer.onvaluelow
 elseif timer.statvalue < timer.onvaluehigh then
 value = timer.onvaluehigh
 else
 value = nil
 end
 
 if not timer.ticks and value then
 setoutputvalue(timer, value)
 end
 
 timer.ticks = timer.timeout
 end
 
 function setstatusvalue(timer, event)
 if timer.ignoresec then
 local delta = os.udifftime(timer.ignoresec, timer.ignoreusec)
 if delta >= 0 and delta <= 1 then
 return
 end
 
 timer.ignoresec = nil
 end
 
 if timer.enabled then
 timer.statvalue = busdatatype.decode(event.datahex, dt.scale)
 timer.ticks = nil -- stop timer
 log('output change', timer.statvalue)
 end
 end
 
 for _, timer in ipairs(timers) do
 timer.statvalue = grp.getvalue(timer.status) or 0
 
 if timer.enable then
 timer.enabled = grp.getvalue(timer.enable)
 else
 timer.enabled = true
 end
 
 log('timer init', timer.statvalue, timer.enabled)
 end
 
 sender = 'tm'
 grp.sender = sender
 
 client = require('localbus').new(0.1)
 client:sethandler('groupwrite', function(event)
 if event.sender == sender then
 return
 end
 
 for _, timer in ipairs(timers) do
 if event.dst == timer.enable then
 settimerstate(timer, event)
 elseif event.dst == timer.switch then
 setswitchvalue(timer, event)
 elseif event.dst == timer.input then
 setinputvalue(timer, event)
 elseif event.dst == timer.status then
 setstatusvalue(timer, event)
 end
 end
 end)
 end
 
 client:loop(1)
 
 for _, timer in ipairs(timers) do
 if timer.ticks then
 timer.ticks = timer.ticks - 1
 
 if timer.ticks == 0 then
 log('timer stop', timer.statvalue)
 setoutputvalue(timer, timer.statvalue)
 timer.ticks = nil
 end
 end
 end
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		 (22.06.2022, 10:29)admin Wrote:  Updated version with an optional timer on/off object and status monitoring. For this to work the dimmer must have a status output active and should report the status as soon as possible (some dimmers have an option to report status when only after a transition). When the script writes its output value it will ignore the status report for 1 second. This can be lowered (line 53) to prevent possible issues when a manual control is performed at the same moment as the scripted control.
 
 Code: if not client thentimers = {
 {
 input = '1/1/1', -- binary PIR status
 enable = '1/1/2', -- enable timer on/off
 output = '1/1/3', -- dimmer control (0..100%)
 status = '1/1/4', -- dimmer status (0..100%)
 onvaluehigh = 90, -- high output value in %
 onvaluelow = 10, -- low output value in %
 timeout = 5, -- in seconds
 }
 }
 
 function setoutputvalue(timer, value)
 timer.ignoresec, timer.ignoreusec = os.microtime()
 grp.write(timer.output, value, dt.scale)
 end
 
 function settimerstate(timer, event)
 timer.enabled = busdatatype.decode(event.datahex, dt.bool)
 timer.ticks = nil
 
 log('timer enabled', timer.enabled)
 end
 
 function setinputvalue(timer, event)
 local value = busdatatype.decode(event.datahex, dt.bool)
 
 if not value or not timer.enabled then
 return
 end
 
 log('pir trigger', timer.statvalue)
 
 if timer.statvalue < timer.onvaluelow then
 value = timer.onvaluelow
 elseif timer.statvalue < timer.onvaluehigh then
 value = timer.onvaluehigh
 else
 value = nil
 end
 
 if not timer.ticks and value then
 setoutputvalue(timer, value)
 end
 
 timer.ticks = timer.timeout
 end
 
 function setstatusvalue(timer, event)
 if timer.ignoresec then
 local delta = os.udifftime(timer.ignoresec, timer.ignoreusec)
 if delta >= 0 and delta <= 1 then
 return
 end
 
 timer.ignoresec = nil
 end
 
 if timer.enabled then
 timer.statvalue = busdatatype.decode(event.datahex, dt.scale)
 timer.ticks = nil -- stop timer
 log('output change', timer.statvalue)
 end
 end
 
 for _, timer in ipairs(timers) do
 timer.statvalue = grp.getvalue(timer.status) or 0
 
 if timer.enable then
 timer.enabled = grp.getvalue(timer.enable)
 else
 timer.enabled = true
 end
 
 log('timer init', timer.statvalue, timer.enabled)
 end
 
 sender = 'tm'
 grp.sender = sender
 
 client = require('localbus').new(0.1)
 client:sethandler('groupwrite', function(event)
 if event.sender == sender then
 return
 end
 
 for _, timer in ipairs(timers) do
 if event.dst == timer.enable then
 settimerstate(timer, event)
 elseif event.dst == timer.switch then
 setswitchvalue(timer, event)
 elseif event.dst == timer.input then
 setinputvalue(timer, event)
 elseif event.dst == timer.status then
 setstatusvalue(timer, event)
 end
 end
 end)
 end
 
 client:loop(1)
 
 for _, timer in ipairs(timers) do
 if timer.ticks then
 timer.ticks = timer.ticks - 1
 
 if timer.ticks == 0 then
 log('timer stop', timer.statvalue)
 setoutputvalue(timer, timer.statvalue)
 timer.ticks = nil
 end
 end
 end
 
Thank you again! 
With this message, I give an update of the status: 
I have been using this modified script for some time now. It works far better, but I still cannot get it to work 100% correctly. 
I would have liked to explain what is going wrong, but it is not easy since the behaviour of the script changes   . 
What have I experienced: 
Some days the script does not work at all (after restarting, this is then solved). 
My family told me that the script also worked the other way around once. So that the lamp went on, while it should have stayed off.
 
Some additional information: 
As enabler I used the status object of the lamp itself. So only if the lamp is already on, it must be made louder. 
I have also noticed that the numbers behind CPU/IO at the bottom sometimes turn red for a while. I don't know if that is relevant. I'm reporting it just to be sure.
 
Additional challenge: Because it is currently light outside for so long, it is also more difficult to see whether the script is working as desired. It is only when it is dark outside that it is noticeable when the lamp is turned up and then down again.
 
I'm going to gain more experience and as soon as I can describe better what exactly happens, I'll let you know.
	 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		Keep logs in the script enabled and also enable logging for all objects that are used by the script. Then you can find why it's not always working as intended.
	 
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
		
		
		10.12.2022, 13:14 
(This post was last modified: 10.12.2022, 13:15 by Dirk79.)
		
	 
		It took a while since my last message. It is dark much earlier now, I have more logs and I can better see when things go wrong.
 Every day the script starts as desired. It starts at 30%, but it disrupts every day. Then it will hang on the brighter setting. I have a series of logs below where you can see the sudden change at 09.12.2022 20:30:55. Hopefully this is enough information to understand the problem. If not, I'd like to share more :-).
 
 09.12.2022 23:57:23   Lights temporary brighter on PIR   *arg:1* string: timer enabled * arg: 2 * bool: false
 09.12.2022 23:31:12   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 23:31:08   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 23:30:38   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 23:30:33   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 23:00:09   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 23:00:04   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 23:00:00   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:35:09   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:35:03   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:34:12   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:34:08   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:34:04   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:33:15   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:33:11   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:32:31   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:32:27   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:32:21   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:32:16   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:30:03   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:29:58   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 21:25:42   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 21:25:37   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 20:52:51   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 20:52:46   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 20:42:57   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 20:42:53   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 20:42:15   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 20:42:10   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 20:36:23   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 20:36:18   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 20:35:36   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 90
 09.12.2022 20:35:32   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 90
 09.12.2022 20:30:55   Lights temporary brighter on PIR   *arg:1* string: output change * arg: 2 * number: 90
 09.12.2022 20:30:51   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 20:30:49   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 20:30:44   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 19:25:52   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 19:25:48   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 19:25:14   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 19:25:09   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 19:22:10   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 19:22:05   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 18:54:34   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 18:54:29   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 18:53:16   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 18:53:11   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 17:56:05   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 18:05:40   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 18:05:45   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 09.12.2022 18:06:22   Lights temporary brighter on PIR   *arg:1* string: pir trigger * arg: 2 * number: 30
 09.12.2022 18:06:27   Lights temporary brighter on PIR   *arg:1* string: timer stop * arg: 2 * number: 30
 
 
 
		
	 
	
	
	
		
	Posts: 8413 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
481 
	
	
		The status change most likely comes from a manual control. With the current logic it won't go back to low level until the light is manually switched off.
	 
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		 (13.12.2022, 11:51)admin Wrote:  The status change most likely comes from a manual control. With the current logic it won't go back to low level until the light is manually switched off. 
Thank you again!
I understand this thought, but I would still like to rule it out. To prove this, I first did a test. To my knowledge there is no other action that puts the light at exactly 90%.
 To test this, I set the value in the program to 85%. I had to restart the system for this to take effect. After this restart, the error remains the same, only the lamp is then set to 85% instead of 90%. I didn't change anything else, so I think I've confirmed that this script itself sets it to 85%.
 Every day the lamp starts at 30% according to a different script.
 I would like to know if this test is sufficient to show that the script itself chooses the higher value as the new setting, and if there is anything else I can try?
 
		
	 
	
	
	
		
	Posts: 22 
	Threads: 4 
	Joined: Nov 2019
	
 Reputation: 
0 
	
	
		Dear admin, 
I have done some additional testing. Hopefully the additional information can help to solve the problem.
 
During my last messages, the timeout period in the script was 5 seconds. I ran several tests with different timeout periods. 
The frequency at which the motion detector transmits a notification is not constant. If you just walk past it, only one trigger will come. If you stay near the motion detector, more triggers will follow each other. The interval between the triggers is usually approx. 5 seconds, but is occasionally faster (2 seconds seen as fastest) or longer. So therefore I ran several tests:
 
a) At the 5-second timeout, the lamp went brighter for a moment and also went softer again. Every time the PIR transmits a new motion trigger the lamp went back. Almost every night, the script went wrong. Not immediately, but often when there was a lot of 'traffic'. Then the lamp stayed on the higher setting. 
b) Then I ran the script on 5-minute timeout for several days. The script ran into error almost immediately every day. 
c) Then I ran the lamp on 1 second timeout for several days. When motion detection is detected, the lamp turns on slightly brighter very briefly (maximum setting is not reached) and immediately goes back down. However, the script does not run into error. Not once did the script stay on the high setting.
 
So my conclusion is that the script is disrupted when a new motion notification comes in at the moment the lamp is already burning brighter. Can this be solved by adding a rule to the script or the like?
 
I am not saying the script is incorrect. Perhaps it is because of my equipment, but clearly it is not working properly. It would be nice if a solution is available for this, because then my problem would be solved   .
  
Thanks!
	
		
	 |