Simple JSON reply read?  [Solved]

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

Moderator: leecollings

Post Reply
User avatar
EdddieN
Posts: 510
Joined: Wednesday 16 November 2016 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.9700
Location: Scotland
Contact:

Simple JSON reply read?

Post by EdddieN »

Hello,

I have a URL that when I call it, it returns this:
{"Label":["28/09/2018","29/09/2018"],"Data":["1195","1181"]}
The Data numbers can be up to 6 max, those represent the number of days from the date before.

Until now I have used this LUA script which seems a bit obsolete and sometimes does not work very well, for example it only returns a value if I have 6 values on the Data reply:

Code: Select all

local t1 = os.date("%H") -- get hour time digit
local t2 = os.date("%M") -- get minute time digit


commandArray = {}
 
 if t1 == "20" and t2 == "32" then -- only poll at 11pm every day

json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")()  -- For Linux
 
       --  API call
       local config=assert(io.popen('curl "http://urladdress.com/Report/GetChartData?SerialNo=1234&DeviceNo=0&NumericPeriod=0"'))
       local Stringjson = config:read('*all')
       config:close()
       local jsonData = json:decode(Stringjson)
       local oil = jsonData.Data[6]

-- print ("JSON DATA" ..Stringjson)  -- debug json
print ("Litres " ..tostring(oil)) -- parsed json value
-- commandArray['UpdateDevice'] = 465 .. "|0|" .. oil -- update sensor value

Oilpercentage = (oil * 100) / 1250
-- print (Oilpercentage)

-- commandArray['UpdateDevice'] = 472 .. "|0|" .. Oilpercentage  -- update sensor value
commandArray[1]={['UpdateDevice']='465|0|' .. oil}
commandArray[2]={['UpdateDevice']='472|0|' .. Oilpercentage}


 end

return commandArray
Is there a simpler way to do it in dzVents without the need of the JSON.lua?
11101101 - www.machinon.com
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Simple JSON reply read?

Post by waaren »

EdddieN wrote: Saturday 29 September 2018 19:18 I have a URL that when I call it, it returns this:
{"Label":["28/09/2018","29/09/2018"],"Data":["1195","1181"]}
The Data numbers can be up to 6 max, those represent the number of days from the date before.
Until now I have used this LUA script which seems a bit obsolete and sometimes does not work very well, for example it only returns a value if I have 6 values on the Data reply:
Hi @EddieN happy to help.
Is my assumption correct that you are always looking for the last value in Data ?
What are the types and subtypes of device 465 and 472 ?
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
EdddieN
Posts: 510
Joined: Wednesday 16 November 2016 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.9700
Location: Scotland
Contact:

Re: Simple JSON reply read?

Post by EdddieN »

Thanks!

Yes the last value.

The devices id are just virtual that I use to populate the output of the Json.

For example I have a Oil sensor virtual which I inject the value from the Json
11101101 - www.machinon.com
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Simple JSON reply read?

Post by waaren »

EdddieN wrote: Saturday 29 September 2018 21:55 Thanks!

Yes the last value.

The devices id are just virtual that I use to populate the output of the Json.

For example I have a Oil sensor virtual which I inject the value from the Json
I understand that they are virtual but in dzVents every devicetype has its own specific device-adapter and methods to update values. For now I will assume counter and percentage.
Without an actual link it is kind of hard to test so I had to fake some parts but I think this one should be close to what you described.

Code: Select all

-- getOil

local callBackString = "getOil"

