Scene notification only on action

I have a scene that is launched on a time schedule that checks to make sure the doors are locked and locks them if they aren’t. I want to get notified only when it has to lock an unlocked door, but so far the only notifications I can set up are every time the scene runs.

Is it possible to do what I’m looking for?

Simple. In the scene’s LUA code, check the status of the door lock. If the door is already locked, then abort the scene.

Refer to http://forum.micasaverde.com/index.php/topic,18679.0.html for information on “Conditional Scene Execution”.

Be sure to also look at PLEG, as a solutiion as well.

[quote=“greggstrickland, post:1, topic:184165”]I have a scene that is launched on a time schedule that checks to make sure the doors are locked and locks them if they aren’t. I want to get notified only when it has to lock an unlocked door, but so far the only notifications I can set up are every time the scene runs.

Is it possible to do what I’m looking for?[/quote]

I use PLEG for this.

make a condition that when scene X becomes true and if Door X is unlocked or Y Door is unlocked then fire action of send notification.

And you can roll that all into one action to check then if any true send lock command to all and send notification that one was unlocked. If you want specific notifications on which was unlocked then you need to split them up into different conditions.

For some reason I’m just not getting it. I think my problem may be a basic confusion with the UI7. I attached the screen of what I’m looking at. What I expected was to have the scene started, the LUUP code executed and then the scene either stops or continues.

This is the LUUP code I’m using to determine if the lock is open and it is at night:

local lockState= luup.variable_get ("urn:micasaverde-com:serviceId:DoorLock1", "Status", 5) -- only run if the lock is unlocked if (lockState== "0") then -- Only run at night return luup.is_night() End return false

but regardless of the code I still get the e-mail that the scene was run. I’m trying to do this without 3rd party apps just to learn the base system before moving forward.

Thanks

Logic would assume that “lockState” is not being set correctly (i.e. never becomes “0”).

Your variable_get statement does not look right to me. I am not home right now, so I cannot look up the correct syntax. If no one else has replied by then, I will see what I can find this evening.

I haven’t had the pleasure of UI7 yet, so cannot comment on your placement of the LUA code. You might want to see if you can abort the scene with just a single return statement, to see if you got that right.

I also avoid UI7 like the plague. I probley can’t help you much with that.

When I watch all the video tutorials they all look really easy to do what I want, but they all use the old UI. I needed the latest to use my Linear garage door opener.

Well eventually you’ll use PLEG anyways, so… ;D

Any update on this problem, greggstrickland?

Like I said, the syntax does not look correct to me, but I admit that I have not seen all of the possible variations. I only interrogate my locks from my phone, so I am using a different interface (http).

However, I think this might work better (not sure though):

luup.variable_get(“urn:upnp-org:serviceId:DoorLock1”, “Status”, 5)

This is assuming that your lock is device #5.

As far as solving your problem, the first thing I would be doing is checking to see if the one statement “return true” and “return false” works like expected. This would demonstrate that you are entering the LUA code in the right place. I would then add the luup.is_night() call and get that working. Then add the check for the door lock.

Also consider using the kwiklog procedure calls to debug your code. You can find the kwiklog source and instructions in the “conditional scene execution” thread.

kwikLog works great for debugging. I haven’t had too much time to work on it, but verified using kwikLog that the variable_get isn’t working the way I thought. It doesn’t seem to be returning the right status (neither my original, nor the one you suggested). I will keep playing with it.

I will be interested in what you find out.

BTW - If you have not already noticed, Vera is exetremely case sensitive, especially in the service id strings. Took me a week to realize that I had one letter in the wrong case when attempting to send a dimming command to a light.

kwikLog works great for debugging. I haven't had too much time to work on it, but verified using kwikLog that the variable_get isn't working the way I thought. It doesn't seem to be returning the right status (neither my original, nor the one you suggested). I will keep playing with it.

A service ID of “urn:micasaverde-com:serviceId:DoorLock1” and variable name “Status” should work - assuming you have the device number correct. If the service ID, variable name or device number are not correct, luup.variable_get(…) usually returns the value nil.

To check, hover your mouse over the name of the variable in the device’s Advanced tab which should show you the correct service ID.

I will keep playing with it.

Have a look at LuaTest. It is designed to make it much easier to play with Lua code for scenes.

OK, I don’t know why, but I had to break the variable_get down using variables before it would work.

This did not work:
local varState= luup.variable_get (“urn:micasaverde-com:serviceId:DoorLock1”, “Status”, 5)

While this worked:
local varEntryDoor = 5
local varSID = “urn:micasaverde-com:serviceId:DoorLock1”
local varState = luup.variable_get (varSID, “Status”, varEntryDoor)

This returns 0 for unlocked, and 1 for locked. Now I can continue with my original tests/questions. I will report back. Thanks!

OK, I don't know why, but I had to break the variable_get down using variables before it would work.

There may have been a non-printing character lurking in one of the strings. This can happen sometimes when you copy/paste from formatted text. It is less likely to happen if you use the Paste as plain text option from the context menu (when available).

There were hidden characters. I typed it manually and it worked.

I also could not find a way in UI7 to notify me only if an action takes place, so I ended up doing it all inside the lua code.

In the current code I detect if the door is unlocked and then lock it. I do the same with my Linear garage door opener. I had code to pause and check to make sure the action happened, but I was sleeping for too long and still getting a failed to lock even though reality was a success.

Here is my code (I borrowed the SMTP code from the forums). Rather than send one e-mail for each event I append the messages and send them once:

[code]local function notify(BODY)
local smtp = require(“socket.smtp”)

local SMTP_SERVER = "smtp.server.net"
--local SMTP_AUTH_USER = "guessed"
--local SMTP_AUTH_PW = "xxxxxxxxx"        
local SMTP_PORT = "25"
local USER_SENDING = "me@me.com"
local USER_RECEIVING = "1115551234@txt.att.net"
local SUBJECT = "Vera Alert"
--local BODY = "Test"

local from = USER_SENDING
local rcpt = {USER_RECEIVING}

local mesgt = {
	headers = {
		to = USER_RECEIVING,
		subject = SUBJECT
	},
	body = BODY
}

local r, e = smtp.send{
	from = from,
	rcpt = rcpt, 
	source = smtp.message(mesgt),
	server = SMTP_SERVER,
	port = SMTP_PORT,
	--user = SMTP_AUTH_USER,
	--password = SMTP_AUTH_PW
}

if (e) then
	luup.log("SMTP ERROR: " ..  e)
end

end

local message = “”

– only run at night
if ( luup.is_night() ) then
– Check the Entry Door (0 is unlocked) kwikset lock
local varEntryState = luup.variable_get (“urn:micasaverde-com:serviceId:DoorLock1”, “Status”, 7)
if (varEntryState== “0”) then
message = message … “\nEntry Door is Unlocked! Attempting to Lock!”
luup.call_action (“urn:micasaverde-com:serviceId:DoorLock1”, “SetTarget”, { newTargetValue=“1” }, 7)
end

-- Check Garage Door (1 is open) Linear garage door opener
local varGarageState = luup.variable_get ("urn:upnp-org:serviceId:SwitchPower1", "Status", 8)
if (varGarageState== "1") then
	message = message .. "\nGarage Door is Open! Attempting to Shut!"
	luup.call_action ("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", { newTargetValue="0" }, 8)
end

end

if (message ~= “”) then
notify(message)
end[/code]

I’m following along on this thread but man this would have been over a few days ago with PLEG.

For me to appreciate PLEG I need to do things the hard way :slight_smile: I’m stubborn like that…

… although I have to ask … if UI7 was just released not too long ago, and everyone love PLEG… why wouldn’t they put a lot of the functionality in natively? From the videos of the older UI’s I’ve seen they look more intuitive. I’m new though so may not have the full picture.

[quote=“greggstrickland, post:18, topic:184165”]For me to appreciate PLEG I need to do things the hard way :slight_smile: I’m stubborn like that…

… although I have to ask … if UI7 was just released not too long ago, and everyone love PLEG… why wouldn’t they put a lot of the functionality in natively? From the videos of the older UI’s I’ve seen they look more intuitive. I’m new though so may not have the full picture.[/quote]

Ehhhh That’s anyones guess.

But PLEG has a learning curve also. Might be to hard for some.

I made a few changes so I thought I would share. Nothing new… I gathered bits and pieces from all over the forums to put this together.

My biggest problem was when I opened my garage door at the exact same moment the scene ran and the door immediately closed on me. Because of this I decided to monitor when the status for the device was last changed. To do this I used luup.variable_watch in the startup.lua

[code]
function EntryTimeStamp()
LastEntryStatus = os.time()
end
luup.variable_watch(“EntryTimeStamp”, “urn:micasaverde-com:serviceId:DoorLock1”, “Status”, 7)

function GarageTimeStamp()
LastGarageStatus = os.time()
end
luup.variable_watch(“GarageTimeStamp”, “urn:upnp-org:serviceId:SwitchPower1”, “Status”, 8)[/code]

Now whenever the device is locked/unlocked/etc the variables LastEntryStatus or LastGarageStatus update with the current os.time(). The only thing you need to watch for is if the device has yet to change state (ie system reboot) then these variables will be null.

I also left the kwikLog code in I used for debugging because I found it so useful. Anything you log using this will show up at /kwikLog.txt (ie 192.168.8.100/kwikLog.txt)

I also have the option to report only without actually doing anything (I use this during the day). Because of this I included code to throttle back the alerts since we never automatically fix the conditions we’re checking for.

I execute everything in 2 passes. The first pass checks the devices and then corrects any issues or exits if no action is needed. If it does change the device it will pause and make the second pass to verify the action was successful. It then alerts you via SMTP as to what was done (if anything).

My scene just runs on a timed interval and the only thing it does is execute this code. I tried to comment as much as possible but feel free to ask questions. Also, I’m still new to this so any advice is appreciated. Thanks to everyone who helped…

[code]local function kwikLog(message, clear)
local socket = require(“socket”)
local time = socket.gettime() or os.time()
local tms = string.format(“.%03d “,math.floor (1000 * (time % 1)))
local stamp = os.date(”%d %b %Y %T”,math.floor(time)) … tms
local mode = “a+”
if clear then mode = “w+” end
local file = io.open(“/www/kwikLog.txt”, mode)
file:write(stamp … (message or “”) … “\n”)
file:close()
end

local function notify(BODY)
local smtp = require(“socket.smtp”)

local SMTP_SERVER = "smtp.yourisp.net"
--local SMTP_AUTH_USER = "guessed"
--local SMTP_AUTH_PW = "xxxxxxxxx"        
local SMTP_PORT = "25"
local USER_SENDING = "me@address.com"
local USER_RECEIVING = "1234567890@txt.att.net"
local USER_RECEIVING2 = "0123456789@txt.att.net"
local SUBJECT = "Vera Alert"
--local BODY = "Test"

local from = USER_SENDING
local rcpt = {
         USER_RECEIVING,
         USER_RECEIVING2
    }

local mesgt = {
	headers = {
		to = USER_RECEIVING,
		subject = SUBJECT
	},
	body = BODY
}

local r, e = smtp.send{
	from = from,
	rcpt = rcpt, 
	source = smtp.message(mesgt),
	server = SMTP_SERVER,
	port = SMTP_PORT,
	--user = SMTP_AUTH_USER,
	--password = SMTP_AUTH_PW
}

if (e) then
	luup.log("SMTP ERROR: " ..  e)
end

end

kwikLog(“Doing my thing”, true)
local message = “”
local actionDoor = “”
local actionGarage = “”
local reportOnly = false – Do we actually lock the door or just report it unlocked
local checkEntry = false – Used to know when to doublecheck lock
local checkGarage = false – Used to know when to doublecheck shut
local maxTimeOpen = 900 – Sets how long (in seconds) since last status change before you lock/shut the device
local reportInterval = 900 – Sets the minimum interval you will be notified when in report only mode

