Page 1 of 1
Use filter() with wildcards
Posted: Wednesday 01 January 2020 21:11
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 )
Re: Use filter() with wildcards
Posted: Thursday 02 January 2020 2:44
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
}
Re: Use filter() with wildcards
Posted: Thursday 02 January 2020 9:41
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...
Re: Use filter() with wildcards [Solved]
Posted: Thursday 02 January 2020 11:46
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.
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
}
Re: Use filter() with wildcards
Posted: Thursday 02 January 2020 18:59
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.
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...
I'll work around it. Thanks for the answer!

Re: Use filter() with wildcards
Posted: Saturday 17 June 2023 10:03
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
