Local, global, variable, chunks... Where is my table?

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

Moderator: leecollings

Post Reply
Sarcas
Posts: 86
Joined: Wednesday 11 October 2017 8:50
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1ß
Location: Friesland
Contact:

Local, global, variable, chunks... Where is my table?

Post by Sarcas »

Right at the beginning of my script, I declare my table:

Code: Select all

execute     = function( domoticz , triggerItem )
local myTable_devId = {}
I have a function that adds values to the table, like:

Code: Select all

hueScenesDz_hueId[i] = {}
myTable_devId[i].action = myUrl
myTable_devId[i].name = theName
Other functions want to use the table, but it is empty in other functions. I've read about variables and chunks, but I still don't understand how to use a variable or table throughout my whole script.
--

Domoticz on rPi4 - RFXCOM RFXtrx433 USB - ZW090 Z-Stick Gen5 EU - IKEA Tradfri - Philips HUE - YouLess meter - SolarEdge
User avatar
boum
Posts: 135
Joined: Friday 18 January 2019 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: France
Contact:

Re: Local, global, variable, chunks... Where is my table?

Post by boum »

You should post your full script, or better, the shortest script that shows the issue.
It's all about visibility (technical term). If your table is not visible from your function, you should pass it as parameter.
Sarcas
Posts: 86
Joined: Wednesday 11 October 2017 8:50
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1ß
Location: Friesland
Contact:

Re: Local, global, variable, chunks... Where is my table? Now with script included...

Post by Sarcas »

I kind of dreaded this moment, because my skills suck, but my ambitions are huge. I am the Dr Frankenstein of scripting; I cut parts from things I think I can use and stitch stuff together with my basic knowledge, google and a lot of trial and error. So behold my monster:

Code: Select all

--[[
Purpose of the script:

HUE is rolling out v2 of its API. Things works different now and there are more options.
One is called 'dynamic scenes'. Lights slowely change color, intensity etc. The Domoticz
plugin can't handle this yet. My goal for this script:

- Read the created scenes from the HUE bridge with v2 API
- Create devices from the HUE scenes
    - Create new / delete removed / rename renamed

The idea is to make a table where the index is the hueSceneId from the HUE bridge:

hueScenesDz_hueId -- key = hueSceneId
hueScenesDz_hueId.onAction
hueScenesDz_hueId.sceneName
hueScenesDz_hueId.dzDeviceIdx

Later offAction and other things can be added. Lets try to get this working first.

The 'logic' :-p

-   Do the API call to the HUE bridge to get all info
-   Catch the response with HUE_SCENELIJST and build the table(s)
-   Check the discovered scenes with the current devices in Domoticz
-   Create new device if needed
    -   Add it to the table and add the new domoticz idx of the device to the table
    Big problem here: Although the device is created, the idx isn't available yet. 
    I need a delay. Trying to wait for the MAKEDZDEVICE_EXECUTED* http-response, but
    then I seem to have lost the content of my main table somehow. So now I am
    experimenting with customEvents and .delay(seconds). This works, but again I can't 
    access my main table. I pass the table in the extradata field, and it is in 
    triggerItem.data but not in hueScenesDz_hueId. 
    
    experiment: is it because the customEvent trigger activates another instance of the script,
    where hueScenesDz_hueId isn't created?
    
-   (todo) Build a table with index domoticz-device index, so I can quickly find 
    corresponding actionOn, off etc.

]]--




