lastUpdate.minutesAgo

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Post Reply
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

lastUpdate.minutesAgo

Post by dpcreel »

I have an issue and I'm probably just missing something. However I'm doing this so several motion detectors can be use in one script:

Code: Select all

return {
	on = {
		devices = {'PIR*'},
		timer = {'every minute'}
	},
	execute = function(domoticz,device,triggerInfo)
        if triggerInfo.type == domoticz.EVENT_TYPE_DEVICE and device.active then
            domoticz.devices(device.name:sub(4)).switchOn().checkFirst().silent()
        elseif triggerInfo.type == domoticz.EVENT_TYPE_TIMER then
            domoticz.devices().filter(function(device)
                return (device.name:sub(1,3) == 'PIR')
            end).forEach(function(PIRDevice)
                if not(PIRDevice.active) and PIRDevice.lastUpdate.minutesAgo >= 5 then
                    domoticz.devices(PIRDevice.name:sub(4)).switchOff().checkFirst().silent()
                end
            end)
        end
    end
}
My motion sensors are named PIR"device name" and my controlled devices are named "device name". When any motion sensor starting with PIR is active dzVents turns on the associated device. After a time period the device is then shut off as long as there is no motion.

Everything worked fine for over a year unit just recently I manually turned a light on by clicking on the device light bulb (21:54:31) in the Domoticz GUI and the light shut off the following minute. IE 21:55:00. The light is supposed to stay on for 5 minutes, I believe this was working fine when I initially wrote this. I tried turning the light on through json and the same issue occurs, but when I activate a motion sensor all works well.

I'm running the latest Domoticz beta on a rpi3.

Any ideas?
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: lastUpdate.minutesAgo

Post by waaren »

dpcreel wrote: Thursday 28 June 2018 3:34 I have an issue and I'm probably just missing something. However I'm doing this so several motion detectors can be use in one script:

Everything worked fine for over a year unit just recently I manually turned a light on by clicking on the device light bulb (21:54:31) in the Domoticz GUI and the light shut off the following minute. IE 21:55:00. The light is supposed to stay on for 5 minutes, I believe this was working fine when I initially wrote this. I tried turning the light on through json and the same issue occurs, but when I activate a motion sensor all works well.
@dpccreel,

in line 13 you check lastUpdate.minutesAgo of your motion detector. If you want your light to stay on for at least 5 minutes irrespective of the trigger by which it is switched on, you should check against the lastUpdate.minutesAgo of your light by changing line 13 from

if not(PIRDevice.active) and PIRDevice.lastUpdate.minutesAgo >= 5 then

to

Code: Select all

if not(PIRDevice.active) and domoticz.devices(PIRDevice.name:sub(4)).lastUpdate.minutesAgo >= 5 then


Please note "as of version 2.4.0, triggerInfo has become more or less obsolete and is left in here for backward compatibility. All information is now available on the second parameter of the execute function" -->> in this script device

triggerinfo might disappear in future versions so better switch now to the new method of checking what triggered the script.

From
if triggerInfo.type == domoticz.EVENT_TYPE_DEVICE and device.active then
domoticz.devices(device.name:sub(4)).switchOn().checkFirst().silent()
elseif triggerInfo.type == domoticz.EVENT_TYPE_TIMER then

Code: Select all

if device.isDevice and device.active then
            domoticz.devices(device.name:sub(4)).switchOn().checkFirst().silent()
elseif device.isTimer then
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
rogzon
Posts: 11
Joined: Monday 14 November 2016 9:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by rogzon »

Hi!
Maybe this would be another way to do this, you would get rid of the timer?

Code: Select all

return {
	on = {
		devices = {'PIR*'},
	},
	execute = function(domoticz,device,triggerInfo)
			if (device.state == 'On') then
				domoticz.devices(device.name:sub(4)).cancelQueuedCommands()
				domoticz.devices(device.name:sub(4)).switchOn().checkFirst()
			else
				domoticz.devices(device.name:sub(4)).cancelQueuedCommands()			
				domoticz.devices(device.name:sub(4)).switchOff().afterMin(5).checkFirst()
			end
    end
}
In this case any one of these PIR sensors, when sensing motion, would first cancel all the previous "afterMin(5)" and then switch it on.
You would need to cancel all the "afterMin(5)" otherwise the lights would go off despite sensing motion in a PIR.
The cancel when device.state is off is to make sure that the very last PIR, not sensing motion, is the one that issues the afterMin(5) command.
The silent() you would need only if there are triggers on the actual switch that would interfere with PIR events.
I don't have that many PIR's so this is not tested....

/R
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: lastUpdate.minutesAgo

Post by waaren »

@rogzon,

looks like a nice solution for the situation where lights are triggered by a motion sensor but this will not work when a light is switched on manually.
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

Thanks, it was written for an earlier version of dzVents, I haven't been reading the release notes as well as I should have. I corrected the outdated triggerInfo.type with isDevice or isTimer.

I want the device to shut off after given time after the motion device (PIR) shuts off. So if there is motion again basically the off timer for the device resets. This was written prior to dzVents allowing .cancelQueuedCommands(). I will probably rewrite it totally re-write this to use .cancelQueuedCommands().

When I first started using this script all my devices were relays, now a couple of the devices are wall switches. I never noticed an issue until my wife told me she just turned on the garage lights and they shut right off. This is my bad.

However, you know how sometimes you get so involved in something you can't solve the problem? That's been me and this. Thanks so much for everyones help in this.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

dpcreel wrote: Thursday 28 June 2018 16:46 Thanks, it was written for an earlier version of dzVents, I haven't been reading the release notes as well as I should have. I corrected the outdated triggerInfo.type with isDevice or isTimer.

I want the device to shut off after given time after the motion device (PIR) shuts off. So if there is motion again basically the off timer for the device resets. This was written prior to dzVents allowing .cancelQueuedCommands(). I will probably rewrite it totally re-write this to use .cancelQueuedCommands().

When I first started using this script all my devices were relays, now a couple of the devices are wall switches. I never noticed an issue until my wife told me she just turned on the garage lights and they shut right off. This is my bad.

However, you know how sometimes you get so involved in something you can't solve the problem? That's been me and this. Thanks so much for everyones help in this.
What I think is weird in your code is that you seem to be switching the PIR device off? I have Z-wave PIR devices and these act as sensors and can't be controlled from Domoticz. In Domoticz I have a switch-device, being the button on the wall or the in-wall relay that switches the light on and off, which gets controlled by the PIR device(s). Like Waaren suggested, you should first check the state and lastUpdate of the switch, and only if that is no reason to keep the light on, check if there are any PIR's that detected motion less than 5 minutes ago so the light must remain on. Something like this:

Code: Select all

if switch.state ~= 'Off' and switch.lastUpdate.minutesAgo > 5 then
	local pir_devices = domoticz.devices('PIR*')
	local off = pir_devices.reduce(
			function(acc, pir_device) 
				if pir_device.state ~= 'Off' or pir_device.lastUpdate.minutesAgo <= 5  then
				    acc = false
				end
				return acc
			end, true)
	if off then
		switch.switchOff()
	end
end
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

PIRDevice is the motion sensor, domoticc.devices(PIRDevivice.name:sub(4)) is the device being switched. i.e. - I have a motion sensor named PIRgarage_lights, the switched relay is named garage_lights. I have many motion sensors all starting with PIR ending with the name of associated relay or switch. This allows me to have one script for many many motion sensors.

I realize that there are issues with the code, I am then addressing now. It's old and not up to date. This code was written many many months ago when I the only switched devices I had were relays. Since then I have added some wall switches. I am using mostly Zwave relays and have some GE zwave wall switches.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

Just like you, I use a single script to switch many devices automatically. I only use this generic script to switch devices Off though. I can per device configure if and when it should be switched off, by putting json in the device's description field. The script is called "auto off" and I've posted it in the dzVents\Examples section. Since I have that script running I only have to switch devices On in my other scripts, which simplifies things a lot.
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

Thanks for the example, with all the new code changes in dzVents it's made coding much shorter and easier. Kudos to dannybloe!

I'll need to re-visit all my old dzVent scripts and make updates.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

dpcreel wrote: Thursday 28 June 2018 19:23 PIRDevice is the motion sensor, domoticc.devices(PIRDevivice.name:sub(4)) is the device being switched. i.e. - I have a motion sensor named PIRgarage_lights, the switched relay is named garage_lights. I have many motion sensors all starting with PIR ending with the name of associated relay or switch. This allows me to have one script for many many motion sensors.

I realize that there are issues with the code, I am then addressing now. It's old and not up to date. This code was written many many months ago when I the only switched devices I had were relays. Since then I have added some wall switches. I am using mostly Zwave relays and have some GE zwave wall switches.
dpcreel wrote: Saturday 30 June 2018 14:16 Thanks for the example, with all the new code changes in dzVents it's made coding much shorter and easier. Kudos to dannybloe!

I'll need to re-visit all my old dzVent scripts and make updates.
Given your explanation of the naming of your switches and pir devices, my example needs a little addition or the switch will remain on if any of the pir devices in your home has seen motion less than 5 minutes ago. Here's how you could make use of your naming convention to look at only the pir having the switches name after the 'PIR':

Code: Select all

if switch.state ~= 'Off' and switch.lastUpdate.minutesAgo > 5 then
	local pir_devices = domoticz.devices('PIR'..switch.name)
	local off = pir_devices.reduce(
			function(acc, pir_device) 
				if pir_device.state ~= 'Off' or pir_device.lastUpdate.minutesAgo <= 5  then
				    acc = false
				end
				return acc
			end, true)
	if off then
		switch.switchOff()
	end
end
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

I'm working on the code for this this morning and this is what I have so far. This is just for the motion activation side, I haven't done the portion that shuts off the device if it's manually triggered.

Code: Select all

return {
	on = {
		devices = {'PIR*'} --motion sensor
	},
	execute = function(domoticz,device,triggerInfo)
	    
	    local timeValue = 5 --minutes of time delay
	    
        if device.isDevice and device.active then
            domoticz.devices(device.name:sub(4)).cancelQueuedCommands()
            domoticz.devices(device.name:sub(4)).switchOn().checkFirst().silent()
        elseif device.isDevice and not(device.active) then
            domoticz.devices(device.name:sub(4)).switchOff().afterMin(timeValue).checkFirst().silent()
        end
    end
}
It looks like I still need to pass the triggerInfo in the execute function for isDevice. Is that correct?

The isDevice is in there because I plan on using isTimer for the timer portion, which I haven't done.
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

This may be off topic but Is there a way to check the QueuedCommands for a device?
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: lastUpdate.minutesAgo

Post by waaren »

dpcreel wrote: Saturday 30 June 2018 15:48 It looks like I still need to pass the triggerInfo in the execute function for isDevice. Is that correct?
triggerInfo is not needed.

Code: Select all

function(domoticz,device) -- this is enough. Just leave out the third parm
No way to check for QueuedCommands within dzvents and as far as I know now neither in domoticz itself
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

I don't know if there is a way to see the queue, if anyone can tell it is dannybloe. But why would you need it? I'm not a big fan of using these timer functions, as I personally think they are very hard to program right. If however you do use them, you don't need to add a timer event to your script. You simply set the time the switch needs to go off at the moment it is switched on. You could add a script to the switch that automatically adds the timer function when the switch is switched on and clears the queue when it is switched off. That way the switch will automatically switch off if it is not switched off manually before the time is over, plus when it is switched off the queue is cleared so the timer will not trigger an 'Off' when the light is switched on again quickly after it was switched off.

Then all you need is to trigger an 'On' from the motion sensor, which at the same time also resets the off timer on the switch every time the motion sensor detects motion.
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

I was planning on doing something similar if I can't access the device que.

I just wanted to access the que to see if there was already an off or on scheduled. Thanks for your help.
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

This is what I ended up doing.

Code: Select all

return {
	on = {
		devices = {'PIR*','LIT*'}
	},
	execute = function(domoticz,item,triggerInfo)
	    
	    local timeValue = 6 --minutes of time delay
	    
        if item.name:sub(1,3) == 'PIR' then
            if item.active then
                domoticz.devices('LIT' .. item.name:sub(4)).cancelQueuedCommands()
                domoticz.devices('LIT' .. item.name:sub(4)).switchOn().checkFirst().silent()
            else
                domoticz.devices('LIT' .. item.name:sub(4)).switchOff().afterMin(timeValue).checkFirst().silent()
            end
        elseif item.name:sub(1,3) == 'LIT' and domoticz.devices('LIT' .. item.name:sub(4)).active then
            item.cancelQueuedCommands()
            item.switchOff().afterMin(timeValue).checkFirst().silent()
        end
    end
}
The motion detector names start with PIR and associated device names start with LIT. It seems to work well so far for all motion sensors.

It think this is getting a little off topic...; but thanks to everyone for their input on this and helping me think through this.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

I think you've still got it a little to complicated. What about this?

Code: Select all

local MOTION_DEVICE = 'PIR*'
local SWITCH_DEVICE = 'LIT*'

return {
	on = {
		devices = {
			SWITCH_DEVICE,
			MOTION_DEVICE
		}
	},
	execute = function(domoticz, device)
		domoticz.log('Device ' .. device.name .. ' was changed.', domoticz.LOG_INFO)
		
		if device.name:sub(1,3) == 'LIT' then
		    if device.state == 'On' then
		        device.switchOff().afterMin(6)
		    else
		        device.cancelQueuedCommands()
		    end
	    elseif device.name:sub(1,3) == 'PIR' then
	        if device.state == 'On' then
	            local switch = domoticz.devices('LIT' .. device.name:sub(4))
	            switch.switchOn()
	        end
		end
	end
}
When a motion device changes to 'On', it switches the associated light on, even when that light was on already. Every time a light receives an 'On' command, the timer for that light is (re-)set to 6 minutes, when a light changes to 'Off' any timed commands are cancelled for that light.

Coming to think of it, I think I'm going to test this for some time and then I might change my 'auto off' script such that it employs this technique, instead of the timer event, because it fires for less events (more efficient on Domoticz, so less delays) and the lights go off after exactly the specified time, not the nearest time rounded to 1 minute after the set time as mine does now.
dpcreel
Posts: 44
Joined: Friday 25 November 2016 14:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: lastUpdate.minutesAgo

Post by dpcreel »

Great idea. Isn't it great that there's more that one way to get to the same point.

Wouldn't your script have to run twice on every motion ON? The first time when there is motion the light comes on, then run second time due to the device change of the light? Am I missing something?
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

That's correct, it will run once for the motion detector, then once more for the switch. Then, after the timer runs out or someone switches the light off, it will run once again to clear the command queue. That would be an improvement over having to run a script every minute to check all devices every minute over and over again.

BUT, I've written the new script and I've run into a problem: my motion sensors have a feature -and I think most sensor have it- that is ment to keep the light on when there is still motion in the room. As a result, the motion device will stay 'On' and it won't send the next 'On' commands that my script needs to reset the timer. Once the timer expires, it will turn off the switch: The lights will go off, even when I'm still in the room. In my previous solution I used the fact that the motion detector was still on to inhibit the lights from going off, but since in this solution I don't get triggered again after the time expires, I don't get another event to switch the lights off any more. At least for now, I'll have to go back to my original solution using the timer event.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: lastUpdate.minutesAgo

Post by rrozema »

For anyone who wants to try it for themselves. Here's the code I wrote for "Auto Off v2". This is NOT "production"-ready. It works, but it has a problem that the lights will go off while you're still in the room and moving, because the motion sensor doesn't re-send an 'On' command while it is still seeing motion. :o

Code: Select all

return {
	on = {
		devices = {
			'*'
		}
	},
	execute = function(domoticz, device)
		
		if device.isDevice then
    		-- Only if we got fired because of a device trigger.
--    		domoticz.log('Device ' .. device.name .. ' was changed', domoticz.LOG_INFO)
    		
		    if device.switchType == 'Motion Sensor' then
    		    -- If a motion sensor switches on, we may have to switch one or more devices on.
    		    
    		    if device.state == 'On' then
    	            local description = device.description
    	            if description ~= nil and description ~= '' then
    	                --domoticz.log( 'description = ' .. description .. '.', domoticz.LOG_INFO)
    	                local ok, settings = pcall( domoticz.utils.fromJSON, description)
    	                if ok and settings ~= nil then
                            
--                            domoticz.log( 'Device: "' .. device.name .. '" type "' .. type(settings.slave_device) .. '".', domoticz.LOG_INFO)
                            
    	                    if type(settings.slave_device) == "string" then
    	                        domoticz.devices(settings.slave_device).switchOn()
    	                    elseif type(settings.slave_device) == "table" then
                                for i,v in ipairs(settings.slave_device) do
                                    domoticz.devices(v).switchOn()
                                end
                            else
                                domoticz.log( 'Device: "' .. device.name .. '" unknown type "' .. type(settings.slave_device) .. '" encountered for "slave_device".', domoticz.LOG_INFO)
    	                    end
--                        else
--                            domoticz.log( 'Device description for "'.. device.name ..'" is not in json format. Ignoring this device.', domoticz.LOG_INFO)
                        end
                    end
                end

		        
--		    elseif device.switchType == 'Door Contact' then
--    		    -- Or if a door contact changes state, we may have to switch some device.
		        
            else
--                domoticz.log( 'Device "' .. device.name .. '" is" ' .. tostring(device.state) .. '".', domoticz.LOG_INFO)

                -- Any other type of device we may need to switch off after
                -- some time.
                if device.state ~= 'Off' then
                    -- If the new state is anyhting but 'Off', queue an
                    -- 'Off' command to execute after x seconds. This 
                    -- will also reset any previous queued 'Off' command.

    	            local description = device.description
    	            if description ~= nil and description ~= '' then
    	                --domoticz.log( 'description = ' .. description .. '.', domoticz.LOG_INFO)
    	                local ok, settings = pcall( domoticz.utils.fromJSON, description)
    	                if ok and settings ~= nil then
	                        local seconds = tonumber(settings.auto_off_seconds)
	                        local minutes = tonumber(settings.auto_off_minutes)
	                        if seconds == nil and minutes == nil then
                                domoticz.log( 'Device ' .. device.name .. ' does not have an auto-off time. Ignoring this device.', domoticz.LOG_INFO)
                            else
                                if seconds == nil then
                                    seconds = minutes * 60
                                elseif minutes ~= nil then
                                    seconds = seconds + minutes * 60
                                end
                                    
                                domoticz.log( 'Device "'.. device.name ..'" is "' .. tostring(device.state) .. '", queueing Off command in ' .. tostring(seconds) .. ' seconds.', domoticz.LOG_INFO)
                                device.switchOff().afterSec(seconds)
                            end
                        else
                            domoticz.log( 'Description for '.. device.name ..' is not valid json. Ignoring this device.', domoticz.LOG_INFO)
                        end
--                    else
--                        domoticz.log( device.name ..' is ' .. tostring(device.state) .. '.', domoticz.LOG_INFO)
                    end
                else
                    -- And if the new state is 'Off' we don't need any more
                    -- queued Off commands for this device so we cancel 
                    -- any commands that may still be queued for us.

                    domoticz.log( device.name ..' is ' .. tostring(device.state) .. ', cancelling queued commands.', domoticz.LOG_INFO)
                    device.cancelQueuedCommands()
                end
            end
        elseif device.isTimer then

        end
	end
}
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 1 guest