Page 1 of 1

Async solution for getting openUV data with API Key (no longer kind of )

Posted: Thursday 24 May 2018 16:18
by waaren
Because I could not use dzVents async openURL together with an API key to get UV and ozone data from openUV, I made a script that kind of simulates that approach with the help of a domoticz user variable.

[EDIT} no longer needed. See updated script and remarks in post 4

First get your free API key from https://www.openuv.io/ and enter that in the data section of the script.
In the same area you need to enter your longitude . latitude values and devicenumbers of your (to be created) virtual UV devices (current and max today) and of the two alerts (UV and ozone alert).

you need dzVents 2.4.0 or later to be able to use this script. Tested and working on PI-3 with Debian stretch. (domoticz V3.9476)

Code: Select all

--[[ openUV.lua for [ dzVents >= 2.4 ] 
]]--

return {
    on      =   {   timer           =   { "every 15 minutes at daytime" }, -- Triggers the getJsonPart
                    httpResponses   =   { "openUV_Response" }               -- Trigger the handle Json part
                },
                
    logging =   {   level     =   domoticz.LOG_DEBUG,                                   
                    marker    =   "openUV" 
                },                                           

    data    =   {   openUV_Longitude          = {initial = "x.xxxxxx"                           },  -- I store my longitude, latitude, APIkey, filename in data
                    openUV_Latitude           = {initial = "xx.xxxxxx"                          },  -- You can get them from domoticz settings
                    openUV_Filename           = {initial = "scripts/dzVents/data/OpenUV.json"   },  -- path relative to domoticz directory
                    openUV_APIKey             = {initial = "blablablabla1234567blablablablaa"   },  -- get your free API key from https://www.openuv.io/
                    openUV_currentUV_device   = {initial = xxx                                  },  -- You have to create a couple of virtual devices 
                    openUV_maxUV_device       = {initial = xxx                                  },  -- (first two as UV sensors and other two as Alert)
                    openUV_UV_Alert_device    = {initial = xxx                                  },  -- Remember device ID's and replace the "xxx" with them
                    openUV_ozone_Alert_device = {initial = xxx                                  },  -- Look at https://www.domoticz.com/wiki/Hardware_Setup#Dummy_Hardware 
                                                                                                    -- If you need help with this
                },
 
    execute = function(dz, trigger)
            
        local function UV_Index2Alert(index)                            -- Levels as from KNMI
            local alert = dz.ALERTLEVEL_RED
            if      index < 3 then alert = dz.ALERTLEVEL_GREY
            elseif  index < 5 then alert = dz.ALERTLEVEL_GREEN
            elseif  index < 7 then alert = dz.ALERTLEVEL_YELLOW
            elseif  index < 9 then alert = dz.ALERTLEVEL_ORANGE
            end
            return alert
        end

        local function ozone2Alert(value)                               -- Levels as found on various WIKI pages
            local alert = dz.ALERTLEVEL_RED
            if      value > 400 then alert = dz.ALERTLEVEL_GREY
            elseif  value > 340 then alert = dz.ALERTLEVEL_GREEN
            elseif  value > 310 then alert = dz.ALERTLEVEL_YELLOW
            elseif  value > 280 then alert = dz.ALERTLEVEL_ORANGE
            end
            return alert
        end
       
        local function getOpenUV_json()
            local openUV_url        = "https://api.openuv.io/api/v1/uv?lat=" .. dz.data.openUV_Latitude .. "&lng=" .. dz.data.openUV_Longitude 
             dz.openURL({
                            url = openUV_url ,
                            method = "GET",
                            callback = "openUV_Response",
                            headers = { ['x-access-token'] =  dz.data.openUV_APIKey },
                      })
        end
                
        local function handleOpenUVResponse()
            -- Read response into table and close file
            openUVResponse      = trigger.json

            if openUVResponse.result.uv                      == nil or
               openUVResponse.result.uv_max                  == nil or
               openUVResponse.result.uv_max_time             == nil or 
               openUVResponse.result.ozone                   == nil or
               openUVResponse.result.safe_exposure_time.st3  == nil then
               dz.log("Some values are missing; check it out",dz.LOG_ERROR) 
               dz.log(openUVResponse,dz.LOG_ERROR) 
               return
            end    

            -- Update UV devices    
            dz.devices(dz.data.openUV_currentUV_device).updateUV(dz.utils.round(openUVResponse.result.uv,1))
            dz.devices(dz.data.openUV_maxUV_device).updateUV(dz.utils.round(openUVResponse.result.uv_max,1))

            -- convert to local time
            local dateOutput        = assert(io.popen("date -d" .. openUVResponse.result.uv_max_time ..  " +%k:%M uur"))   
            local openUVMaxUVtime   = dateOutput:read("*all")
            dateOutput:close()
            
            -- Construct Alertlevel and text and update UV alert device (type = Alert)
            UV_AlertText = "Max UV index today is " .. dz.utils.round(openUVResponse.result.uv_max,1) .. " at " .. openUVMaxUVtime 
            dz.log("Current UV index = " .. dz.utils.round(openUVResponse.result.uv,1) .. ", " ..  UV_AlertText,dz.LOG_INFO)
            dz.devices(dz.data.openUV_UV_Alert_device).updateAlertSensor(UV_Index2Alert(openUVResponse.result.uv_max), UV_AlertText)

            -- Construct Alertlevel and text and update ozone alert device (type = Alert)
            ozoneAlertText = "Ozone (Dobson unit) is " .. openUVResponse.result.ozone .. "\n Max. exposure to sun (Skintype 3) is " ..
                            openUVResponse.result.safe_exposure_time.st3 .. " minutes."         
            dz.log(ozoneAlertText,dz.LOG_INFO)
            dz.devices(dz.data.openUV_ozone_Alert_device).updateAlertSensor(ozone2Alert(openUVResponse.result.ozone), ozoneAlertText)
        end
        
        if trigger.isTimer then
            getOpenUV_json()
        else     
            handleOpenUVResponse()
        end
    end
}
 
[EDIT & BTW] I am still considering if I will include this in my updateWeatherSensors solution. Any advice on that is appreciated.

have Fun!

Re: (kind of) async solution for getting openUV data with API Key

Posted: Thursday 24 May 2018 18:49
by EddyG
Nice solution. I filled a bug report in the dzVents section for the problem with the header.
I hope that Dannybloe can solve that.
If that problem is solved, I think you should include this in your buienradar script.
Perhaps you could then also get 'cloudCover' from https://api.darksky.net/forecast/<api-key>/<lat>,<lon>
There are some calculations for UV and cloudCover to get the real UV. Just an idea. ;)

Re: (kind of) async solution for getting openUV data with API Key

Posted: Thursday 24 May 2018 19:27
by EddyG
My bad (syntax BUG). This works.

Code: Select all

                        domoticz.openURL({
                                url = 'https://api.openuv.io/api/v1/uv?lat=<lat>&lng=<lon>',
                                method = 'GET',
                                callback = 'UV-data',
                                headers = { ['x-access-token'] = '<api-key>' },
And later to get the UV from the response:

Code: Select all

 local UVvalue = item.json.result.uv

Re: (kind of) async solution for getting openUV data with API Key

Posted: Friday 25 May 2018 1:42
by waaren
The reply from EddyG made it possible for me to modify my script in such a way that it is no longer dependent on user variables to simulate async behaviour of collecting the UV json and handling it.
The updated script now use native dzVents to achieve the async method.

[EDIT 20180525 - 18:05] bugfix in time conversion uv_max_time

Code: Select all

--[[ openUV.lua for [ dzVents >= 2.4 ] 
]]--

return {
    on      =   {   timer           =   { "every 15 minutes at daytime" }, -- Triggers the getJsonPart
                    httpResponses   =   { "openUV_Response" }               -- Trigger the handle Json part
                },
                
    logging =   {   level     =   domoticz.LOG_DEBUG,                                   
                    marker    =   "openUV" 
                },                                           

    data    =   {   openUV_Longitude          = {initial = "x.xxxxxx"                           },  -- I store my longitude, latitude, APIkey, filename in data
                    openUV_Latitude           = {initial = "xx.xxxxxx"                          },  -- You can get them from domoticz settings
                    openUV_Filename           = {initial = "scripts/dzVents/data/OpenUV.json"   },  -- path relative to domoticz directory
                    openUV_APIKey             = {initial = "blablablabla1234567blablablablaa"   },  -- get your free API key from https://www.openuv.io/
                    openUV_currentUV_device   = {initial = xxx                                  },  -- You have to create a couple of virtual devices 
                    openUV_maxUV_device       = {initial = xxx                                  },  -- (first two as UV sensors and other two as Alert)
                    openUV_UV_Alert_device    = {initial = xxx                                  },  -- Remember device ID's and replace the "xxx" with them
                    openUV_ozone_Alert_device = {initial = xxx                                  },  -- Look at https://www.domoticz.com/wiki/Hardware_Setup#Dummy_Hardware 
                                                                                                    -- If you need help with this
                },
 
    execute = function(dz, trigger)
            
        local function UV_Index2Alert(index)                            -- Levels as from KNMI
            local alert = dz.ALERTLEVEL_RED
            if      index < 3 then alert = dz.ALERTLEVEL_GREY
            elseif  index < 5 then alert = dz.ALERTLEVEL_GREEN
            elseif  index < 7 then alert = dz.ALERTLEVEL_YELLOW
            elseif  index < 9 then alert = dz.ALERTLEVEL_ORANGE
            end
            return alert
        end

        local function ozone2Alert(value)                               -- Levels as found on various WIKI pages
            local alert = dz.ALERTLEVEL_RED
            if      value > 400 then alert = dz.ALERTLEVEL_GREY
            elseif  value > 340 then alert = dz.ALERTLEVEL_GREEN
            elseif  value > 310 then alert = dz.ALERTLEVEL_YELLOW
            elseif  value > 280 then alert = dz.ALERTLEVEL_ORANGE
            end
            return alert
        end
       
        local function getOpenUV_json()
            local openUV_url        = "https://api.openuv.io/api/v1/uv?lat=" .. dz.data.openUV_Latitude .. "&lng=" .. dz.data.openUV_Longitude 
             dz.openURL({
                            url = openUV_url ,
                            method = "GET",
                            callback = "openUV_Response",
                            headers = { ['x-access-token'] =  dz.data.openUV_APIKey },
                      })
        end
                
        local function handleOpenUVResponse()
            -- Read response into table and close file
            openUVResponse      = trigger.json

            if openUVResponse.result.uv                      == nil or
               openUVResponse.result.uv_max                  == nil or
               openUVResponse.result.uv_max_time             == nil or 
               openUVResponse.result.ozone                   == nil or
               openUVResponse.result.safe_exposure_time.st3  == nil then
               dz.log("Some values are missing; check it out",dz.LOG_ERROR) 
               dz.log(openUVResponse,dz.LOG_ERROR) 
               return
            end    

            -- Update UV devices    
            dz.devices(dz.data.openUV_currentUV_device).updateUV(dz.utils.round(openUVResponse.result.uv,1))
            dz.devices(dz.data.openUV_maxUV_device).updateUV(dz.utils.round(openUVResponse.result.uv_max,1))

                -- convert to local time
            local commandString     = "date -d " .. openUVResponse.result.uv_max_time ..  "  '+%k:%M uur' "
            local dateOutput        = assert(io.popen(commandString))   
            local openUVMaxUVtime   = dateOutput:read("*all")
            dateOutput:close()
            
            -- Construct Alertlevel and text and update UV alert device (type = Alert)
            UV_AlertText = "Max UV index today is " .. dz.utils.round(openUVResponse.result.uv_max,1) .. " at " .. openUVMaxUVtime 
            dz.log("Current UV index = " .. dz.utils.round(openUVResponse.result.uv,1) .. ", " ..  UV_AlertText,dz.LOG_INFO)
            dz.devices(dz.data.openUV_UV_Alert_device).updateAlertSensor(UV_Index2Alert(openUVResponse.result.uv_max), UV_AlertText)

            -- Construct Alertlevel and text and update ozone alert device (type = Alert)
            ozoneAlertText = "Ozone (Dobson unit) is " .. openUVResponse.result.ozone .. "\n Max. exposure to sun (Skintype 3) is " ..
                            openUVResponse.result.safe_exposure_time.st3 .. " minutes."         
            dz.log(ozoneAlertText,dz.LOG_INFO)
            dz.devices(dz.data.openUV_ozone_Alert_device).updateAlertSensor(ozone2Alert(openUVResponse.result.ozone), ozoneAlertText)
        end
        
        if trigger.isTimer then
            getOpenUV_json()
        else     
            handleOpenUVResponse()
        end
    end
}
 
so many thanks and credits to @EddyG

have Fun !