Yes it's possible but what do you want?
The max temp for the next 24 hours (current hour - same hour tomorrow) or the max temp for the next day (00:00 - 23:59)?
Moderator: leecollings
Yes it's possible but what do you want?
Maybe, if possible the max for "today 00:00 - 23:59" and the next day "00:00 - 23:59"
Added optional virtual devices for max. temperature today, max temperature tomorrow, mm rain today, mm rain tomorrow.
Code: Select all
--[[
This script collects rain en temperature forecast data from openweathermap.org
You need a free API key to access this data. Read howto get this free API key
at https://openweathermap.org/guide#how
Next you need to create a uservariable (type string) and enter the openweathermap API key as value
Then create the devices you want
Please note that dzVents requires acces to domoticz at a sufficient level to retrieve the location settings
including the latititude and longitude. It can only get these if the Local Networks (nu username/password)
include 127.0.0.1 (and ::1 for systems using IPv6)
Explained in the wiki at: https://www.domoticz.com/wiki/DzVents:_next_generation_LUA_scripting#Using_dzVents_with_Domoticz
original script posted: https://www.domoticz.com/forum/viewtopic.php?f=59&t=33424&start=20
history
20200720 Start coding - shared on forum
20200722 Added average and minimum temperature devices
20200806 Added optional virtual devices for max. temperature today, max temperature tomorrow, mm rain today, mm rain tomorrow.
]]--
local scriptVar = 'openWeatherMap'
return
{
on = {
timer =
{
'at *:17'
},
devices =
{
scriptVar .. 'Trigger', -- only used for testing
},
httpResponses =
{
scriptVar
}
},
logging =
{
level = domoticz.LOG_DEBUG, -- switch to domoticz.ERROR when script works as designed
marker = scriptVar,
},
execute = function(dz, item)
-- ******** enter names of vars and devices below this line
local openWeatherAPIKey = dz.variables('openWeatherAPIKey').value -- Type string var required
local currentRain = dz.devices('Current rain') -- optional virtual Custom Sensor
local rain48Hours = dz.devices('Rain 48 hours') -- optional virtual Custom Sensor
local rain8Days = dz.devices('Rain 8 days') -- optional virtual Custom Sensor
local rainToday = dz.devices('Rain today') -- optional virtual Custom Sensor
local rainTomorrow = dz.devices('Rain tomorrow') -- optional virtual Custom Sensor
local weatherText = dz.devices('WeatherForecast') -- optional text Sensor
local currentTemperature = dz.devices('Current Temperature') -- Optional virtual Temperature sensor
local maxTemperature48Hours = dz.devices('Max Temperature next 48 hours') -- Optional virtual Temperature sensor
local maxTemperature8Days = dz.devices('Max Temperature next 8 days') -- Optional virtual Temperature sensor
local minTemperature48Hours = dz.devices('Min Temperature next 48 hours') -- Optional virtual Temperature sensor
local minTemperature8Days = dz.devices('Min Temperature next 8 days') -- Optional virtual Temperature sensor
local maxTemperatureToday = dz.devices('Max Temperature today') -- Optional virtual Temperature sensor
local maxTemperatureTomorrow = dz.devices('Max Temperature tomorrow') -- Optional virtual Temperature sensor
local avgTemperature48Hours = dz.devices('Average Temperature next 48 hours') -- Optional virtual Temperature sensor
local avgTemperature8Days = dz.devices('Average Temperature next 8 days') -- Optional virtual Temperature sensor
-- ******** No changes required below this line
local openWeatherURL = 'https://api.openweathermap.org/data/2.5/onecall?&units=metric'
local DAY_SECONDS = 86400
local endOfToday = os.time{year = dz.time.year, month = dz.time.month, day = dz.time.day, hour = 0} + DAY_SECONDS
local endOfTomorrow = endOfToday + DAY_SECONDS
local function getCurrentRain(t)
if t == nil then return 0 end
local totalmm = 0
for key, mm in pairs(t) do
totalmm = totalmm + mm
end
return totalmm
end
local function getDayNightSeconds(t)
t.daySeconds = t.sunset - t.sunrise
t.nightSeconds= DAY_SECONDS - t.daySeconds
end
local function get8DaysTemperatures(t)
local maxTemperature = -100
local minTemperature = 100
local avgTemperature, avgHelper = 0, 0
for _, record in ipairs(t) do
getDayNightSeconds(record)
if record.temp.max > maxTemperature then maxTemperature = record.temp.max end
if record.temp.min < minTemperature then minTemperature = record.temp.min end
avgTemperature = ( record.temp.day * record.daySeconds + record.temp.night * record.nightSeconds ) / DAY_SECONDS
avgHelper = avgHelper + avgTemperature
end
avgTemperature = avgHelper / #t
return dz.utils.round(maxTemperature,1), dz.utils.round(minTemperature,1), dz.utils.round(avgTemperature,1)
end
local function getHoursTemperatures(t)
local maxTemperature, maxTemperatureToday, maxTemperatureTomorrow = -100, -100, -100
local minTemperature = 100
local avgHelper = 0
for _, record in ipairs(t) do
if record.dt < endOfToday and record.temp > maxTemperatureToday then maxTemperatureToday = record.temp end
if record.dt > endOfToday and record.dt < endOfTomorrow and record.temp > maxTemperatureTomorrow then maxTemperatureTomorrow = record.temp end
if record.temp > maxTemperature then maxTemperature = record.temp end
if record.temp < minTemperature then minTemperature = record.temp end
avgHelper = avgHelper + record.temp
end
return dz.utils.round(maxTemperature,1),
dz.utils.round(minTemperature,1),
dz.utils.round((avgHelper / #t),1),
dz.utils.round(maxTemperatureToday,1),
dz.utils.round(maxTemperatureTomorrow,1)
end
local function getHoursRain(t)
if t == nil then return 0 end
local totalmm,todaymm, tomorrowmm = 0,0,0
for key, record in ipairs(t) do
if type(record) == 'table' and record.rain ~= nil then
for id, mm in pairs(record.rain) do
todaymm = todaymm + ( ( record.dt < endOfToday and mm ) or 0 )
tomorrowmm = tomorrowmm + ( ( record.dt > endOfToday and record.dt < endOfTomorrow and mm ) or 0 )
totalmm = totalmm + mm
end
end
end
return totalmm, todaymm, tomorrowmm
end
local function get8DaysRain(t)
if t == nil then return 0 end
local totalmm = 0
for key, record in ipairs(t) do
if type(record) == 'table' and record.rain ~= nil then
totalmm = totalmm + record.rain
end
end
return totalmm
end
local function createResultTable(rt)
rt.currentRain = getCurrentRain(rt.current.rain)
rt.rain48Hours, rt.todaymm, rt.tomorrowmm = getHoursRain(rt.hourly)
rt.rain8Days = get8DaysRain(rt.daily)
rt.maxTemperature48Hours, rt.minTemperature48Hours,
rt.avgTemperature48Hours, rt.maxTemperatureToday, rt.maxTemperatureTomorrow = getHoursTemperatures(rt.hourly)
rt.maxTemperature8Days, rt.minTemperature8Days, rt.avgTemperature8Days = get8DaysTemperatures(rt.daily)
rt.maxTemperature8Days = math.max(rt.maxTemperature48Hours, rt.maxTemperature8Days)
rt.minTemperature8Days = math.min(rt.minTemperature48Hours, rt.minTemperature8Days)
end
local function updateTextDevice(t)
local text = 'range: rain - max Temp' .. '\n'
text = text .. 'current: ' .. t.currentRain .. ' mm, ' .. t.current.temp .. ' °C' .. '\n'
text = text .. '48 hours: ' .. t.rain48Hours .. ' mm, ' .. t.maxTemperature48Hours .. ' °C' .. '\n'
text = text .. '8 days: ' .. t.rain8Days .. ' mm, ' .. t.maxTemperature8Days .. ' °C' .. '\n'
weatherText.updateText(text)
end
local function deviceExists(dv)
if dv == nil then
return false
else
return dz.utils.deviceExists(dv.name)
end
end
local function updateDevice(dv, value)
if deviceExists(dv) then
if dv.deviceType == 'Temp' then
dv.updateTemperature(value)
else
dv.updateCustomSensor(value)
end
end
end
local function updateDevices(rt)
updateDevice(currentRain, rt.currentRain)
updateDevice(rain48Hours, rt.rain48Hours)
updateDevice(rain8Days, rt.rain8Days)
updateDevice(rainTomorrow, rt.tomorrowmm)
updateDevice(currentTemperature, rt.current.temp)
updateDevice(maxTemperature48Hours, rt.maxTemperature48Hours)
updateDevice(maxTemperature8Days, rt.maxTemperature8Days)
updateDevice(maxTemperatureTomorrow, rt.maxTemperatureTomorrow)
updateDevice(minTemperature48Hours, rt.minTemperature48Hours)
updateDevice(minTemperature8Days, rt.minTemperature8Days)
updateDevice(avgTemperature48Hours, rt.avgTemperature48Hours)
updateDevice(avgTemperature8Days, rt.avgTemperature8Days)
if deviceExists(rainToday) and rainToday.lastUpdate.dDate < ( endOfToday - DAY_SECONDS ) then
updateDevice(rainToday, rt.todaymm)
elseif deviceExists(rainToday) then
updateDevice(rainToday, math.max(rt.todaymm, tonumber(rainToday.sValue)))
end
if deviceExists(maxTemperatureToday) and maxTemperatureToday.lastUpdate.dDate < ( endOfToday - DAY_SECONDS ) then
updateDevice(maxTemperatureToday, rt.maxTemperatureToday)
elseif deviceExists(maxTemperatureToday) then
updateDevice(maxTemperatureToday, math.max(rt.maxTemperatureToday, maxTemperatureToday.temperature))
end
if deviceExists(weatherText) then updateTextDevice(rt) end
end
-- main code
if item.isHTTPResponse then
if item.ok and item.isJSON then
local rt = item.json
createResultTable(rt)
updateDevices(rt)
else
dz.log('There was a problem with the response from ' .. scriptVar, dz.LOG_ERROR)
dz.log(item, dz.LOG_DEBUG)
end
else -- get the data from openweatherMap
dz.openURL({
url = openWeatherURL ..
'&lat=' .. dz.settings.location.latitude ..
'&lon=' .. dz.settings.location.longitude ..
'&appid=' .. openWeatherAPIKey,
callback = scriptVar, -- see httpResponses above.
})
end
end
}
I added minTemperatureToday and minTemperatureTomorrow in below version
It is a rolling forecast meaning it will only look at the future.Is the maxtemperaturetoday for the entire day or for the remaining hours?
Because the information is a prediction about the future you could just take ( min + max ) / 2 for this just after midnight.Averagetemperaturetoday would also be useful for increased running @t higher temperatures (better COP)
Code: Select all
--[[
This script collects rain en temperature forecast data from openweathermap.org
You need a free API key to access this data. Read howto get this free API key
at https://openweathermap.org/guide#how
Next you need to create a uservariable (type string) and enter the openweathermap API key as value
Then create the devices you want
Please note that dzVents requires access to domoticz at a sufficient level to retrieve the location settings
including the latitude and longitude. It can only get these if the Local Networks (not using username/password)
include 127.0.0.1 (and ::1 for systems using IPv6)
Explained in the wiki at: https://www.domoticz.com/wiki/DzVents:_next_generation_LUA_scripting#Using_dzVents_with_Domoticz
original script posted: https://www.domoticz.com/forum/viewtopic.php?f=59&t=33424&start=20
history
20200720 Start coding - shared on forum
20200722 Added average and minimum temperature devices
20200806 Added optional virtual devices for max. temperature today, max temperature tomorrow, mm rain today, mm rain tomorrow.
20201109 Defined devices in separate table so the will only be visited when required
20200116 Add minimum temperature (rest of) today and tomorrow
]]--
local scriptVar = 'openWeatherMap'
return
{
on = {
timer =
{
'at *:17'
},
devices =
{
scriptVar .. 'Trigger', -- only used for testing
},
httpResponses =
{
scriptVar
}
},
logging =
{
level = domoticz.LOG_DEBUG, -- switch to domoticz.ERROR when script works as designed
marker = scriptVar,
},
execute = function(dz, item)
-- ******** enter name of API var and devices below this line
local openWeatherAPIKey = dz.variables('openWeatherAPIKey').value -- Type string var required
if item.isHTTPResponse then
-- ******** enter names of used devices between the quotes below this line
dv = {}
dv.currentRain = dz.devices('Current rain') -- optional virtual Custom Sensor
dv.rain48Hours = dz.devices('Rain 48 hours') -- optional virtual Custom Sensor
dv.rain8Days = dz.devices('Rain 8 days') -- optional virtual Custom Sensor
dv.rainToday = dz.devices('Rain today') -- optional virtual Custom Sensor
dv.rainTomorrow = dz.devices('Rain tomorrow') -- optional virtual Custom Sensor
dv.weatherText = dz.devices('WeatherForecast') -- optional text Sensor
dv.currentTemperature = dz.devices('Current Temperature') -- Optional virtual Temperature sensor
dv.maxTemperature48Hours = dz.devices('Max Temperature next 48 hours') -- Optional virtual Temperature sensor
dv.maxTemperature8Days = dz.devices('Max Temperature next 8 days') -- Optional virtual Temperature sensor
dv.minTemperature48Hours = dz.devices('Min Temperature next 48 hours') -- Optional virtual Temperature sensor
dv.minTemperature8Days = dz.devices('Min Temperature next 8 days') -- Optional virtual Temperature sensor
dv.maxTemperatureToday = dz.devices('Max Temperature today') -- Optional virtual Temperature sensor
dv.maxTemperatureTomorrow = dz.devices('Max Temperature tomorrow') -- Optional virtual Temperature sensor
dv.avgTemperature48Hours = dz.devices('Average Temperature next 48 hours') -- Optional virtual Temperature sensor
dv.avgTemperature8Days = dz.devices('Average Temperature next 8 days') -- Optional virtual Temperature sensor
dv.minTemperatureToday = dz.devices('Min Temperature today') -- Optional virtual Temperature sensor
dv.minTemperatureTomorrow = dz.devices('Min Temperature tomorrow') -- Optional virtual Temperature sensor
end
-- ******** No changes required below this line
local openWeatherURL = 'https://api.openweathermap.org/data/2.5/onecall?&units=metric'
local DAY_SECONDS = 86400
local endOfToday = os.time{year = dz.time.year, month = dz.time.month, day = dz.time.day, hour = 0} + DAY_SECONDS
local endOfTomorrow = endOfToday + DAY_SECONDS
local function getCurrentRain(t)
if t == nil then return 0 end
local totalmm = 0
for key, mm in pairs(t) do
totalmm = totalmm + mm
end
return totalmm
end
local function getDayNightSeconds(t)
t.daySeconds = t.sunset - t.sunrise
t.nightSeconds= DAY_SECONDS - t.daySeconds
end
local function get8DaysTemperatures(t)
local maxTemperature = -100
local minTemperature = 100
local avgTemperature, avgHelper = 0, 0
for _, record in ipairs(t) do
getDayNightSeconds(record)
if record.temp.max > maxTemperature then maxTemperature = record.temp.max end
if record.temp.min < minTemperature then minTemperature = record.temp.min end
avgTemperature = ( record.temp.day * record.daySeconds + record.temp.night * record.nightSeconds ) / DAY_SECONDS
avgHelper = avgHelper + avgTemperature
end
avgTemperature = avgHelper / #t
return dz.utils.round(maxTemperature,1), dz.utils.round(minTemperature,1), dz.utils.round(avgTemperature,1)
end
local function getHoursTemperatures(t)
local maxTemperature, maxTemperatureToday, maxTemperatureTomorrow = -100, -100, -100
local minTemperature, minTemperatureToday, minTemperatureTomorrow = 100, 100, 100
local avgHelper = 0
for _, record in ipairs(t.hourly) do
if record.dt < endOfToday and record.temp > maxTemperatureToday then maxTemperatureToday = record.temp end
if record.dt < endOfToday and record.temp < minTemperatureToday then minTemperatureToday = record.temp end
if record.dt > endOfToday and record.dt < endOfTomorrow and record.temp > maxTemperatureTomorrow then maxTemperatureTomorrow = record.temp end
if record.dt > endOfToday and record.dt < endOfTomorrow and record.temp < minTemperatureTomorrow then minTemperatureTomorrow = record.temp end
if record.temp > maxTemperature then maxTemperature = record.temp end
if record.temp < minTemperature then minTemperature = record.temp end
avgHelper = avgHelper + record.temp
end
t.maxTemperature48Hours = dz.utils.round(maxTemperature,1)
t.minTemperature48Hours = dz.utils.round(minTemperature,1)
t.avgTemperature48Hours = dz.utils.round((avgHelper / #t.hourly),1)
t.maxTemperatureToday = dz.utils.round(maxTemperatureToday,1)
t.maxTemperatureTomorrow = dz.utils.round(maxTemperatureTomorrow,1)
t.minTemperatureToday = dz.utils.round(minTemperatureToday,1)
t.minTemperatureTomorrow = dz.utils.round(minTemperatureTomorrow,1)
return t
end
local function getHoursRain(t)
if t == nil then return 0 end
local totalmm,todaymm, tomorrowmm = 0,0,0
for key, record in ipairs(t) do
if type(record) == 'table' and record.rain ~= nil then
for id, mm in pairs(record.rain) do
todaymm = todaymm + ( ( record.dt < endOfToday and mm ) or 0 )
tomorrowmm = tomorrowmm + ( ( record.dt > endOfToday and record.dt < endOfTomorrow and mm ) or 0 )
totalmm = totalmm + mm
end
end
end
return totalmm, todaymm, tomorrowmm
end
local function get8DaysRain(t)
if t == nil then return 0 end
local totalmm = 0
for key, record in ipairs(t) do
if type(record) == 'table' and record.rain ~= nil then
totalmm = totalmm + record.rain
end
end
return totalmm
end
local function createResultTable(rt)
rt.currentRain = getCurrentRain(rt.current.rain)
rt.rain48Hours, rt.todaymm, rt.tomorrowmm = getHoursRain(rt.hourly)
rt.rain8Days = get8DaysRain(rt.daily)
rt = getHoursTemperatures(rt)
rt.maxTemperature8Days, rt.minTemperature8Days, rt.avgTemperature8Days = get8DaysTemperatures(rt.daily)
rt.maxTemperature8Days = math.max(rt.maxTemperature48Hours, rt.maxTemperature8Days)
rt.minTemperature8Days = math.min(rt.minTemperature48Hours, rt.minTemperature8Days)
end
local function updateTextDevice(t)
local text = 'range: rain - max Temp' .. '\n'
text = text .. 'current: ' .. t.currentRain .. ' mm, ' .. t.current.temp .. ' °C' .. '\n'
text = text .. '48 hours: ' .. t.rain48Hours .. ' mm, ' .. t.maxTemperature48Hours .. ' °C' .. '\n'
text = text .. '8 days: ' .. t.rain8Days .. ' mm, ' .. t.maxTemperature8Days .. ' °C' .. '\n'
dv.weatherText.updateText(text)
end
local function deviceExists(dv)
if dv == nil then
return false
else
return dz.utils.deviceExists(dv.name)
end
end
local function updateDevice(dv, value)
if deviceExists(dv) then
if dv.deviceType == 'Temp' then
dv.updateTemperature(value)
else
dv.updateCustomSensor(value)
end
end
end
local function updateDevices(rt)
updateDevice(dv.currentRain, rt.currentRain)
updateDevice(dv.rain48Hours, rt.rain48Hours)
updateDevice(dv.rain8Days, rt.rain8Days)
updateDevice(dv.rainTomorrow, rt.tomorrowmm)
updateDevice(dv.currentTemperature, rt.current.temp)
updateDevice(dv.maxTemperature48Hours, rt.maxTemperature48Hours)
updateDevice(dv.maxTemperature8Days, rt.maxTemperature8Days)
updateDevice(dv.maxTemperatureToday, rt.maxTemperatureToday)
updateDevice(dv.minTemperatureToday, rt.minTemperatureToday)
updateDevice(dv.maxTemperatureTomorrow, rt.maxTemperatureTomorrow)
updateDevice(dv.minTemperatureTomorrow, rt.minTemperatureTomorrow)
updateDevice(dv.minTemperature48Hours, rt.minTemperature48Hours)
updateDevice(dv.minTemperature8Days, rt.minTemperature8Days)
updateDevice(dv.avgTemperature48Hours, rt.avgTemperature48Hours)
updateDevice(dv.avgTemperature8Days, rt.avgTemperature8Days)
if deviceExists(dv.rainToday) and dv.rainToday.lastUpdate.dDate < ( endOfToday - DAY_SECONDS ) then
updateDevice(dv.rainToday, rt.todaymm)
elseif deviceExists(dv.rainToday) then
updateDevice(dv.rainToday, math.max(rt.todaymm, tonumber(dv.rainToday.sValue)))
end
if deviceExists(dv.maxTemperatureToday) and dv.maxTemperatureToday.lastUpdate.dDate < ( endOfToday - DAY_SECONDS ) then
updateDevice(dv.maxTemperatureToday, rt.maxTemperatureToday)
elseif deviceExists(dv.maxTemperatureToday) then
updateDevice(dv.maxTemperatureToday, math.max(rt.maxTemperatureToday, dv.maxTemperatureToday.temperature))
end
if deviceExists(dv.weatherText) then updateTextDevice(rt) end
end
-- main code
if item.isHTTPResponse then
if item.ok and item.isJSON then
local rt = item.json
createResultTable(rt)
updateDevices(rt)
else
dz.log('There was a problem with the response from ' .. scriptVar, dz.LOG_ERROR)
dz.log(item, dz.LOG_DEBUG)
end
else -- get the data from openweatherMap
dz.openURL({
url = openWeatherURL ..
'&lat=' .. dz.settings.location.latitude ..
'&lon=' .. dz.settings.location.longitude ..
'&appid=' .. openWeatherAPIKey,
callback = scriptVar, -- see httpResponses above.
})
end
end
}
@ Waaren,
Thx for reporting.Jan Jansen wrote: ↑Monday 18 January 2021 11:07 there is a problem with the average temperature over the next 48 hours, This sensor continues to display the value infinity
Code: Select all
t.avgTemperature48Hours = dz.utils.round((avgHelper / #t),1)
Code: Select all
t.avgTemperature48Hours = dz.utils.round((avgHelper / #t.hourly),1)
What is OneCall ?
Are you using the dzVents script that I posted here or the OWM hardware module @kiddigital created?
Can you please post all the loglines produced by one executing cycle of the script and the result of the call you make to the API yourself?
You left out the important part of the log (the line with the actual URL used).
Code: Select all
2021-03-16 12:12:00.129 Status: dzVents: Info: ==> OWM_MétéoForecast: ------ Start internal script: DV_MeteoForecast:, trigger: "at *:12"
2021-03-16 12:12:00.130 Status: dzVents: Debug: ==> OWM_MétéoForecast: OpenURL: url = https://api.openweathermap.org/data/2.5/onecall?&units=metric&lat=0&lon=0&appid=365a47xxxxxxxxxxxxxx43864e
2021-03-16 12:12:00.130 Status: dzVents: Debug: ==> OWM_MétéoForecast: OpenURL: method = GET
2021-03-16 12:12:00.130 Status: dzVents: Debug: ==> OWM_MétéoForecast: OpenURL: post data = nil
2021-03-16 12:12:00.131 Status: dzVents: Debug: ==> OWM_MétéoForecast: OpenURL: headers = nil
2021-03-16 12:12:00.131 Status: dzVents: Debug: ==> OWM_MétéoForecast: OpenURL: callback = ==> OWM_MétéoForecast
2021-03-16 12:12:00.131 Status: dzVents: Info: ==> OWM_MétéoForecast: ------ Finished DV_MeteoForecast
2021-03-16 12:12:00.131 Status: EventSystem: Script event triggered: /usr/local/domoticz/dzVents/runtime/dzVents.lua
2021-03-16 12:12:00.571 Status: dzVents: Info: Handling httpResponse-events for: "==> OWM_MétéoForecast"
2021-03-16 12:12:00.571 Status: dzVents: Info: ==> OWM_MétéoForecast: ------ Start internal script: DV_MeteoForecast: HTTPResponse: "==> OWM_MétéoForecast"
2021-03-16 12:12:00.616 Status: dzVents: Debug: ==> OWM_MétéoForecast: Processing device-adapter for Current rain: Custom sensor device adapter
Users browsing this forum: No registered users and 1 guest