if (not LastEntryStatus) then LastEntryStatus = os.time() end – On system restart this may not be set yet
local timeSinceEntryChange = os.time() - LastEntryStatus – Prevents door from shutting/locking on you
local minutesSinceEntryChange = timeSinceEntryChange / 60 – convert to minutes for reporting
minutesSinceEntryChange = math.floor(minutesSinceEntryChange)

if (not LastGarageStatus) then LastGarageStatus = os.time() end – On system restart this may not be set yet
local timeSinceGarageChange = os.time() - LastGarageStatus – Prevents door from shutting/locking on you
local minutesSinceGarageChange = timeSinceGarageChange / 60 – convert to minutes for reporting
minutesSinceGarageChange = math.floor(minutesSinceGarageChange)

– This puts the code into reportOnly mode during the daytime
if (not luup.is_night()) then reportOnly = true end

kwikLog(“Outside of loop”)
– Run loop twice to verify lock/shut was successful
– Loop 1 will check and lock/shut
– Loop 2 will verify success (will not run if loop 1 did nothing)
for i=1,2 do

kwikLog("I’m here for pass " … i)

-- Check the Entry Door (0 is unlocked)
local varEntryState = luup.variable_get ("urn:micasaverde-com:serviceId:DoorLock1", "Status", 7)
if (varEntryState== "0" and reportOnly == false) then
	
	if (checkEntry == true) then
		-- This is the second pass and the door failed to lock
		message = message .. "\nDOOR FAILED TO LOCK! CHECK IT!"
	else
		-- This is the first pass so try and lock the door if enough time has passed
		if (timeSinceEntryChange > maxTimeOpen) then
			message = message .. "\nEntry Door has been unlocked for " .. minutesSinceEntryChange .. " minutes! Attempting to Lock!"
			luup.call_action ("urn:micasaverde-com:serviceId:DoorLock1", "SetTarget", { newTargetValue="1" }, 7)
			checkEntry = true
		end
	end
elseif (checkEntry == true and reportOnly == false) then
	-- This is the second pass and the door was successfully lovked last pass
	mmessage = message .. "\nDoor was locked!"
elseif (varEntryState== "0" and reportOnly == true) then
	-- Don't do anything, just report that the door isn't locked
	if (timeSinceEntryChange > reportInterval) then
		-- This is to prevent from SPAMing because the door is never locked by this code
		message = message .. "\nReport Only: Entry Door has been unlocked for " .. minutesSinceEntryChange .. " minutes!"
	end
end

-- Check Garage Door (1 is open)
local varGarageState = luup.variable_get ("urn:upnp-org:serviceId:SwitchPower1", "Status", 8)
if (varGarageState== "1" and reportOnly == false) then

	if (checkGarage == true) then
		-- This is the second pass and the garage failed to close
		message = message .. "\nGARAGE FAILED TO CLOSE! CHECK IT!"
	else
		-- This is the first pass so try and shut the door if enough time has passed
		if (timeSinceGarageChange > maxTimeOpen) then
			message = message .. "\nGarage Door has been open for " .. minutesSinceGarageChange .. "minutes! Attempting to Shut!"
			luup.call_action ("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", { newTargetValue="0" }, 8)
			checkGarage = true
		end
	end
elseif (checkGarage == true and reportOnly == false) then
	-- This is the second pass and the garage was successfully shut last pass
	message = message .. "\nGarage door was shut!"
elseif (varGarageState== "1" and reportOnly == true) then
	-- Don't do anything, just report that the door isn't closed
	if (timeSinceGarageChange > reportInterval) then
		-- This is to prevent from SPAMing because the door is never closed by this code
		message = message .. "\nReport Only: Garage Door has been open for " .. minutesSinceGarageChange .. "minutes!"
	end
end

if (message == "") then 
	-- No actions were taken on first pass so we can stop now
	kwikLog("Finished my thing")
	return
end

if (reportOnly == true) then
	-- Since we are just reporting we can end now
	notify(message)
	kwikLog("Finished my thing")
	return
end

-- Pause for 120 seconds after first run and check again (to give devices time to report back)
if (i == 1) then luup.sleep(120000) end

end
– Let the users know what happened
kwikLog(“Finished my thing”)
notify(message)[/code]