return {
    on  = {
        devices = {
            'HueScene - *',
            2418            -- my virtual button; activates the script for tests
        },
        -- timer           = {
        --     'every minute'
        -- },
        httpResponses   = {
            'HUE_SCENELIJST',
            'MAKEDZDEVICE_EXECUTED*'
        },
        customEvents = {
            'HUEEVENT_*'
        },
--  Uncomment this later and make it so the devices are checked at startup    
--         system = {
-- 			'start'
-- 		}
    },

    logging     = {
        level   = domoticz.LOG_DEBUG,
        marker  = 'HUE_SCENELIJST',
    },

    execute     = function( domoticz , triggerItem )
        domoticz.log( 'Script started' , domoticz.LOG_DEBUG )

        local hueScenesDz_hueId     = {}
        local scenePrefix           = 'HueScene - '

        -- ---------------------------------------------------------------------
        -- FUNCTIONS -----------------------------------------------------------
        -- ---------------------------------------------------------------------

        -- ---------------------------------------------------------------------
        -- Ask the HUE scenes from the bridge, the CALLBACK handles the response
        -- ---------------------------------------------------------------------
        local function scenesFromBridge()
            domoticz.log('scenesFromBridge() : local function scenesFromBridge()' , domoticz.LOG_DEBUG )

            domoticz.openURL({
                url         = 'https://' .. domoticz.helpers.myHueBridgeIp .. '/clip/v2/resource/scene',
                method      = 'GET',
                callback    = 'HUE_SCENELIJST',
                headers     = {
                    ['hue-application-key'] = domoticz.helpers.myHueApiKey
                }
            })
        end

        -- ---------------------------------------------------------------------
        -- Create the device
        -- ---------------------------------------------------------------------
        local function makeDzDevice(hueSceneId)
            domoticz.log('makeDzDevice() : local function makeDzDevice()' , domoticz.LOG_DEBUG )

            domoticz.openURL({
                url         = domoticz.settings.url .. '/json.htm?type=createdevice&idx=' .. domoticz.helpers.hueScenesHardwareId .. '&sensorname=' .. domoticz.utils.urlEncode(hueScenesDz_hueId[hueSceneId].sceneName) .. '&devicetype=244&devicesubtype=73',
                method      = 'GET',
                callback    = 'MAKEDZDEVICE_EXECUTED#' .. hueSceneId
            })

            domoticz.emitEvent( "HUEEVENT_".. hueSceneId , hueScenesDz_hueId ).afterSec(2)
        end

        -- ---------------------------------------------------------------------
        -- Use the reply from the bridge to build local tables
        -- ---------------------------------------------------------------------
        local function makeScenelijst()
            domoticz.log('makeScenelijst() : Step 2 - local function makeScenelijst()' , domoticz.LOG_DEBUG )

            if (triggerItem.isJSON) then
                local result_table  = triggerItem.json.data     -- giving table with all actions
                local tc            = #result_table             -- counting number of actions

                for i = 1, tc do   -- go through all actions
                    local hueSceneId    = result_table[i].id                -- the scene-id from the hue bridge
                    local hueSceneName  = result_table[i].metadata.name     -- the scene-name from the hue bridge

                    local onActionCurl  = 'curl --header "Content-Type: application/json"   --header "hue-application-key: ' .. domoticz.helpers.myHueApiKey .. '"' ..
                        ' --request PUT  --data \'"recall":{"action":"dynamic_palette"}' ..
                        ' https://' .. domoticz.helpers.myHueBridgeIp .. '/clip/v2/resource/scene/' .. hueSceneId    -- the curl used to activate the scene on the hue bridge

                    hueScenesDz_hueId[hueSceneId]           = {}
                    hueScenesDz_hueId[hueSceneId].onAction  = onActionCurl
                    hueScenesDz_hueId[hueSceneId].sceneName = scenePrefix .. hueSceneName

                    if not domoticz.utils.deviceExists(hueScenesDz_hueId[hueSceneId].sceneName) then
                        domoticz.log('Device "' .. hueScenesDz_hueId[hueSceneId].sceneName .. '" does not exist.' , domoticz.LOG_DEBUG )
                        makeDzDevice(hueSceneId)
                    end

                end
            else
                domoticz.log('noJSON',domoticz.LOG_ERROR)
            end
        end



        -- ---------------------------------------------------------------------
        -- MAIN CODE -----------------------------------------------------------
        -- ---------------------------------------------------------------------

        if ( triggerItem.isDevice ) then
            domoticz.log ( 'Trigger is device : ' .. triggerItem.idx , domoticz.LOG_DEBUG )
            
            if ( triggerItem.idx == 2418 ) then
                domoticz.log('Trigger is device testbutton')

                scenesFromBridge()      -- get the scenes from the bridge and put them in a table
            else
                domoticz.log ( '******** Trigger is device : ' .. triggerItem.idx , domoticz.LOG_DEBUG )
            end
        end
        
        if ( triggerItem.isHTTPResponse ) then
            domoticz.log('Trigger is HTTPResponse : ' .. triggerItem.callback , domoticz.LOG_DEBUG )

            if triggerItem.callback == 'HUE_SCENELIJST' then
                makeScenelijst()

            elseif string.find(triggerItem.callback, "MAKEDZDEVICE_EXECUTED#") then
                if triggerItem.ok then
                    domoticz.log ( 'Devicecreation was ok' , domoticz.LOG_DEBUG )
                else
                    domoticz.log ( 'ERROR - Devicecreation was not ok' , domoticz.LOG_DEBUG )
                    -- do stuff
                end
            end
        end

        -- In the next part I have to add the domoticz index to hueScenesDz_hueId for the
        -- newly created device. But where is hueScenesDz_hueId ???
        if ( triggerItem.isCustomEvent ) then
            domoticz.log ( 'CustomEvent trigger = ' .. triggerItem.trigger, domoticz.LOG_DEBUG )
            domoticz.log ( 'CustomEvent data = ' .. triggerItem.data, domoticz.LOG_DEBUG )
            local event = triggerItem.data
            if event == nil then
                domoticz.log( 'data is missing', domoticz.LOG_ERROR)
            elseif event.dzDeviceIdx == nil then
                domoticz.log( 'dzDeviceIdx is missing', domoticz.LOG_ERROR)
            elseif event.onAction == nil then
                domoticz.log( 'onAction is missing', domoticz.LOG_ERROR)
            elseif event.sceneName == nil then
                domoticz.log( 'sceneName is missing', domoticz.LOG_ERROR)
            end
            domoticz.utils.dumpTable( hueScenesDz_hueId )
        end
    end
}
It is of course far from being finished. It does create devices, and the curl it creates for activating the scenes is tested and works. Today I thought that my problem perhaps has to do with my old concept of a program as one thing, in which code is executed sequentially. But if it actually is true that a custom event, or a http response spawn a new instance of the script, it might make sense that in those cases variables are unknown.

Is this the case?

Thanks for any advice or tips and comments. I am enjoying the puzzle, but it is hard to find clear info on LUA for an amateur. It either is too simple or too complex.

S.
--

Domoticz on rPi4 - RFXCOM RFXtrx433 USB - ZW090 Z-Stick Gen5 EU - IKEA Tradfri - Philips HUE - YouLess meter - SolarEdge
Sarcas
Posts: 86
Joined: Wednesday 11 October 2017 8:50
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.1ß
Location: Friesland
Contact:

Re: Local, global, variable, chunks... Where is my table?

Post by Sarcas »

Doh.

Changing hueScenesDz_hueId into a script level persistent variable seemed to work. I should have realized this sooner. Anyway... Onward!
--

Domoticz on rPi4 - RFXCOM RFXtrx433 USB - ZW090 Z-Stick Gen5 EU - IKEA Tradfri - Philips HUE - YouLess meter - SolarEdge
User avatar
boum
Posts: 135
Joined: Friday 18 January 2019 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10717
Location: France
Contact:

Re: Local, global, variable, chunks... Where is my table?

Post by boum »

Good for you.
Yes, persistent data was probably the easiest way to do it in your case.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest