The Vera Community forums have moved!

Advanced => Plugins & Plugin Development => Programming => openLuup => Topic started by: DesT on January 27, 2019, 09:43:39 am

Title: find device id by search pattern
Post by: DesT on January 27, 2019, 09:43:39 am
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 ?
Title: Re: find device id by search pattern
Post by: rigpapa on January 27, 2019, 09:49:27 am
Code: [Select]
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

EDIT: More complete example to answer the question:

Code: [Select]
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.
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 09:59:48 am
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.

Code: [Select]
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
Title: Re: find device id by search pattern
Post by: rigpapa on January 27, 2019, 10:01:07 am
Posted an edit to my response while you were answering. Check back on my previous answer--I think I've got you.
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 10:08:35 am
Thanks again ;)

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

Code: [Select]
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

And looks like it's working perfectly ;)
Title: Re: find device id by search pattern
Post by: rigpapa on January 27, 2019, 10:19:46 am
Thanks again ;)

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

Code: [Select]
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

And looks like it's working perfectly ;)

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: [Select]
...

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
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 10:25:35 am
Ohh yeah.... my mistake.  You're right! ;)
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 10:26:24 am
It would be nice not to have to generate an array and then loop through that... which you can do with coroutines:

Code: [Select]
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:

Code: [Select]
for n,d in matchDev "SS:" do
    print (n, d.description)
end
Title: Re: find device id by search pattern
Post by: rigpapa on January 27, 2019, 10:49:37 am
Sure, maybe a bit much for the new players. :) But if you're going that way, we can simplify a tiny bit because coroutines are not required...

Code: [Select]
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
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 11:00:37 am
Guys.... you are so awesome ;)

If we push that to another level again....

How to have a

function matchDev( pattern, room)

;)

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
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 11:12:54 am
How to have a

function matchDev( pattern, room)

Well, if you must...

Code: [Select]
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.
Title: Re: find device id by search pattern
Post by: rigpapa on January 27, 2019, 11:17:15 am
And if you change the pattern match to: d.description:match( pattern or '.*' ) in either akbooers or mine, the pattern also becomes optional and matches all device names if nil, so you can specify either pattern, room, or both, and get expected results.
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 11:33:03 am
Playing with the last version of the code.. and I added the change of rigpapa for the description that give me:

Code: [Select]
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

Code: [Select]
for n,d in Tools.matchDev('D-') do
    print(d)
end

or

Code: [Select]
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...
Title: Re: find device id by search pattern
Post by: rigpapa on January 27, 2019, 11:39:49 am
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 "^D%-"

And your room needs to be an ID, not a name. By name is a whole new can of worms.
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 11:41:36 am
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.
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 11:42:15 am
... Ah.  Posted at (nearly)  the same time.

At least our answers were consistent!
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 11:43:00 am
Thanks guys!

So for the room "name" I can declare some global variable for them? ;)
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 11:46:52 am
I check the link from rigpapa and can't find anything about that...

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
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 11:52:24 am
So for the room "name" I can declare some global variable for them? ;)

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

Code: [Select]
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:

Code: [Select]
{
["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.
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 11:56:18 am
this is my output....

Code: [Select]
{
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...
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 11:58:39 am
...so what's the problem?  I don't quite understand.
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 12:00:24 pm
That I will need to make my search pattern very precise.  For example, just the word Basement, can give me 3 rooms and Outside can give me 6 results.
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 12:06:28 pm
That I will need to make my search pattern very precise.  For example, just the word Basement, can give me 3 rooms and Outside can give me 6 results.

Well, if you're just doing a simple search, then, yes.  I thought you would be using the exact name?  This is, perhaps, what @rigpapa meant by "a whole new can of worms".

Searches can also be made to look for "ends with ..." or such like, too.
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 12:19:07 pm
I think I will stick with the room number ;)

thanks a lot rigpapa and AK for this help this morning. ;)
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 02:34:17 pm
rigpapa, AK,

Possible to convert the room parameter into an array to be able to pass more than one room and act like a OR ;)
Title: Re: find device id by search pattern
Post by: akbooer on January 27, 2019, 05:26:37 pm
Code: [Select]
function matchDev ( pattern , rooms)
    local wanted = {}
    for _, r in ipairs ((type(rooms) == "table") and rooms or {rooms}) do wanted[r] = r end
    return function(_, last)
        while true do
            local d
            last,d = next( luup.devices, last )
            if not last or (d.description:match( pattern ) and (not rooms or wanted[d.room_num])) then
                return last,d
            end
        end
    end
end

with this you can write things like...

Code: [Select]
for n,d in matchDev "^D-" do ... end

for n,d in matchDev ("^D-", 3) do ... end

for n,d in matchDev ("^D-", {1,3,5}) do ... end

...now go and learn Lua properly so you can do it yourself!   ;)
Title: Re: find device id by search pattern
Post by: DesT on January 27, 2019, 06:23:27 pm
Thanks AK ;)

It's in my todo list of 2019... learn Python from 0% and dig a little more into LUA!
Title: Re: find device id by search pattern
Post by: DesT on January 28, 2019, 02:30:33 pm
AK,

Do you think it's possible that a FOR loop is running too fast for openLuup and that some "command" can be ignored ?

I'm using a FOR loop to "reset" all my smartswitch devices (from the smartswitch plugin) and having some device that are not also reset correctly and it's not always the "same".

Should I add a "wait/sleep" in the loop ?
Title: Re: find device id by search pattern
Post by: akbooer on January 28, 2019, 02:59:52 pm
Would need a bit more info on that like the actual code plus some logs.