return {
    on      =   {   timer           =   { "at 20:32" },       -- Triggers the getJsonPart
                    httpResponses   =   { callBackString }    -- Trigger the handle Json part
                },
    logging =   {   level     =   domoticz.LOG_DEBUG,
                    marker    =   "getOil"    },

    execute = function(dz, trigger)

        local function triggerJSON()
            local  URLString   = "http://urladdress.com/Report/GetChartData?SerialNo=1234&DeviceNo=0&NumericPeriod=0"
            dz.openURL({    url = URLString,
                            method = "GET",
                            callback = callBackString })                      
        end

        local function getResponse()
            local rt = dz.utils.fromJSON(trigger.data)
            local data = rt.Data
            return (data[#data])
        end
        
        -- main 
        if not (trigger.isHTTPResponse) then
            triggerJSON()
        elseif trigger.ok then                                      -- statusCode == 2xx
            local oilDevice             = dz.devices(465)
            local oilPercentageDevice   = dz.devices(472)
            local oil                   = tonumber(getResponse())
            oilDevice.updateCounter(oil)				-- Type: General      subType: Counter incremental
            oilPercentageDevice.updatePercentage(oil * 100 / 1250)	-- Type: General      subType: Percentage
        else
            dz.log("triggerJSON() : Could not get (valid) data from urladdress" ,dz.LOG_ERROR)
        end
    end
}
the one below is the code I used to test.
Spoiler: show

Code: Select all

-- getOil

local callBackString = "getOil"

return {

    on      =   {   timer           =   { "at 20:32" },       -- Triggers the getJsonPart
                    devices         =   { "oilActivator" },       -- Only used for test / developement
                    httpResponses   =   { callBackString }          -- Trigger the handle Json part
                },
                
    logging =   {   level     =   domoticz.LOG_DEBUG,
                    marker    =   "getOil"    },

        
    execute = function(dz, trigger)

            
        local function triggerJSON()
            --local  URLString   = "http://urladdress.com/Report/GetChartData?SerialNo=1234&DeviceNo=0&NumericPeriod=0"
            local  URLString   = dz.settings['Domoticz url'] .. /json.htm?type=command&param=getversion"
            dz.openURL({    url = URLString,
                            method = "GET",
                            callback = callBackString })                      
        end

        local function getResponse()
            local rt = dz.utils.fromJSON(trigger.data)
            for k, v in pairs(rt) do
                dz.log("Key: " .. k .. "   Value: " .. tostring(v),dz.LOG_DEBUG)
            end
            
            jsonString = '{"Label":["28/09/2018","29/09/2018"],"Data":["1195","1181","234","456"]}'
            local rt = dz.utils.fromJSON(jsonString)
            local data = rt.Data
            dz.log(data[1],dz.LOG_DEBUG)
            return (data[#data])
        end
        
        -- main 
        if not (trigger.isHTTPResponse) then
            triggerJSON()
        elseif trigger.ok then                                      -- statusCode == 2xx
        
            -- local oilDevice             = dz.devices(465)
            local oilDevice             = dz.devices(1061)
            -- local oilPercentageDevice   = dz.devices(472)
            local oilPercentageDevice   = dz.devices(1062)
            
            local oil                   = tonumber(getResponse())
            
            oilDevice.updateCounter(oil)
            oilPercentageDevice.updatePercentage(oil * 100 / 1250)
        else
            dz.log("triggerJSON() : Could not get (valid) data from xxxxxxxx" ,dz.LOG_ERROR)
        end
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
EdddieN
Posts: 510
Joined: Wednesday 16 November 2016 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.9700
Location: Scotland
Contact:

Re: Simple JSON reply read?

Post by EdddieN »

Thanks, I just PM you with the link
11101101 - www.machinon.com
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Simple JSON reply read?  [Solved]

Post by waaren »

EdddieN wrote: Sunday 30 September 2018 12:31 Thanks, I just PM you with the link
Tested and working script. Added some comments to explain what the code does.

Code: Select all

-- getOil
local callBackString = "getOil"

return {
    on      =   {   timer           =   { "at 20:32" },          -- call to url will be done at this set time
                    httpResponses   =   { callBackString }       -- Script will be triggered again when url call rcomes back with data (= almost immediate)
                },
               
--    logging =   {   level     =   domoticz.LOG_DEBUG,          -- remove the comment -- in this and next line when debugging 
--                    marker    =   "getOil"    },
        
    execute = function(dz, trigger)

        local function triggerJSON()
            local  URLString   = "enter your url between the quotes"
            dz.openURL({    url = URLString,
                            method = "GET",
                            callback = callBackString })                      
        end

        local function getResponse()
            local rt = dz.utils.fromJSON(trigger.data)  -- convert json data to Lua table
            local data = rt.Data                        -- get subtable Data
            return (data[#data])                        -- return last value in data table
        end
        
        -- main 
        if not (trigger.isHTTPResponse) then
            triggerJSON()                              -- call to url
        elseif trigger.ok then                         -- statusCode == 2xx
        
            local oilCounter         = dz.devices(465)           -- virtual sensor (counter)
            local oilPercentage      = dz.devices(472)           -- virtual sensor (percentage)
            
            local oil                = tonumber(getResponse())   -- sometimes returnValue is a string  
           
            if oil ~= oilCounter.counter then                    -- No need to update device if value have not changed  
                dz.log("OilCounter updated to " .. oil ,dz.LOG_DEBUG)
                oilCounter.updateCounter(oil)
                oilPercentage.updatePercentage(oil * 100 / 1250)
            else
                dz.log("No update of oilCounter necessary. It is still " .. oil ,dz.LOG_DEBUG)
            end
        else
            dz.log("triggerJSON() : Could not get (valid) data from xxxxxxxx" ,dz.LOG_ERROR)
        end
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
EdddieN
Posts: 510
Joined: Wednesday 16 November 2016 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.9700
Location: Scotland
Contact:

Re: Simple JSON reply read?

Post by EdddieN »

Thanks,

465 is a virtual sensor (not counter as it can go up from time to time), the % (472) has update but no the virtual sensor.

The log file returns this:
2018-09-30 17:35:00.416 Status: dzVents: Info: getOil: ------ Start internal script: Oil_Poller2:, trigger: at 17:35
2018-09-30 17:35:00.416 Status: dzVents: Debug: getOil: OpenURL: url = http://urladdress.com
2018-09-30 17:35:00.416 Status: dzVents: Debug: getOil: OpenURL: method = GET
2018-09-30 17:35:00.416 Status: dzVents: Debug: getOil: OpenURL: post data = nil
2018-09-30 17:35:00.416 Status: dzVents: Debug: getOil: OpenURL: headers = nil
2018-09-30 17:35:00.416 Status: dzVents: Debug: getOil: OpenURL: callback = getOil
2018-09-30 17:35:00.417 Status: dzVents: Info: getOil: ------ Finished Oil_Poller2
2018-09-30 17:35:00.630 Status: EventSystem: Script event triggered: /home/pi/domoticz/dzVents/runtime/dzVents.lua
.
.
2018-09-30 17:35:02.872 Status: dzVents: Info: Handling httpResponse-events for: "getOil
2018-09-30 17:35:02.872 Status: dzVents: Info: getOil: ------ Start internal script: Oil_Poller2: HTTPResponse: "getOil"
2018-09-30 17:35:02.920 Status: dzVents: Debug: getOil: Processing device-adapter for Oil tank: Custom sensor device adapter
2018-09-30 17:35:02.922 Status: dzVents: Debug: getOil: Processing device-adapter for Oiltank left: Percentage device adapter
2018-09-30 17:35:02.922 Status: dzVents: Debug: getOil: OilCounter updated to 1181
2018-09-30 17:35:02.922 Status: dzVents: Error (2.4.6): getOil: Method updateCounter is not available for device "Oil tank" (deviceType=General, deviceSubType=Custom Sensor). If you believe this is not correct, please report.
2018-09-30 17:35:02.923 Status: dzVents: Info: getOil: ------ Finished Oil_Poller2
2018-09-30 17:35:02.923 Status: EventSystem: Script event triggered: /home/pi/domoticz/dzVents/runtime/dzVents.lua
the 1181 value does not get updated, also curious why the script repeats twice.

Tried changing updatecounter with updateCustomSensor(value) but gives me an error
11101101 - www.machinon.com
User avatar
EdddieN
Posts: 510
Joined: Wednesday 16 November 2016 11:31
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.9700
Location: Scotland
Contact:

Re: Simple JSON reply read?

Post by EdddieN »

Forget my last comment, got it working. Obviulsy I cannot write UpdateCustomSensor property, it was a typo.

Thanks so much for writing this!! :)

I understand most of the code, except this:

local function getResponse()
local rt = dz.utils.fromJSON(trigger.data) -- convert json data to Lua table
local data = rt.Data -- get subtable Data
return (data[#data]) -- return last value in data table
end

Mostly the subdata and the last data part?
11101101 - www.machinon.com
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Simple JSON reply read?

Post by waaren »

EdddieN wrote: Sunday 30 September 2018 21:51 I understand most of the code, except this:

local function getResponse()
local rt = dz.utils.fromJSON(trigger.data) -- convert json data to Lua table
local data = rt.Data -- get subtable Data
return (data[#data]) -- return last value in data table
end

Mostly the subdata and the last data part?
trigger.data is the complete response from the url. In the first line of the function I force dzVents to interpret this as a json string and convert this string to a (nested) table. This table looks something like
Label
"28/09/2018"
"29/09/2018"
Data
"1195" -- can be accessed by rt.Data[1]
"1181" -- can be accessed by rt.Data[2] or by rt.Data[#rt.Data]

You are only interested in the Data part of this table and specific in the last entry of this part. Lua uses the #tablename syntax for the last entry in a table. Using local data = rt.Data, I create a second reference to the subtable for readability and refer to the last element in that subtable with data[#data] .
I could have done the same with
local function getResponse()
local rt = dz.utils.fromJSON(trigger.data) -- convert json data to Lua table
return (rt.Data[#rt.Data]) -- return last value in data table
end
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest