Page 1 of 1
Simple JSON reply read?
Posted: Saturday 29 September 2018 19:18
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?
Re: Simple JSON reply read?
Posted: Saturday 29 September 2018 19:33
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 ?
Re: Simple JSON reply read?
Posted: Saturday 29 September 2018 21:55
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
Re: Simple JSON reply read?
Posted: Saturday 29 September 2018 22:18
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¶m=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
}
Re: Simple JSON reply read?
Posted: Sunday 30 September 2018 12:31
by EdddieN
Thanks, I just PM you with the link
Re: Simple JSON reply read? [Solved]
Posted: Sunday 30 September 2018 15:54
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
}
Re: Simple JSON reply read?
Posted: Sunday 30 September 2018 18:38
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
Re: Simple JSON reply read?
Posted: Sunday 30 September 2018 21:51
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?
Re: Simple JSON reply read?
Posted: Monday 01 October 2018 0:05
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