Page 1 of 1

Can IFTTT script also work with ID's

Posted: Thursday 17 October 2019 19:52
by pvklink
Hi,

I have a small question about the ifttt script.
It works wunderful within domoticz and IFTTT !

Last part is converting my node-red nora scripts to use ifttvar
I normally use this content to execute a device with ifttvar : [{"obj":"lantaarn","act":"On"}]
But this special node for google home uses id's.

Does this script also handles id's instead of names?
I tried:
[{"obj":"1002","act":"On"}]
[{"obj":1002,"act":"On"}] but they dont work...
am i doing something wrong, or does this script only work with devicename (dont get me wrong, i am VERY happy with this script, i used it 1000 times....

Code: Select all

--[[
syntax of JSON in uservar: 
[
{"obj":"IFvar","set":"TestString"},
{"obj":"IFswitch","act":"On","fS":10,"aS":10,"si":true},
{"obj":"IFSelector","lbl":"Level1"},
{"obj":"IFScene","act":"On"}]

or 
[
{"obj":"IFvar","set":"TestString"},
{"obj":"message from ifttt","msg":["message to all"]},
{"obj":"IFSelector","lbl":"Level1"},
{"obj":"IFScene","act":"On"}
]

max. number of chars = 200
  
every action request in the json should have obj/object and max. one of (act/action, lbl/label, msg/message, set or upd/update, ). 
Other controls (aS/afterSec, fS/ forSec, rAS/repeatAfterSec, si/silent are optional.


if message/msg is the requested action the object field is used as subject and subtable [{}]

            mandatory       line.object    message subject
            mandatory       line.message[1] message body
            optional or nil line.message[2] message priority  (-2=LOW, -1=MODERATE, 0=NORMAL, 1=HIGH, 2=EMERGENCY)
            optional or nil line.message[3] message sound (string like 'pushover','bike','none')
            optional or nil line.message[4] extra 
            optional or nil line.message[5] subsystem or table with subsystems
            
            examples 
            [{"obj":"message from ifttt","msg":["message to all notification systems with default priority"]}]
            [{"obj":"message from ifttt","msg":["message to pushover with high priority",1,null,null,"pushover"]}]
            [{"obj":"message from ifttt","msg":["message to pushover and gcm with low priority",-2,null,null,["pushover","gcm"] ]}]

if OSCommand/os is the requested action, the object field is used program / scriptname. name must be full qualified e.g. "/home/pi/scripts/myScript.sh"

]]--
local iftttvar = "IFTTTvar"  

return 
{
    on =    
    { 
        variables = { iftttvar },   
    },
                    
    logging =
    {   
        level = domoticz.LOG_DEBUG,
        marker = 'ifttt',
   }, 

    execute = function(dz, item)
        
        local function makeLongKeys(str)
            local shortNames = {    
                                    act="action",  -- optional: Can be On, Off or OS/OScommand: 
                                                   -- On; valid for switches and groups and scenes and scenes; Off; valid for switches and groups
                                    aS="afterSec", -- optional: 
                                    fS="forSec",   -- optional: Only valid for standard (On/Off) switches 
                                    lbl="label",   -- optional: levelName or number for selector type switches
                                    msg="message", -- Optional: obj must be set to subject 
                                    obj="object",  -- Mandatory and must be unique in domoticz: name for device, scene, group or uservariable.  
                                    os="OSCommand", -- if os / OSCommand is the requested action, obj must be set to full qualified script /program. 
                                    rAS="repeatAfterSec", -- optional: Only valid for standard (On/Off) switches 
                                    set="set",  -- Optional: update uservariable 
                                    si="silent",  -- Optional: use "si":true in JSON
                                    upd="update", -- Optional: Only valid for devices (set nValue, sValue)
                                    
                               }
 
            for short, long in pairs(shortNames) do
                str = str:gsub('%f[%a]' .. short .. '%f[%A]' ,long) -- this will only replace short with long if short is a whole word
            end
            return str  
        end
        
        local function getBaseType(name)
            for i, tuple in ipairs(_G.domoticzData) do 
                if tuple.name == name then 
                    return tuple.baseType, tuple.id 
                end
            end
        end
        
        local function makeTarget(baseType, name)
            if baseType == 'device' then 
                return dz.devices(name)
            elseif baseType == 'group' then 
                return dz.groups(name)
            elseif baseType == 'scene' then 
                return dz.scenes(name) 
            elseif baseType == 'uservariable' then 
                return dz.variables(name)
            end
        end

        local function doLabelVariant(line, target)
            if line.afterSec and line.silent then 
                target.switchSelector(line.label).silent().afterSec(line.afterSec)
            elseif line.afterSec then
                target.switchSelector(line.label).afterSec(line.afterSec)
           elseif line.silent then
                target.switchSelector(line.label).silent()
           else
                target.switchSelector(line.label)
           end
        end
        
        local function doUpdateVariant(line, target)
            if line.afterSec and line.silent then 
                target.update(line.update).silent().afterSec(line.afterSec)
            elseif line.silent then
                target.update(line.update).silent()
            elseif line.afterSec then
                target.update(line.update).afterSec(line.afterSec)
            else
                target.update(line.update)
            end
        end
        
        local function doSetVariant(line, target)
            if line.afterSec and line.silent then 
                target.set(line.set).silent().afterSec(line.afterSec)
            elseif line.silent then
                target.set(line.set).silent()
            elseif line.afterSec then
                target.set(line.set).afterSec(line.afterSec)
            else
                target.set(line.set)
            end
        end
        
        local function doOnVariant(line, target)
            if line.afterSec and line.forSec and line.silent then 
                target.switchOn().silent().afterSec(line.afterSec).forSec(line.forSec)
            elseif line.afterSec and line.repeatAfterSec and line.silent then 
                target.switchOn().silent().afterSec(line.afterSec).repeatAfterSec(line.repeatAfterSec)
            elseif line.afterSec and line.silent then
                target.switchOn().silent().afterSec(line.afterSec)
           elseif line.afterSec then
                target.switchOn().afterSec(line.afterSec)
           elseif line.silent then
                target.switchOn().silent()
           else
                target.switchOn()
           end
        end
        
        local function doOffVariant(line, target)
            if line.afterSec and line.forSec and line.silent then 
                target.switchOff().silent().afterSec(line.afterSec).forSec(line.forSec)
            elseif line.afterSec and line.repeatAfterSec and line.silent then 
                target.switchOff().silent().afterSec(line.afterSec).repeatAfterSec(line.repeatAfterSec)
            elseif line.afterSec and line.silent then
                target.switchOff().silent().afterSec(line.afterSec)
            elseif line.afterSec then
                target.switchOff().afterSec(line.afterSec)
            elseif line.silent then
                target.switchOff().silent()
            else
                target.switchOff()
            end
        end
        
        local function doStopVariant(line, target)
            if line.afterSec and line.silent then 
                target.stop().silent().afterSec(line.afterSec)
            elseif line.afterSec then
                target.stop().afterSec(line.afterSec)
            elseif line.silent then
                target.stop().silent()
            else
                target.stop()
            end
        end
        
        local function doNotificationVariant(line)
            dz.notify(line.object,line.message[1],line.message[2] or nil,line.message[3] or nil,line.message[4] or nil,line.message[5] or nil)
        end

        local function doOSVariant(osCommand)
            os.execute('sudo ' .. osCommand .. ' &')
            dz.utils.dumpTable(result)
        end

        local function doTasks(result)
            for _, line in ipairs(result) do
                if line.message then
                    doNotificationVariant(line)
                elseif line.action == 'OSCommand' then
                    doOSVariant(line.object)
                else
                    local baseType, idx = getBaseType(line.object)
                    target = makeTarget(baseType, line.object)
                    if not(target) then 
                       dz.log('no device, scene, group or var found',dz.LOG_ERROR)
                       return 
                    end 
                    if line.action and line.action == 'Off' then -- for switch type devices and groups
                        doOffVariant(line, target)
                    elseif line.action and line.action == 'On' then -- for switch type devices, scenes and groups
                        doOnVariant(line, target)
                    elseif line.action and line.action == 'OSCommand' then 
                        doOSVariant(line, target)
                    elseif line.action and line.action == 'Stop' then -- for type blinds 
                        doStopVariant(line, target)
                    elseif line.label then -- for selector type devices
                        doLabelVariant(line, target) 
                    elseif line.set then -- for uservariables
                        doSetVariant(line, target)
                    elseif line.update then -- for devices to set nValu, sValue
                        doUpdateVariant(line, target)
                    end
                end
            end
        end

        -- main 
        local result = dz.utils.fromJSON(makeLongKeys(item.value))
        doTasks(result)
        
    end 
}


Re: Can IFTTT script also work with ID's  [Solved]

Posted: Thursday 17 October 2019 20:18
by waaren
pvklink wrote: Thursday 17 October 2019 19:52 Does this script also handles id's instead of names?
In it's current form the script cannot deal with numeric objects because it does use the name to search in the getBaseType() function to identify the type of object (device, uservariable, scene, etc..) . A numeric value is not unique in _G.domoticzData.so this cannot be used.

To enable the script to deal with ID's, the JSON in the uservar should include the type of the object. It would then become something like:
[{"obj":1002,"type":"device","act":"On"}] If you are able to send such a JSON into the var, I am happy to code this into your current script.
If you send me the script via PM as you use it now, I will have a look.

Re: Can IFTTT script also work with ID's

Posted: Saturday 19 October 2019 16:50
by pvklink
OK, thanks Waaren.
Works perfect now!

Code: Select all

--[[
syntax of JSON in uservar:  
[
{"obj":"IFvar","set":"TestString"},
{"obj":"IFswitch","act":"On","fS":10,"aS":10,"si":true},
{"obj":IFswitchID,"type":"device","act":"On"},   if IFswitchID = numeric , type = device, group, etc mandatory
{"obj":"IFSelector","lbl":"Level1"},
{"obj":"IFScene","act":"On"}]

or 
[
{"obj":"IFvar","set":"TestString"},
{"obj":"message from ifttt","msg":["message to all"]},
{"obj":"IFSelector","lbl":"Level1"},
{"obj":"IFScene","act":"On"}
]

max. number of chars = 200
  
every action request in the json should have obj/object and max. one of (act/action, lbl/label, msg/message, set or upd/update, ). 
Other controls (aS/afterSec, fS/ forSec, rAS/repeatAfterSec, si/silent are optional.


if message/msg is the requested action the object field is used as subject and subtable [{}]

            mandatory       line.object    message subject
            mandatory       line.message[1] message body
            optional or nil line.message[2] message priority  (-2=LOW, -1=MODERATE, 0=NORMAL, 1=HIGH, 2=EMERGENCY)
            optional or nil line.message[3] message sound (string like 'pushover','bike','none')
            optional or nil line.message[4] extra 
            optional or nil line.message[5] subsystem or table with subsystems
            
            examples 
            [{"obj":"message from ifttt","msg":["message to all notification systems with default priority"]}]
            [{"obj":"message from ifttt","msg":["message to pushover with high priority",1,null,null,"pushover"]}]
            [{"obj":"message from ifttt","msg":["message to pushover and gcm with low priority",-2,null,null,["pushover","gcm"] ]}]

if OSCommand/os is the requested action, the object field is used program / scriptname. name must be full qualified e.g. "/home/pi/scripts/myScript.sh"

]]--
local iftttvar = "IFTTTvar"  

return 
{
    on =    
    { 
        variables = { iftttvar },   
    },
                    
    logging =
    {   
        level = domoticz.LOG_DEBUG,
        marker = 'ifttt',
   }, 

    execute = function(dz, item)
        
        local function makeLongKeys(str)
            local shortNames = {    
                                    act="action",  -- optional: Can be On, Off or OS/OScommand: 
                                                   -- On; valid for switches and groups and scenes and scenes; Off; valid for switches and groups
                                    aS="afterSec", -- optional: 
                                    fS="forSec",   -- optional: Only valid for standard (On/Off) switches 
                                    lbl="label",   -- optional: levelName or number for selector type switches
                                    msg="message", -- Optional: obj must be set to subject 
                                    obj="object",  -- Mandatory and must be unique in domoticz: name for device, scene, group or uservariable.  
                                    os="OSCommand", -- if os / OSCommand is the requested action, obj must be set to full qualified script /program. 
                                    rAS="repeatAfterSec", -- optional: Only valid for standard (On/Off) switches 
                                    set="set",  -- Optional: update uservariable 
                                    si="silent",  -- Optional: use "si":true in JSON
                                    upd="update", -- Optional: Only valid for devices (set nValue, sValue)
                                    
                               }
 
            for short, long in pairs(shortNames) do
                str = str:gsub('%f[%a]' .. short .. '%f[%A]' ,long) -- this will only replace short with long if short is a whole word
            end
            return str  
        end
        
        local function getBaseType(line)
            if line.type then return line.type, line.object end
            for i, tuple in ipairs(_G.domoticzData) do 
                if tuple.name == line.object then 
                    return tuple.baseType, tuple.id 
                end
            end
        end
        
        local function makeTarget(baseType, identifier)
            if baseType == 'device' then 
                return dz.devices(identifier)
            elseif baseType == 'group' then 
                return dz.groups(identifier)
            elseif baseType == 'scene' then 
                return dz.scenes(identifier) 
            elseif baseType == 'uservariable' then 
                return dz.variables(identifier)
            end
        end

        local function doLabelVariant(line, target)
            if line.afterSec and line.silent then 
                target.switchSelector(line.label).silent().afterSec(line.afterSec)
            elseif line.afterSec then
                target.switchSelector(line.label).afterSec(line.afterSec)
           elseif line.silent then
                target.switchSelector(line.label).silent()
           else
                target.switchSelector(line.label)
           end
        end
        
        local function doUpdateVariant(line, target)
            if line.afterSec and line.silent then 
                target.update(line.update).silent().afterSec(line.afterSec)
            elseif line.silent then
                target.update(line.update).silent()
            elseif line.afterSec then
                target.update(line.update).afterSec(line.afterSec)
            else
                target.update(line.update)
            end
        end
        
        local function doSetVariant(line, target)
            if line.afterSec and line.silent then 
                target.set(line.set).silent().afterSec(line.afterSec)
            elseif line.silent then
                target.set(line.set).silent()
            elseif line.afterSec then
                target.set(line.set).afterSec(line.afterSec)
            else
                target.set(line.set)
            end
        end
        
        local function doOnVariant(line, target)
            if line.afterSec and line.forSec and line.silent then 
                target.switchOn().silent().afterSec(line.afterSec).forSec(line.forSec)
            elseif line.afterSec and line.repeatAfterSec and line.silent then 
                target.switchOn().silent().afterSec(line.afterSec).repeatAfterSec(line.repeatAfterSec)
            elseif line.afterSec and line.silent then
                target.switchOn().silent().afterSec(line.afterSec)
            elseif line.afterSec and line.forSec then 
                target.switchOn().afterSec(line.afterSec).forSec(line.forSec)
            elseif line.forSec then
                target.switchOn().forSec(line.forSec)
            elseif line.afterSec then
                target.switchOn().afterSec(line.afterSec)

            elseif line.silent then
                target.switchOn().silent()
            else
                target.switchOn()
           end
        end
        
        local function doOffVariant(line, target)
            if line.afterSec and line.forSec and line.silent then 
                target.switchOff().silent().afterSec(line.afterSec).forSec(line.forSec)
            elseif line.afterSec and line.repeatAfterSec and line.silent then 
                target.switchOff().silent().afterSec(line.afterSec).repeatAfterSec(line.repeatAfterSec)
            elseif line.afterSec and line.silent then
                target.switchOff().silent().afterSec(line.afterSec)
            elseif line.afterSec and line.forSec then 
                target.switchOff().afterSec(line.afterSec).forSec(line.forSec)
            elseif line.forSec then
                target.switchOff().forSec(line.forSec)

            elseif line.afterSec then
                target.switchOff().afterSec(line.afterSec)
            elseif line.silent then
                target.switchOff().silent()
            else
                target.switchOff()
            end
        end
        
        local function doStopVariant(line, target)
            if line.afterSec and line.silent then 
                target.stop().silent().afterSec(line.afterSec)
            elseif line.afterSec then
                target.stop().afterSec(line.afterSec)
            elseif line.silent then
                target.stop().silent()
            else
                target.stop()
            end
        end
        
        local function doNotificationVariant(line)
            dz.notify(line.object,line.message[1],line.message[2] or nil,line.message[3] or nil,line.message[4] or nil,line.message[5] or nil)
        end

        local function doOSVariant(osCommand)
            os.execute('sudo ' .. osCommand .. ' &')
            dz.utils.dumpTable(result)
        end

        local function doTasks(result)
            for _, line in ipairs(result) do
                if line.message then
                    doNotificationVariant(line)
                elseif line.action == 'OSCommand' then
                    doOSVariant(line.object)
                else
                    local baseType, idx = getBaseType(line)
                    target = makeTarget(baseType, line.object)
                    if not(target) then 
                       dz.log('no device, scene, group or var found',dz.LOG_ERROR)
                       return 
                    end 
                    if line.action and line.action == 'Off' then -- for switch type devices and groups
                        doOffVariant(line, target)
                    elseif line.action and line.action == 'On' then -- for switch type devices, scenes and groups
                        doOnVariant(line, target)
                    elseif line.action and line.action == 'OSCommand' then 
                        doOSVariant(line, target)
                    elseif line.action and line.action == 'Stop' then -- for type blinds 
                        doStopVariant(line, target)
                    elseif line.label then -- for selector type devices
                        doLabelVariant(line, target) 
                    elseif line.set then -- for uservariables
                        doSetVariant(line, target)
                    elseif line.update then -- for devices to set nValu, sValue
                        doUpdateVariant(line, target)
                    end
                end
            end
        end

        -- main 
        local result = dz.utils.fromJSON(makeLongKeys(item.value))
        doTasks(result)
        
    end 
}