find device id by search pattern

Hey guys…

I’m sure I know I already see something about that somewhere but can’t find it…

In my code I have somewhere a loop like…

local myDevices = {277,278,284,285,286,288,289,293,294,295,296,297,298,299,302,303,304,305,308,339,354,355,389,461,462,463,464,485,486,498}

for _,d in ipairs (myDevices) do
do something here…
end

I need to replace my local myDevices = { something } with a function that will return all the ID of devices that match something in the “device name”

Is it something possible in Lua ?

for _,d in ipairs (myDevices) do if luup.devices[d] and luup.devices[d].description:match( pattern ) then -- do what you need done, this device matches end end

For patterns, see: Programming in Lua : 20.2

EDIT: More complete example to answer the question:

function findDevices( pattern ) local res = {} -- empty array to start for n,d in pairs( luup.devices ) do if d.description:match( pattern ) then table.insert( res, n ) end end return res end

This function returns an array (Lua table) of device numbers, the names of which match the pattern argument.

Thanks man…
But in your code I still have to list my device ID in myDevices variable… is it possible to have a if that will check against all devices? I would like to have a for loop with a more dynamic search so I never need to change my code.

[quote=“rigpapa, post:2, topic:200502”]for _,d in ipairs (myDevices) do if luup.devices[d] and luup.devices[d].description:match( pattern ) then -- do what you need done, this device matches end end

For patterns, see: https://www.lua.org/pil/20.2.html[/quote]

Posted an edit to my response while you were answering. Check back on my previous answer–I think I’ve got you.

Thanks again :wink:

Just modify my code with your new snippet and having something like that:

[code]function findDevices( pattern )
local res = {} – empty array to start
for n,d in pairs( luup.devices ) do
if d.description:match( pattern ) then
table.insert( res, n )
end
end
return res
end

local myDevices = findDevices(‘SS:’)

for _,d in ipairs (myDevices) do
if luup.devices[d] and luup.devices[d].description:match( ‘SS:’ ) then
print (myDevices)
end
end[/code]

And looks like it’s working perfectly :wink:

[quote=“DesT, post:5, topic:200502”]Thanks again :wink:

Just modify my code with your new snippet and having something like that:

[code]function findDevices( pattern )
local res = {} – empty array to start
for n,d in pairs( luup.devices ) do
if d.description:match( pattern ) then
table.insert( res, n )
end
end
return res
end

local myDevices = findDevices(‘SS:’)

for _,d in ipairs (myDevices) do
if luup.devices[d] and luup.devices[d].description:match( ‘SS:’ ) then
print (myDevices)
end
end[/code]

And looks like it’s working perfectly ;)[/quote]

With the function doing the pattern match, you don’t need the pattern check in the second loop–that work is already done. The function returns only those devices that match the pattern. So now, you should be doing something more like:

[code]…

local myDevices = findDevices(‘SS:’)

for _,d in ipairs( myDevices ) do
local devobj = luup.devices[d] – for example, to access the device object for the current matching device
– Do something

end[/code]

Ohh yeah… my mistake. You’re right! :wink:

It would be nice not to have to generate an array and then loop through that… which you can do with coroutines:

local function matchDev (pattern)
    local function match ()
        for n,d in pairs (luup.devices) do
            if d.description:match (pattern) then
                coroutine.yield (n,d)
            end
        end
    end
    return coroutine.wrap (match)
end   

Use this like:

for n,d in matchDev "SS:" do
    print (n, d.description)
end

Sure, maybe a bit much for the new players. :slight_smile: But if you’re going that way, we can simplify a tiny bit because coroutines are not required…

[code]function matchDev( pattern )
local last = nil
return function()
while true do
local d
last,d = next( luup.devices, last )
if not last or d.description:match( pattern ) then
return last,d
end
end
end
end

for n,d in matchDev(‘SS:’) do

end[/code]

Guys… you are so awesome :wink:

If we push that to another level again…

How to have a

function matchDev( pattern, room)

:wink:

EDIT: I like a function that return the ID so I can use it anywhere else in a for loop. I have a Tools functions file that I declare a bunch of function that I can use anywhere with Tools.mynewfunction

[quote=“DesT, post:10, topic:200502”]How to have a

function matchDev( pattern, room)[/quote]

Well, if you must…

function matchDev ( pattern , room)
    return function(_, last)
        while true do
            local d
            last,d = next( luup.devices, last )
            if not last or (d.description:match( pattern ) and (not room or room == d.room_num)) then
                return last,d
            end
        end
    end
end

The use of the room parameter is optional… it will work as before without it.

And if you change the pattern match to: [tt]d.description:match( pattern or ‘.*’ )[/tt] in either akbooers or mine, the pattern also becomes optional and matches all device names if [tt]nil[/tt], so you can specify either pattern, room, or both, and get expected results.

Playing with the last version of the code… and I added the change of rigpapa for the description that give me:

function matchDev (pattern, room) return function(_, last) while true do local d last,d = next( luup.devices, last ) if not last or (d.description:match( pattern or '.*' ) and (not room or room == d.room_num)) then return last,d end end end end

and trying with

for n,d in Tools.matchDev('D-') do print(d) end

or

for n,d in Tools.matchDev('D-','Basement') do print(d) end

Not sure my search works very well… and at the same time, what’s the special character in pattern for tell START WITH “D-” ? I check the link from rigpapa and can’t find anything about that…

The dash character is one of the special characters in a pattern, so you have to escape it, which for Lua patterns means putting a ‘%’ in front of it. And to start a check from the beginning of the string, you use a caret, so in all [tt]“^D%-”[/tt]

And your room needs to be an ID, not a name. By name is a whole new can of worms.

You have to be careful with search patterns, since severa lcharacters have special meanings. ‘-’ is one of them. You need to quote it like this “D%-”.

The special characters for ‘starts with’ is ‘^’, so you’d need “^D%-”.

The rooms are room numbers, not names, although the code could be changed.

… Ah. Posted at (nearly) the same time.

At least our answers were consistent!

Thanks guys!

So for the room “name” I can declare some global variable for them? :wink:

The definitive link for Lua syntax in general, and patterns in particular is:

http://www.lua.org/manual/5.1/manual.html#5.4.1

Don’t do that. Create a lookup table directly from luup.rooms:

local room_no = {}

for i,n in pairs (luup.rooms) do
    room_no[n] = i
end
 
print (pretty(room_no))

gives, for one of my machines:

{
	 ["MiOS-35104005"] = 2,
	 ["MiOS-35104860"] = 4,
	 ["MiOS-45101161"] = 3,
	 ["MiOS-88800156"] = 8,
	 ["Vera Room A"] = 6,
	 ["Vera Room B"] = 7,
	 testing = 5
}

But, this could be included in the search. The problem with names is that there is no guarantee that they are unique, whereas room numbers definitely are.

this is my output…

{ Basement = 13, ["Basement - Bathroom"] = 9, Bathroom = 23, ["Bedroom - Antoine"] = 6, ["Bedroom - Master"] = 20, ["Bedroom - Mathieu"] = 5, ["Bedroom - Twins"] = 4, ["Dining Room"] = 19, Downstairs = 30, Garage = 25, Hallway = 7, Home = 2, ["IoT Network"] = 27, ["IoT Presence"] = 28, ["IoT SmartSwitch"] = 29, Kitchen = 21, ["Living Room"] = 10, ["MiOS-50005737"] = 1, ["Office - Nath"] = 18, ["Office - Sebastien"] = 16, Outside = 26, ["Outside - Basement"] = 15, ["Outside - Front"] = 12, ["Outside - Garage"] = 14, ["Outside - Patio"] = 11, ["Outside - Shed"] = 24, Upstairs = 17, ["Upstairs - Bathroom"] = 8, openLuup = 22 }

So it can be a pain 'cause a bunch of rooms start with the same thing…