Prevent runtime errors.  [Solved]

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

Moderator: leecollings

Post Reply
User avatar
Hesitated
Posts: 42
Joined: Monday 04 June 2018 21:40
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.11665
Location: Ede
Contact:

Prevent runtime errors.

Post by Hesitated »

I've been working with customEvents and it is helpfull to reduce (duplicate) code in other scripts, so they will be easier to maintain.

E.g.:

Code: Select all

local up = "Up"
local down = "Down"

return {
  on = {
    customEvents = {
      'BedieningRolluiken'
    }
  },
  logging = 
  { 
    level = domoticz.LOG_ERROR,
    marker = "Bediening rolluiken" 
  },
  execute = function(dz, item)

    local function rolluikOpen(rolluik)
      if rolluik ~= nil then
        dz.log('Rolluik omhoog: ' .. rolluik.name, dz.LOG_DEBUG)
        rolluik.switchOff()
      end
    end

    local function rolluikDicht(rolluik)
      if rolluik ~= nil then
        dz.log('Rolluik omlaag: ' .. rolluik.name, dz.LOG_DEBUG)
        rolluik.switchOn()
      end
    end

    local json = dz.utils.fromJSON(item.data)
    local command = json[1]
    
    if command ~= up and command ~= down then
       return 
    end

    local devices = json[2]
    local rolluiken = dz.devices().filter(devices)
    dz.log('#rolluiken: ' .. tostring(#rolluiken), dz.LOG_DEBUG)

    if command == up then
      dz.log('Command was "Up"', dz.LOG_DEBUG)
      rolluiken.forEach(function(rolluik)
        rolluikOpen(rolluik)
      end)
    elseif command == down then
      dz.log('Command was "Down"', dz.LOG_DEBUG)
      rolluiken.forEach(function(rolluik)
        rolluikDicht(rolluik)
      end)
    end
  end
}
Which will be triggered by other scripts containing:

Code: Select all

  local args = {
    "Down",
    idsRolluiken
  }
  dz.emitEvent('BedieningRolluiken', args)
But the main script could fail when the passed arguments are not in the expected format.
E.g.:

Code: Select all

local json = dz.utils.fromJSON(item.data)
could fail if item.data is not (proper) json

Or:

Code: Select all

local rolluiken = dz.devices().filter(devices)
could fail if devices are not found.

How do I prevent these runtime errors? (pcall can't be used here)
Domoticz 2020.2 - RPi3B+ - RFXtrx433XL - P1 - CC2531 - Somfy - Xiaomi - Hue - Omron - MQTT
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: Prevent runtime errors.

Post by boum »

Why would pcall couldn't be called there? What behavior do you expect?

You can protect against runtime error either piecemeal or on the whole custom event script.
For the two places you shown, it would be:

Code: Select all

local ok, json = pcall(dz.utils.fromJSON, item.data)
if not ok then 
  -- handle error
  return
end
and

Code: Select all

-- use anonymous function, dz.devices() is a table
local ok, rolluiken = pcall(function() return dz.devices().filter(devices) end) 
if not ok then 
  -- handle device not found
  return
end
and for the custom script, you just wrap your whole execute function in a local function and pcall it:

Code: Select all

return {
  on = {
    customEvents = { 'BedieningRolluiken' }
  },
  execute = function(dz, item)
    local checkExecute = function(dz, item)
      local function rolluikOpen(rolluik) [...]
      end
      [...]
    end
    
    -- protected call
    local ok = pcall(checkExecute, dz, item)
    if not ok then
      dz.log(...)
    end
  end
}
Last edited by boum on Sunday 26 April 2020 14:10, edited 2 times in total.
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: Prevent runtime errors.

Post by boum »

I checked and you cannot use pcall on callable tables. I'll update the example above for dz.devices.
User avatar
Hesitated
Posts: 42
Joined: Monday 04 June 2018 21:40
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.11665
Location: Ede
Contact:

Re: Prevent runtime errors.

Post by Hesitated »

boum wrote: Sunday 26 April 2020 13:56 Why would pcall couldn't be called there? What behavior do you expect?
I think my knowledge of lua is still far too limited... :oops:
boum wrote: Sunday 26 April 2020 13:56

Code: Select all

local ok, json = pcall(dz.utils.fromJSON, item.data)
Ah, I did not know that I could put json as the second variable.
boum wrote: Sunday 26 April 2020 13:56 and for the custom script, you just wrap your whole execute function in a local function and pcall it:
This one I should have known, but didn't think of it.
Domoticz 2020.2 - RPi3B+ - RFXtrx433XL - P1 - CC2531 - Somfy - Xiaomi - Hue - Omron - MQTT
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Prevent runtime errors.

Post by waaren »

Hesitated wrote: Sunday 26 April 2020 13:04 But the main script could fail when the passed arguments are not in the expected format.
E.g.:

Code: Select all

local json = dz.utils.fromJSON(item.data)
could fail if item.data is not (proper) json
If item.data is not in the right JSON format you will get an error message but the script will not fail. Item.data will be nil and that is something that can be handled in your script logic.
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
Hesitated
Posts: 42
Joined: Monday 04 June 2018 21:40
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.11665
Location: Ede
Contact:

Re: Prevent runtime errors.

Post by Hesitated »

waaren wrote: Sunday 26 April 2020 17:39 If item.data is not in the right JSON format you will get an error message but the script will not fail. Item.data will be nil and that is something that can be handled in your script logic.
Unfortunately not always.

With this url you're right!

Code: Select all

https://domoticz/json.htm?type=command&param=customevent&event=BedieningRolluiken&data=ok
But if you use this url:

Code: Select all

https://domoticz/json.htm?type=command&param=customevent&event=BedieningRolluiken&data=[%22Up%22,{}]
you'll get:

Code: Select all

2020-04-26 17:41:54.697 Error: dzVents: Error: (3.0.1) Bediening rolluiken: Error parsing json to LUA table: /home/pi/domoticz/scripts/dzVents/../lua/JSON.lua:808: expected string argument to JSON:decode(), got table
2020-04-26 17:41:54.697 Error: dzVents: Error: (3.0.1) Bediening rolluiken: item.data is not jsontable: 0x728f4468 
Domoticz 2020.2 - RPi3B+ - RFXtrx433XL - P1 - CC2531 - Somfy - Xiaomi - Hue - Omron - MQTT
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Prevent runtime errors.  [Solved]

Post by waaren »

Hesitated wrote: Sunday 26 April 2020 17:57 Unfortunately not always.
if you use this url:

Code: Select all

https://domoticz/json.htm?type=command&param=customevent&event=BedieningRolluiken&data=[%22Up%22,{}]
you'll get:

Code: Select all

2020-04-26 17:41:54.697 Error: dzVents: Error: (3.0.1) Bediening rolluiken: Error parsing json to LUA table: /home/pi/domoticz/scripts/dzVents/../lua/JSON.lua:808: expected string argument to JSON:decode(), got table
2020-04-26 17:41:54.697 Error: dzVents: Error: (3.0.1) Bediening rolluiken: item.data is not jsontable: 0x728f4468 
Yes you can get an Error message but the script will continue (at least it does on my systems (dzVents 3.0.2)

Let me have a look if I can add the isJSON attribute to item in customEvents triggers to help catching errors.

If I use

Code: Select all

        /json.htm?type=command&param=customevent&event=faultyJSON&data=[%22Up%22,{}]
and this test script

Code: Select all

return 
{
	on = 
	{
		customEvents = 
		{
			'faultyJSON',  -- just an example to trigger the request
		},
	},
		
	execute = function(dz, item)
        -- /json.htm?type=command&param=customevent&event=faultyJSON&data=[%22Up%22,{}]
        
        lodash = dz.utils._
        
        for i=1, 10 do
            dz.log('although you will see an error. The script is  still executing here', dz.LOG_FORCE)
        end
        
        
        dz.log('ítem is: ' .. lodash.str(item), dz.LOG_FORCE)
        dz.log('item.data: ' .. lodash.str(item.data), dz.LOG_FORCE)
    end	
}
The log shows:
Spoiler: show

Code: Select all

2020-04-26 19:03:24.612 Status: dzVents: Info: Handling Domoticz custom event for: "faultyJSON"
2020-04-26 19:03:24.613 Status: dzVents: Info: ------ Start internal script: dz JSON reader: Custom event: "faultyJSON"
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: although you will see an error. The script is still executing here
2020-04-26 19:03:24.613 Status: dzVents: !Info: ítem is: {["type"]="customEvent", ["isSystem"]=false, ["isDevice"]=false, ["status"]="info", ["isTimer"]=false, ["data"]={"Up", {}}, ["isHardware"]=false, ["isHTTPResponse"]=false, ["isCustomEvent"]=true, ["isSecurity"]=false, ["trigger"]="faultyJSON", ["isGroup"]=false, ["isVariable"]=false, ["message"]="", ["isScene"]=false}
2020-04-26 19:03:24.613 Status: dzVents: !Info: item.data: {"Up", {}}
2020-04-26 19:03:24.613 Status: dzVents: Info: ------ Finished dz JSON reader
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
Hesitated
Posts: 42
Joined: Monday 04 June 2018 21:40
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.11665
Location: Ede
Contact:

Re: Prevent runtime errors.

Post by Hesitated »

waaren wrote: Sunday 26 April 2020 19:10 Yes you can get an Error message but the script will continue (at least it does on my systems (dzVents 3.0.2)
Just updated to 20202.2, to be sure...

I'll feel sighted blind, but eventually solved the mistery:

Code: Select all

    local lodash = dz.utils._
    local json = dz.utils.fromJSON(item.data)
    if json == nil then
      dz.log('item.data is not json: ' .. lodash.str(item.data), dz.LOG_FORCE)
      return
    end
is now looging:

Code: Select all

2020-04-26 22:04:50.204 Status: dzVents: Info: Bediening rolluiken: ------ Start internal script: BedieningRolluiken: Custom event: "BedieningRolluiken"
2020-04-26 22:04:50.204 Status: dzVents: !Info: Bediening rolluiken: item.data is not json: {"Up", {}}
2020-04-26 22:04:50.204 Status: dzVents: Info: Bediening rolluiken: ------ Finished BedieningRolluiken
2020-04-26 22:04:50.204 Error: dzVents: Error: (3.0.2) Bediening rolluiken: Error parsing json to LUA table: /home/pi/domoticz/scripts/dzVents/../lua/JSON.lua:808: expected string argument to JSON:decode(), got table 
I'm probably confused by the fact that the error message is shown after the last line of the script.

The function dz.utils._.str() is very usefull, thanxs!
Domoticz 2020.2 - RPi3B+ - RFXtrx433XL - P1 - CC2531 - Somfy - Xiaomi - Hue - Omron - MQTT
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest