Use filter() with wildcards  [Solved]

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

Moderator: leecollings

Post Reply
User avatar
FearNaBoinne
Posts: 144
Joined: Tuesday 30 April 2019 10:08
Target OS: Linux
Domoticz version: 2021.1
Location: Sector 0
Contact:

Use filter() with wildcards

Post by FearNaBoinne »

Is there a way to use filter() with wildcards, so it only selects the devices I need without having to iterate through every one of them and checking the names myself?

Something like:

Code: Select all

local StatusNames = {
	'Is * Alive',
	'Monit: * alive'
	}
local StatusDevices = domoticz.devices().filter(StatusNames)
StatusDevices.forEach(function(light)
   BLABLA )
RasPi, Raspbian , Domoticz v2021.1, Z-Wave Stick, RFLink, RFXtrx433e, Hue, Tuya (Tasmota/Mosquitto with Discovery), ESP(easy), MySensors.org, OTGW
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Use filter() with wildcards

Post by waaren »

FearNaBoinne wrote: Wednesday 01 January 2020 21:11 Is there a way to use filter() with wildcards, so it only selects the devices I need without having to iterate through every one of them and checking the names myself?
Not sure if I understand you correctly but if you want to process devices where the state matches a given wildcard you could use something like

Code: Select all

return 
{
    on = 
    {
        devices = 
        {
            'filterTrigger' -- just a virtual switch to trigger this script
        }
    },
    
    logging = 
    {
        level = domoticz.LOG_ERROR,
    },
        
        
    execute = function(dz)
      _G.logMarker =  _G.moduleLabel
      
        function string.sMatch(text, match) -- specialized sanitized match function to allow combination of Lua magic chars in wildcards
            local sanitizedMatch = ('^' .. match:gsub("[%^$]","."):gsub("*", ".*"):gsub("?", ".") .. '$') -- convert to Lua wildcards
            local escapedSanitizedMatch = sanitizedMatch:gsub("([%%%(%)%[%]%+%-%?])", "%%%1") -- escaping all 'magic' chars except *, ., ^ and $
            return text:match(escapedSanitizedMatch)
        end
        
        local wildcardedStatusTable = 
        {
            'Is * Alive',
            'Monit: * alive',
            'Auto *',
            '*us?d*',
            '*domoticz*',
        }
        
        -- chain all devices -->> filter -->> forEach
        dz.devices().filter(function(dv)
                        for _, status in ipairs(wildcardedStatusTable) do  
                            if dv.sValue:sMatch(status) ~= nil then
                                return true
                            end
                        end
                    end).forEach(function(foundDevice)
                            dz.log('sValue of device ' .. foundDevice.name .. ' is ' .. foundDevice.sValue,dz.LOG_FORCE ) 
                        end)
       
       -- or using table to store interim results 
        local variables = dz.variables()
        local filteredVariables = variables.filter(function(vars)
                                                for _, status in ipairs(wildcardedStatusTable) do  
                                                    if tostring(vars.value):sMatch(status) ~= nil then
                                                        return true
                                                    end
                                                end
                                            end)
                            
        filteredVariables.forEach(function(foundVariable)
                            dz.log('value of variable ' .. foundVariable.name .. ' is ' .. foundVariable.value,dz.LOG_FORCE ) 
                          end)
       
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
FearNaBoinne
Posts: 144
Joined: Tuesday 30 April 2019 10:08
Target OS: Linux
Domoticz version: 2021.1
Location: Sector 0
Contact:

Re: Use filter() with wildcards

Post by FearNaBoinne »

Thanls for the suggestion, but no, I am trying to create an array of devices with a NAME matching the wildcards, WITHOUT iterating through every device manually to check it's name...
RasPi, Raspbian , Domoticz v2021.1, Z-Wave Stick, RFLink, RFXtrx433e, Hue, Tuya (Tasmota/Mosquitto with Discovery), ESP(easy), MySensors.org, OTGW
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Use filter() with wildcards  [Solved]

Post by waaren »

FearNaBoinne wrote: Thursday 02 January 2020 9:41 Thanls for the suggestion, but no, I am trying to create an array of devices with a NAME matching the wildcards, WITHOUT iterating through every device manually to check it's name...
It will never be possible to filter a collection without iteration at some level; that's true for any computer language today. Maybe it will change with quantum computing but I would not hold my breath waiting for it. :D

Below script return the matching devices / variables when their name matches a wildcard.

Code: Select all

return 
{
    on = 
    {
        devices = 
        {
            'filterTrigger' -- just a virtual switch to trigger this script
        }
    },

    logging = 
    {
        level = domoticz.LOG_ERROR,
    },

    execute = function(dz)
      _G.logMarker =  _G.moduleLabel

        function string.sMatch(text, match) -- specialized sanitized match function to allow combination of Lua magic chars in wildcards
            local sanitizedMatch = ('^' .. match:gsub("[%^$]","."):gsub("*", ".*"):gsub("?", ".") .. '$') -- convert to Lua wildcards
            local escapedSanitizedMatch = sanitizedMatch:gsub("([%%%(%)%[%]%+%-%?])", "%%%1") -- escaping all 'magic' chars except *, ., ^ and $
            return text:match(escapedSanitizedMatch)
        end

        local wildcardedNameTable = 
        {
            'Is * Alive',
            'Monit: * alive',
            '*rigger',
             '*r*r*',
            '*domoticz*',
            '*?omoticz*',
        }

        -- chain all devices -->> filter -->> forEach
        dz.devices().filter(function(dv)
                        for _, wildcardString in ipairs(wildcardedNameTable) do  
                            if dv.name:sMatch(wildcardString) ~= nil then
                                dv.matchingWildcard = wildcardString
                                return true
                            end
                        end
                    end).forEach(function(foundDevice)
                            dz.log('Device ' .. foundDevice.name .. ' matches ' .. foundDevice.matchingWildcard,dz.LOG_FORCE ) 
                        end)

       -- or using tables to store interim results 
        local variables = dz.variables()
        local filteredVariables = variables.filter(function(var)
                                                for _, wildcardString in ipairs(wildcardedNameTable) do  
                                                    if tostring(var.name):sMatch(wildcardString) ~= nil then
                                                        var.matchingWildcard = wildcardString
                                                        return true
                                                    end
                                                end
                                            end)

        filteredVariables.forEach(function(foundVariable)
                            dz.log('Variable ' .. foundVariable.name .. ' matches ' .. foundVariable.matchingWildcard,dz.LOG_FORCE ) 
                          end)

    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
FearNaBoinne
Posts: 144
Joined: Tuesday 30 April 2019 10:08
Target OS: Linux
Domoticz version: 2021.1
Location: Sector 0
Contact:

Re: Use filter() with wildcards

Post by FearNaBoinne »

waaren wrote: Thursday 02 January 2020 11:46 It will never be possible to filter a collection without iteration at some level; that's true for any computer language today. Maybe it will change with quantum computing but I would not hold my breath waiting for it. :D
I realize that, but if filter() could do that for me (and save me a few steps), it'd make my scripts smaller and more legible... Hence my question!
So the answer (apparently) is no, you cannot (currently) use filter() with wildcards... :shock:

I'll work around it. Thanks for the answer! ;)
RasPi, Raspbian , Domoticz v2021.1, Z-Wave Stick, RFLink, RFXtrx433e, Hue, Tuya (Tasmota/Mosquitto with Discovery), ESP(easy), MySensors.org, OTGW
dizzeenl
Posts: 31
Joined: Wednesday 14 November 2018 23:57
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Dordrecht
Contact:

Re: Use filter() with wildcards

Post by dizzeenl »

Thanks waaren for the wildcard code. i found another code for wildcard filtering (viewtopic.php?t=18212) and combined the 2.

using a if statement with the wildcardedNameTable numer of the wildcard it's possible to filter further.

Code: Select all

.forEach(function(foundDevice,wildcardString)
                            dz.log('Device ' .. foundDevice.name .. ' matches ' .. foundDevice.matchingWildcard,dz.LOG_FORCE ) 
                            if (foundDevice.matchingWildcard == wildcardedNameTable[1]) then 
                                dz.log('only the first wildcard',dz.LOG_FORCE )  
                            end
                        end)
I'm trying to make a general script for sending messages for different devices, like al the devices with the name *door* i want to trigger en run trough a script say

door open/closed
People left/entered (unifi)
window open/closed

etc.

i dont know if this is the best solution :lol:
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest