Issue with getting device info using Luup.devices command

Hi all,
I’m trying to create a scene using Luup script that checks all of my window & door sensors to see if they’re tripped or not. I know that I can create a bunch of if/then statements with the device id hard coded for each sensor i currently have, then add a new if/then statement with the device I’d whenever I add another sensor. BUT, I’d rather have my scene check for all devices of the correct type, then loop through them. Obviously this is better because my scene automatically checks new sensors without me having to add them manually. I’ve been fooling around with the Luup.devices command to accomplish this, but my first issue is that it appears that there my device ids are not contiguous and it causes my scene to error and stop. Below is my test code which loops through device ids 21 through 32, and logs whether or not a actual device is present for that I’d number. This is not working, as you can see below the script, I copied the Luup log entries that are produced. When this scene runs. The first id number (21) has an actual device (my wife’s garage door sensor,) and the log output is beautiful, but the next ID number (22) has no device and it appears to break. Can anyone explain why it breaks and how I can fix my script? Perhaps there’s an easier way to get all of my sensor devices loaded into an array for easy access???

for d=21,32 do
if luup.devices[d].id == nil then
luup.log(‘=> No device with that id!’)
else
luup.log('===>Device # ’ … d … ’ id: ’ … luup.devices[d].id … ’ name: ’ … luup.devices[d].description … ’ type: ’ … luup.devices[d].device_type … ’ category: ’ … luup.devices[d].category_num)
end

Luup.log entries
50 05/13/14 23:31:30.591 luup_log:0: ===>Device # 21 id: 18 name: C Garage Door type: urn:schemas-micasaverde-com:device:DoorSensor:1 category: 4 <0x2e2bd680>
01 05/13/14 23:31:30.591 e[31;1mLuaInterface::CallFunction_Scene Scene 52 failed [string “function scene_51()…”]:12: attempt to index field ‘?’ (a nil value)e[0m <0x2e2bd680>

There will be no entry in the luup.device() table for any device that has been deleted. If you are searching through the table by device number, you need to test for a nil entry before attempting to index it. An alternative is to use something like:

for deviceNo,d in pairs(luup.devices) do if d.device_type == "<device-type-you-want>" then luup.log('===>Device # ' .. deviceNo .. ' id: ' .. d.id .. ' name: ' .. d.description .. ' type: ' .. d.device_type .. ' category: ' .. d.category_num) end end

Rex, thanks for sending me in the right direction! I created the following script around your suggested code and it mostly works. One issue though. When I uncomment the four lines of code at the end, I get Lua errors. Is there an issue with my syntax or is it an issue with calling local variables?

local vol = 60
local son = 33
local devcnt = 0
local numopen = 0
luup.log(‘Commencing device search loop’)
for deviceNo,d in pairs(luup.devices) do
if d.category_num == 4 then
luup.log('===>Device # ’ … deviceNo … ’ id: ’ … d.id … ’ category: ’ … d.category_num … ’ room: ’ … d.room_num … ’ name: ’ … d.description … ’ type: ’ … d.device_type)
local tripped = luup.variable_get(d.device_type, “Tripped”, d.id)
if (tripped == “1”) then
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”,
{Text=d.description … " is Open", Language=“en”, Volume=vol}, son)
luup.log(d.description … " status was " … tripped)
numopen = numopen + 1
else
luup.log(d.description … " status was " … tripped)
end
devcnt = devcnt + 1
end
end
–[[
if numopen == 0 then
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”, {Text=“All windows and doors are closed”, Language=“en”, Volume=vol}, son)
end
–]]
luup.log(‘All done! There were ’ … devcnt … ’ door/window sensors found and … ’ numopen ’ … open’)

maybe you could also try looping through and using devices with the parent id of your alarm pane.

luup.log('All done! There were ' .. devcnt .. ' door/window sensors found and .. ' numopen ' .. open')

Should be

luup.log('All done! There were ' .. devcnt .. ' door/window sensors found and ' .. numopen .. ' open')

akbooer, thanks for catching my errant apostrophe. I fixed that part and the lua code stopped causing an error. Now I have another issue. I modified my code so that inside the for loop, I’m checking the tripped status of each device. Unfortunately, this command keeps failing when I run the scene. It works fine with an actual number, but I can’t seem to use a variable in its place. It seems that the d.id works in my luup.log line, but doesn’t work in the local tripped = line. I’ve tried several ways to pass the id f the device but they all do not work. The code is below with the two lines I’m talking about in bold and the lua log errors are below that. Any help would be greatly appreciated!

local vol = 10
local son = 33
local devcnt = 0
local devno = 0
local numopen = 0
luup.log(‘Commencing device search loop’)
for deviceNo,d in pairs(luup.devices) do
if d.category_num == 4 then
luup.log(‘Device #’ … deviceNo … ’ id:’ … d.id … ’ category:’ … d.category_num … ’ room:’ … d.room_num … ’ name:’ … d.description … ’ type: ’ … d.device_type)

local tripped = luup.variable_get(“urn:micasaverde-com:serviceId:SecuritySensor1”, “Tripped”, d.id)
if (tripped == “1”) then
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”, {Text=d.description … " is Open", Language=“en”, Volume=vol}, son)
luup.log(d.description … " status was " … tripped)
numopen = numopen + 1
else
luup.log(d.description … " status was " … tripped)
end
devcnt = devcnt + 1
end
end
if numopen == 0 then
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”, {Text=“All windows and doors are closed”, Language=“en”, Volume=vol}, son)
end

luup.log(‘All done! There were ’ … devcnt … ’ door/window sensors found and ’ … numopen ’ … open’)

<=======================>

50 05/15/14 11:18:57.969 luup_log:0: Commencing device search loop <0x2d8c3680>
50 05/15/14 11:18:57.970 luup_log:0: Device #21 id:18 category:4 room:8 name:C Garage Door type: urn:schemas-micasaverde-com:device:DoorSensor:1 <0x2d8c3680>
01 05/15/14 11:18:57.971 e[31;1mLuaInterface::CallFunction_Scene Scene 52 failed [string “function scene_51()…”]:27: attempt to concatenate local ‘tripped’ (a nil value)e[0m <0x2d8c3680>

Use deviceNo instead of d.id. d.id is the node of Z-Wave devices.

A trick to avoid code errors in these circumstances is to do this:

local tripped = luup.variable_get(“urn:micasaverde-com:serviceId:SecuritySensor1”, “Tripped”, deviceNo) or “Nil”

This will give tripped the string value “Nil” if the luup.variable_get(…) returns nil. At least it will show-up in the log.

Rex, Thanks for the info. every time I think I understand, something new comes up that I didn’t know! Anyway, the loop works great, but now, I get an error in the if section after the loop. It appears that the numopen variable I use in the loop no longer has a value. I’m aware that in Lua, local variables have a limited scope depending on the block or section they’re declared in. I thought that by declaring numopen at the top of the code, it would be accessible everywhere within my code. Perhaps that’s not even the issue. Anyway, here’s the if code section followed by the error from the log.

if numopen == 0 then
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”, {Text=“All windows and doors are closed”, Language=“en”, Volume=vol}, son)
end

<====================>

01 05/15/14 12:43:56.111 e[31;1mLuaInterface::CallFunction_Scene Scene 52 failed [string “function scene_51()…”]:34: attempt to call local ‘numopen’ (a number value)e[0m <0x2d4c1680>

Declaring the variable ahead of the for loop should make it accessible both inside the loop and after it. Anyway, the error does not say it has a nil value but that you are trying to call it… The error also indicates that the problem is at line 34 but the code you posted earlier is only 26 lines. Please post your current code.

If you post it as code (use the # button), we can see the exact lines.

Rex, again, thanks for all you expert advice. Somehow it’s working and I’m not so sure what I did. I think I’ve been mostly committing syntax errors and eventually worked them out. I have one more piece of the code to test and then I’ll post it here for anyone else who might want a similar scene.
Thanks! Pasqual

Ok, so it’s finally working reliably. This script checks for all connected door/window sensors and announces how many there are and if any are open (tripped.) I plan to have two scenes, one for upstairs sonos and one for downstairs. The variables should be self explanatory.

Please Note: This scene requires the Sonis plugin to work correctly!

Feel free to reply with questions, comments, improvements, etc. Just needs some polish to make the speech slower and it will be dynamite!

– Door/Window sensor check and speech annotation by Pasqual Zottola
local vol = 50
local son = 27 --mast bdr =33, kitch=27
local devcnt = 0
local devno = 0
local numopen = 0
local isare = “is”
local opensensors = " "
luup.log(‘Commencing sensor device search loop’)
for deviceNo,d in pairs(luup.devices) do
if d.category_num == 4 then

  local tripped = luup.variable_get("urn:micasaverde-com:serviceId:SecuritySensor1", "Tripped", deviceNo) or "Nil"
  
  if (tripped == "1") then
     opensensors = opensensors .. ". " .. d.description
     --[[ This line will change to recording info to an array so sonos speaks only once.

luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”,
{Text=d.description … " is Open", Language=“en”, Volume=vol}, son)
–]]
– luup.log(d.description … " status was " … tripped)
numopen = numopen + 1
end
luup.log(d.description … ’ status:’ … tripped … ’ Dev #’ … deviceNo … ’ id:’ … d.id … ’ cat #:’ … d.category_num … ’ type:’ … d.device_type)
devcnt = devcnt + 1
end
end
if numopen == 0 then --If there are no sensors tripped, log and announce!
luup.log(‘There were ’ … devcnt … ’ door and window sensors found and all are closed’)
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”, {Text=“There were " … devcnt … " door and window sensors found, and all are closed”, Language=“en”, Volume=vol}, son)

else --If there are any sensors tripped, log and announce!
if numopen > 1 then
isare = “are”
end
luup.log(‘There were ’ … devcnt … ’ door and window sensors found and ’ … numopen … " " … isare … ’ open’ … opensensors)
luup.call_action(“urn:micasaverde-com:serviceId:Sonos1”, “Say”, {Text=“There were " … devcnt … " sensors found and " … numopen … " " … isare … " open.” … opensensors, Language=“en”, Volume=vol}, son)

end

Nice bit of programming. Just interested in how it will be used? Check for proper lockdown before arming?

Sent from my iPad using Tapatalk

Grwebster, I have this script in a scene that is scheduled to run at 10pm, 11pm, and 12am. This way, if we leave doors or windows open at night, we get a verbal reminder of which ones so we can close them. I don’t currently have a scene configured for alerting me if one of the doors/windows is opened during the night, but that would be a. Simple matter of playing a siren sound through my Sonos system…