Page 1 of 1

Attempt to index local 'device' (a nil value)

Posted: Saturday 20 January 2018 12:14
by htilburgs
In my first attempt to make a dzVents script, I get an error that I can't explain.
As far as I can see, nothing is wrong.

Domoticz v3.8833

The dzVents script:

Code: Select all

return {
    active = true,
    on = {
        timer = {
            'between 11:46 and 12:00'
        },
    
        devices = {
            'PIR Sensor'
        }
    },
    execute = function(domoticz, device)
        if (device.name == 'PIR Sensor' and device.state == 'On') then
            domoticz.devices('Lamp Gang').switchOn().forMin(1)
            domoticz.log('Lamp gang ingeschakeld door PIR')
        end
    end
}
The error message

Code: Select all

2018-01-20 11:54:56.035 dzVents: Info: Handling events for: "PIR Sensor", value: "Off"
2018-01-20 11:54:56.035 dzVents: Info: ------ Start internal script: PIR2: Device: "PIR Sensor (Aeon Labs Z-Stick GEN5)", Index: 489
2018-01-20 11:54:56.035 dzVents: Info: ------ Finished PIR2
2018-01-20 11:55:00.521 dzVents: Info: ------ Start internal script: PIR2:, trigger: between 11:46 and 12:00
2018-01-20 11:55:00.521 Error: dzVents: Error: An error occured when calling event handler PIR2
2018-01-20 11:55:00.521 Error: dzVents: Error: ...e/pi/domoticz/scripts/dzVents/generated_scripts/PIR2.lua:18: attempt to index local 'device' (a nil value)
2018-01-20 11:55:00.521 dzVents: Info: ------ Finished PIR2
The second thing I noticed, is that the script still works, even the timer is not true.
The error "attempt to index local 'device' (a nil value)" disappeared:

Code: Select all

2018-01-20 12:01:43.930 EventSystem: Script event triggered: /home/pi/domoticz/dzVents/runtime/dzVents.lua
2018-01-20 12:02:15.174 dzVents: Info: Handling events for: "PIR Sensor", value: "Off"
2018-01-20 12:02:15.175 dzVents: Info: ------ Start internal script: PIR2: Device: "PIR Sensor (Aeon Labs Z-Stick GEN5)", Index: 489
2018-01-20 12:02:15.175 dzVents: Info: ------ Finished PIR2
2018-01-20 12:02:27.628 dzVents: Info: Handling events for: "PIR Sensor", value: "On"
2018-01-20 12:02:27.629 dzVents: Info: ------ Start internal script: PIR2: Device: "PIR Sensor (Aeon Labs Z-Stick GEN5)", Index: 489
2018-01-20 12:02:27.630 dzVents: Info: Lamp gang ingeschakeld door PIR
2018-01-20 12:02:27.631 dzVents: Info: ------ Finished PIR2
Probably I'm doing something wrong, but as it is my first attempt and the Wiki is not helping me with this, I need some help ;-)

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 20 January 2018 12:49
by waaren
You asked dzVents to trigger between 11:46 and 12:00 or when anything changed on the PIR sensor.

If program is triggered by the timer then device is nil

Syntaxis for what you try to achieve:

devices = { ['PIR Sensor'] = {'between 11:46 and 12:00'}

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 20 January 2018 13:38
by htilburgs
waaren wrote: Saturday 20 January 2018 12:49 You asked dzVents to trigger between 11:46 and 12:00 or when anything changed on the PIR sensor.

If program is triggered by the timer then device is nil

Syntaxis for what you try to achieve:

devices = { ['PIR Sensor'] = {'between 11:46 and 12:00'}
Ok, nice. That works!
The next attempt is to turn it on at 50% for 1 minute.
I used:

Code: Select all

domoticz.devices('Lamp Gang').DimTo(50).forMin(1)
and

Code: Select all

domoticz.devices('Lamp Gang').level:50.forMin(1)
but no luck, both give errors
attempt to call field 'DimTo' (a nil value)
attempt to call field 'level' (a number value)

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 20 January 2018 14:01
by waaren
according to wiki you should use dimTo(50) -- Case matters

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 20 January 2018 17:31
by htilburgs
waaren wrote: Saturday 20 January 2018 14:01 according to wiki you should use dimTo(50) -- Case matters
Ok, thanks again, didn't noticed it.
Now this simple script works!

Code: Select all

return {
    active = true,
    on = 
    {
        devices = {['PIR Sensor'] = {'between 23:30 and 06:30'}}
    },
    execute = function(domoticz, device)
        if (device.name == 'PIR Sensor' and device.state == 'On') then
            domoticz.devices('Lamp Gang').dimTo(50).forMin(1)
            domoticz.log('Lamp gang ingeschakeld door PIR')
        end
    end
}

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 20 January 2018 22:40
by waaren
Your welcome,

your line of code

Code: Select all

if (device.name == 'PIR Sensor' and device.state == 'On') then
can be shortened to

Code: Select all

if device.state == 'On' then -- when code reach this line device.name is always 'PIR Sensor' because code is triggered by change of this device

Re: Attempt to index local 'device' (a nil value)

Posted: Thursday 19 December 2019 22:20
by bertbigb
Hello,

I have a different but similar problem what I can't find myself and I hope someone can help me.
I have a script what should put on the gardenlights at 06:00, put off at sunrise and put on at sunset and then depending on the day of the week at 22:30 put the lights off.

This is my script:

Code: Select all

return {
	on = {
		devices = {},
		timer = {'every minute'},
	},

	execute = function(domoticz, triggeredItem)
	    
        local GardenLights  = 'Tuinlamp'
        local VerandaLight  = 'Veranda'
        local GardenSeason  = 'GardenSeason'
    
        if domoticz.devices(GardenLights).state == 'Off' and
           (domoticz.timer.matchesRule('at 06:00') or
            domoticz.timer.matchesRule('at sunset')) then
            -- at 6  and at sunset we put on the gardenlights
            domoticz.log('Gardenlight switched on', domoticz.LOG_INFO)
            domoticz.devices(GardenLights).switchOn().checkFirst()
            -- at Gardenseason also put light in Veranda on
            if domoticz.variables(GardenSeason) == 'True' then domoticz.devices(VerandaLight).switchOn().checkFirst() end
        else
            if domoticz.devices(GardenLights).state == 'On' and
                (domoticz.timer.matchesRule('at sunrise') or
                 domoticz.timer.matchesRule('at 22:30 on sun,mon,tue,wed,thu') or 
                 domoticz.timer.matchesRule('at 01:00 on fri,sat')) then
                 -- put off the lights at sunrise and at certain times at night
                 domoticz.log('Gardenlight switched off', domoticz.LOG_INFO)
                domoticz.devices(GardenLights).switchOff().checkFirst()
                domoticz.devices(VerandaLight).switchOff().checkFirst()
            else
                domoticz.log('Nothing triggered', domoticz.LOG_INFO)
            end
        end    
	end
}


but the code gives the following error:

Code: Select all

2019-12-19 22:16:00.559 Status: dzVents: Info: ------ Start internal script: Buitenverlichting:, trigger: every minute
2019-12-19 22:16:00.581 Status: dzVents: Error (2.4.19): An error occured when calling event handler Buitenverlichting
2019-12-19 22:16:00.581 Status: dzVents: Error (2.4.19): .../scripts/dzVents/generated_scripts/Buitenverlichting.lua:23: attempt to index field 'timer' (a nil value)
2019-12-19 22:16:00.581 Status: dzVents: Info: ------ Finished Buitenverlichting
Line 23 is the line domoticz.timer.matchesRule('at sunrise').

I hope someone can help me because I'm not really seasoned in dzVentz.
Thanks already for anyone providing help !

Re: Attempt to index local 'device' (a nil value)

Posted: Thursday 19 December 2019 22:49
by waaren
bertbigb wrote: Thursday 19 December 2019 22:20 The code gives the following error:

Code: Select all

2019-12-19 22:16:00.581 Status: dzVents: Error (2.4.19): .../scripts/dzVents/generated_scripts/Buitenverlichting.lua:23: attempt to index field 'timer' (a nil value)
The object (table) is domoticz.time not domoticz.timer

Can you check this ?

Code: Select all

return 
{
    on = 
    {
        timer = {'every minute'},
    },

    execute = function(domoticz)
        
        local GardenLights  = domoticz.devices('Tuinlamp')
        local VerandaLight  = domoticz.devices('Veranda')
        local GardenSeason  = domoticz.variables('GardenSeason')
    
        if GardenLights.state == 'Off' and (    domoticz.time.matchesRule('at 06:00') or 
                                                domoticz.time.matchesRule('at sunset')) then
            -- at 6  and at sunset we put on the gardenlights
            domoticz.log('Gardenlight switched on', domoticz.LOG_INFO)
            GardenLights.switchOn().checkFirst()
            -- at Gardenseason also put light in Veranda on
            if GardenSeason.value == 'True' then 
                VerandaLight.switchOn().checkFirst() 
            end
        else
            if GardenLights.state == 'On' and (    domoticz.time.matchesRule('at sunrise') or 
                                                domoticz.time.matchesRule('at 22:30 on sun,mon,tue,wed,thu') or 
                                                domoticz.time.matchesRule('at 01:00 on fri,sat')) then
                 -- put off the lights at sunrise and at certain times at night
                domoticz.log('Gardenlight switched off', domoticz.LOG_INFO)
                GardenLights.switchOff().checkFirst()
                VerandaLight.switchOff().checkFirst()
            else
                domoticz.log('Nothing triggered', domoticz.LOG_INFO)
            end
        end    
    end



Re: Attempt to index local 'device' (a nil value)

Posted: Friday 20 December 2019 8:37
by bertbigb
Hello Waaren,

That is a really quick reply, thank you very much.
I have no errors anymore and it works!!
Thanks for telling what the problem is --> The object (table) is domoticz.time not domoticz.timer

Do you know a place on the internet where you can find all the objects, I know about the wiki ofcourse but I more or less looking for a place where I can find things like concatenated commands --> domoticz.timer.matchesRule and domoticz(<name>). switchOff().checkFirst()
Your help is very much appreciated!

Re: Attempt to index local 'device' (a nil value)

Posted: Friday 20 December 2019 11:04
by waaren
bertbigb wrote: Friday 20 December 2019 8:37 I have no errors anymore and it works!!
Do you know a place on the internet where you can find all the objects, I know about the wiki ofcourse but I more or less looking for a place where I can find things like concatenated commands --> domoticz.timer.matchesRule and domoticz(<name>). switchOff().checkFirst()
What you call concatenated commands are in fact nested tables / functions. See below example script where I tried to visualize this using a switch type device as trigger.

A good place to start understanding Lua functions and tables is this Lua users wiki
With a short introduction to tables here

Code: Select all

return
{
    on = 
    {
        devices = { 199 } -- changes to a virtual switch type device that you can use as trigger for this example script
    },
    
    execute = function(dz, item)
        dz.log('Device ' .. item.name, dz.LOG_INFO)
        
        dz.log('type silent(): ' .. type(item.switchOff().silent()),dz.LOG_INFO)
        dz.utils.dumpTable(item.switchOff().silent())
        
        dz.log('type afterHour(): ' .. type(item.switchOff().silent().afterHour(1)),dz.LOG_INFO)
        dz.utils.dumpTable(item.switchOff().silent().afterHour(1))
        
        dz.log('type checkFirst(): ' .. type(item.switchOff().silent().afterHour(1).checkFirst()),dz.LOG_INFO)
        dz.utils.dumpTable(item.switchOff().silent().afterHour(1).checkFirst())
        
        dz.log('type forSec(): ' .. type(item.switchOff().silent().afterHour(1).checkFirst().forSec(2)),dz.LOG_INFO)
        dz.utils.dumpTable(item.switchOff().silent().afterHour(1).checkFirst().forSec(2))
        
        dz.log('type repeatAfterSec(): ' .. type(item.switchOff().silent().afterHour(1).checkFirst().forSec(2).repeatAfterSec(3)),dz.LOG_INFO)
        dz.utils.dumpTable(item.switchOff().silent().afterHour(1).checkFirst().forSec(2).repeatAfterSec(7))
    
        dz.log('type _latest: ' .. type(item.switchOff().silent().afterHour(1).checkFirst().forSec(2).repeatAfterSec(3)._latest),dz.LOG_INFO)
        dz.utils.dumpTable(item.switchOff().silent().afterHour(1).checkFirst().forSec(2).repeatAfterSec(7)._latest)
    
        dz.log('type _latest: ' .. type(item.switchOff().silent().afterHour(1).checkFirst().forSec(2).repeatAfterSec(3)._latest[item.name]),dz.LOG_INFO)
        dz.log('_latest.' .. item.name .. ': ' .. item.switchOff().silent().afterHour(1).checkFirst().forSec(2).repeatAfterSec(7)._latest[item.name],dz.LOG_INFO)
    end
}

Re: Attempt to index local 'device' (a nil value)

Posted: Friday 20 December 2019 16:49
by bertbigb
Hi Waaren,

Thank you very much for this guidance. I will read that stuff during this Christmas holiday.

This morning I tested your script with a single time and it worked.
But I also wanted to extend the script a bit since in the past I have found out that sometimes a time event was missed. So I thought to extend the script with some margins
So I made it as follows:

Code: Select all

return 
{
    on = 
    {
        timer = {'sunrise',
                 'sunset',
                 'every minute'},
    },

    execute = function(domoticz)
        
        local GardenLights  = domoticz.devices('Tuinlamp')
        local VerandaLight  = domoticz.devices('Veranda')
        local GardenSeason  = domoticz.variables('GardenSeason')
    
        if GardenLights.state == 'Off' and (    domoticz.time.matchesRule('at 06:00-sunrise') or 
                                                domoticz.time.matchesRule('at sunset-22:00')) then
            -- at 6  and at sunset we put on the gardenlights
            domoticz.log('Gardenlight switched on', domoticz.LOG_INFO)
            GardenLights.switchOn().checkFirst()
            -- at Gardenseason also put light in Veranda on
            if GardenSeason.value == 'True' then 
                VerandaLight.switchOn().checkFirst() 
            end
        else
            if GardenLights.state == 'On' and ( domoticz.time.matchesRule('at sunrise-09:00') or 
                                                domoticz.time.matchesRule('at 22:30-22:45 on sun,mon,tue,wed,thu') or 
                                                domoticz.time.matchesRule('at 01:00-01:15 on fri,sat')) then
                 -- put off the lights at sunrise and at certain times at night
                domoticz.log('Gardenlight switched off', domoticz.LOG_INFO)
                GardenLights.switchOff().checkFirst()
                VerandaLight.switchOff().checkFirst()
            else
                domoticz.log('Nothing triggered', domoticz.LOG_INFO)
            end
        end    
    end

}
At Sunset the script wasn't triggerd, so I thought it would do on domoticz.time.matchesRule('at sunset-22:00') but it doesn't do also

Code: Select all

2019-12-20 16:37:00.414 Status: dzVents: Info: ------ Start internal script: Buitenverlichting:, trigger: every minute
2019-12-20 16:37:00.437 Status: dzVents: Info: Nothing triggered
2019-12-20 16:37:00.437 Status: dzVents: Info: ------ Finished Buitenverlichting
Did I do something wrong with at ' sunset-22:00' I thought that the script would check between sunset and 10 'o clock but obvious it doesn't.
Can you help me a little bit more?

Re: Attempt to index local 'device' (a nil value)

Posted: Friday 20 December 2019 18:56
by waaren
bertbigb wrote: Friday 20 December 2019 16:49 Did I do something wrong with at ' sunset-22:00' I thought that the script would check between sunset and 10 'o clock but obvious it doesn't.
Can you help me a little bit more?
I know there is a remark in the dzVents wiki about missed time triggers but I never experienced one on my systems.

at 06:00-sunrise, at sunset-22:00 and at sunrise-09:00 are no valid dzVents time rules.

A couple of remarks:
Please note that between 06:00 and sunrise will never be true during winter in large parts of the world. Similar for between sunset and 22:00 in summer.

Code: Select all

if GardenLights.state == 'Off' and GardenLights.switchOn().checkFirst() -- this is double.
. Only 1 check should be enough.

Code: Select all

domoticz.time.matchesRule('at 01:00-01:15 on fri,sat'))
. -- are you sure you don't want this to happen only in the weekends ?

The domoticz event system triggers time based event scripts max. once a minute. So

Code: Select all

 timer = {'sunrise',  'sunset',  'every minute'  },
does not add any value over

Code: Select all

timer = { 'every minute ' },
in this script. Both settings causes the script to trigger 1440 times / day. My approach would be to have the script to trigger only when it has something to do. Here it would be something like below (not tested!)

Code: Select all

local sunrise = 'at sunrise'  
local sunset = 'at sunset' 
local onMorningTime = 'at 06:00'  
local offEveningWeekdays = 'at 22:30 on mon, tue, wed, thu, fri'
local offNightWeekend = 'at 01:00 on sat,sun'

return 
{
    on = 
    {
        timer = { sunrise, sunset, onMorningTime, offEveningWeekdays,  offNightWeekend }
    },

    execute = function(dz, item)

        local GardenLights = dz.devices('Tuinlamp')
        local VerandaLight = dz.devices('Veranda')
        local GardenSeason = dz.variables('GardenSeason')

        local now = math.floor(dz.time.secondsSinceMidnight / 60) -- minutesSinceMidnight does not exist
        local activeRule = item.trigger

        if ( activeRule == onMorningTime and dz.time.sunriseInMinutes > now ) or  -- at 6 if sunrise is after 6
             activeRule == sunset then     
            -- at 6 AM and at sunset we put on the gardenlights
            GardenLights.switchOn().checkFirst()
             if GardenSeason.value == 'True' then 
                VerandaLight.switchOn().checkFirst() 
            end
            dz.log('Lights should be on now', dz.LOG_INFO)
        elseif activeRule == sunrise or activeRule == offEveningWeekdays or activeRule == offNightWeekend then
            -- at sunrise and in the evening / at night we switch off the lights.
            GardenLights.switchOff().checkFirst()
            VerandaLight.switchOff().checkFirst() 
            dz.log('Lights should be off now', dz.LOG_INFO)
        end
    end
}

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 21 December 2019 12:11
by bertbigb
Hi Waaren,

Thanks again. I learn a whole lot from all your explications and samples. Hopefully I will come to a level I can help others also on these kind of subjects. A lot of what you were telling me makes sense.
Please note that between 06:00 and sunrise will never be true during winter in large parts of the world. Similar for between sunset and 22:00 in summer.

This I do not understand very well. Like now in winter the time 06:00 is before sunrise at 08:41(sunrise) so although the syntax was not ok but between 06:00 - sunrise I thought is similar to 06:00 - 08:41. But nevertheless the syntax is not correct anyway as you wrote. My meaning was to have the gardenlights on from 06;00 (when I'm awake) till sunrise, because then it is light enough.

That is probably why I do not understand this piece very well

Code: Select all

local now = math.floor(dz.time.secondsSinceMidnight / 60) -- minutesSinceMidnight does not exist
        local activeRule = item.trigger

        if ( activeRule == onMorningTime and dz.time.sunriseInMinutes > now ) or  -- at 6 if sunrise is after 6
             activeRule == sunset then     
            -- at 6 AM and at sunset we put on the gardenlights
            GardenLights.switchOn().checkFirst()
I would have thought that it should be something like

Code: Select all

        local now = math.floor(dz.time.secondsSinceMidnight / 60) -- minutesSinceMidnight does not exist
        local activeRule = item.trigger

        if ( activeRule == onMorningTime and dz.time.sunriseInMinutes < now ) then     
            -- at 6 AM and BEFORE sunset we put on the gardenlights
            GardenLights.switchOn().checkFirst()
I will test the script and see if it works today. I will post the result here so if anyone needs a similar script they know they can make use of it.
Thanks once again. Great help you are giving.

Re: Attempt to index local 'device' (a nil value)

Posted: Saturday 21 December 2019 19:45
by waaren
bertbigb wrote: Saturday 21 December 2019 12:11 I would have thought that it should be something like

Code: Select all

        local now = math.floor(dz.time.secondsSinceMidnight / 60) -- minutesSinceMidnight does not exist
        local activeRule = item.trigger

        if ( activeRule == onMorningTime and dz.time.sunriseInMinutes < now ) then     
            -- at 6 AM and BEFORE sunset we put on the gardenlights
            GardenLights.switchOn().checkFirst()
If you would code it like that and sunrise is at 5:59 or earlier the light will be switched on at 6:00 and will not switched off again until very late in the evening.

Re: Attempt to index local 'device' (a nil value)  [Solved]

Posted: Sunday 22 December 2019 22:42
by bertbigb
Hi Waaren,

Just to let you know but the script you supplied works very good.
Thanks again for all your help!