Multi-day weather forecast to control device  [Solved]

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

Moderator: leecollings

Atis
Posts: 37
Joined: Monday 30 March 2020 7:30
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Multi-day weather forecast to control device

Post by Atis »

Hello,

I would like Multi-day weather forecast to control device. How can I set up that I can Using the forecast to control domoticz device?
I see 8 day forecast in domoticz, but I can not use this information to control the sprinkler or something else.
i added another weather forecast but in domoticz it only shows the current value.

I need temperature and rain forecast. Possibly if the amount of precipitation can be solved.

Thank you,
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Atis wrote: Sunday 19 July 2020 8:57 I would like Multi-day weather forecast to control device. How can I set up that I can Using the forecast to control domoticz device?
This information can be collected from openweathermap.org if you have a (free) API key and can be processed using a dzVents script.

What would you like to see in domoticz based on the data from openwathermap and on what devicetype(s)?
How would the control need to look like if you know the expected average-, min- and max temperatures and the expected amount of rain in mm per day for the next 7 days?
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Atis
Posts: 37
Joined: Monday 30 March 2020 7:30
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Multi-day weather forecast to control device

Post by Atis »

waaren wrote: Sunday 19 July 2020 12:55
Atis wrote: Sunday 19 July 2020 8:57 I would like Multi-day weather forecast to control device. How can I set up that I can Using the forecast to control domoticz device?
This information can be collected from openweathermap.org if you have a (free) API key and can be processed using a dzVents script.

What would you like to see in domoticz based on the data from openwathermap and on what devicetype(s)?
How would the control need to look like if you know the expected average-, min- and max temperatures and the expected amount of rain in mm per day for the next 7 days?
Hello Waaren,
I think 5-7 days max. celsius forecast divided into days. This info in temperatures sheet.
The rain data in mm for the next 5-7 days in weather sheet.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Atis wrote: Monday 20 July 2020 8:10 I think 5-7 days max. celsius forecast divided into days. This info in temperatures sheet.
The rain data in mm for the next 5-7 days in weather sheet.
Could look like below. rain forecast data is in custom sensors (in the utility tab)

When not yet familiar with dzVents please start with reading Get started Before implementing (~ 5 minutes). Special attention please for "In Domoticz go to Setup > Settings > Other and in the section EventSystem make sure the checkbox 'dzVents enabled' is checked. Also make sure that in the Security section in the settings you allow 127.0.0.1 to not need a password. dzVents uses that port to send certain commands to Domoticz. Finally make sure you have set your current location in Setup > Settings > System > Location, otherwise there is no way to determine nighttime/daytime state."

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

]]--

local scriptVar = 'openWeatherMap'

return
{
    on = {
        timer =
        {
            'at 05:17' -- Once a day should be enough
        },

        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('Rain today')         -- 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 weatherText = dz.devices('WeatherForecast')    -- optional text Sensor

        local currentTemperature = dz.devices('Current Temperature') -- Optional virtual Temperature sensor
        local temperature48Hours = dz.devices('Max Temperature next 48 hours') -- Optional virtual Temperature sensor
        local temperature8Days = dz.devices('Max 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 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 get8DaysMaxTemperature(t)
            local maxTemperature = -100
            for _, record in ipairs(t) do
                if record.temp.max > maxTemperature then maxTemperature = record.temp.max end
             end
            return dz.utils.round(maxTemperature,1)
        end

        local function get48HoursMaxTemperature(t)
            local maxTemperature = -100
            for _, record in ipairs(t) do
                if record.temp > maxTemperature then maxTemperature = record.temp end
             end
            return dz.utils.round(maxTemperature,1)
        end

        local function get48HoursRain(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
                    for id, mm in pairs(record.rain) do
                        dz.log(id)
                        totalmm = totalmm + mm
                    end
                end
            end
            return totalmm
        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 = get48HoursRain(rt.hourly)
            rt.rain8Days = get8DaysRain(rt.daily)

            rt.temperature48Hours = get48HoursMaxTemperature(rt.hourly)
            rt.temperature8Days = get8DaysMaxTemperature(rt.daily)
        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.temperature48Hours .. ' °C' .. '\n'
            text = text .. '8 days:    ' .. t.rain8Days .. ' mm, ' .. t.temperature8Days .. ' °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 updateDevices(rt)
            if deviceExists(currentRain) then currentRain.updateCustomSensor(rt.currentRain) end
            if deviceExists(rain48Hours) then rain48Hours.updateCustomSensor(rt.rain48Hours) end
            if deviceExists(rain8Days) then rain8Days.updateCustomSensor(rt.rain8Days) end

            if deviceExists(currentTemperature) then currentTemperature.updateTemperature(rt.current.temp) end
            if deviceExists(temperature48Hours) then temperature48Hours.updateTemperature(rt.temperature48Hours) end
            if deviceExists(temperature8Days) then temperature8Days.updateTemperature(rt.temperature8Days) 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
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Atis
Posts: 37
Joined: Monday 30 March 2020 7:30
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Multi-day weather forecast to control device

Post by Atis »

waaren wrote: Monday 20 July 2020 13:27
Atis wrote: Monday 20 July 2020 8:10 I think 5-7 days max. celsius forecast divided into days. This info in temperatures sheet.
The rain data in mm for the next 5-7 days in weather sheet.
Could look like below. rain forecast data is in custom sensors (in the utility tab)

Hello Waaren, Thank you your script. Script is working but I have the problem with data:

Temperature: The script said 48 h and next 8 days max temp. 24.7 and 24.6. But I see the openwethermap page the teperature in next 8 day max 28-30Celsius.

Rain forecast: The domoticz said no rain today and the next 48 hours. But the wether site said light rain tomorrow 0,34 mm/h. 8 days rain forecast data not right. Can you help me?
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Atis wrote: Tuesday 21 July 2020 9:22 Script is working but I have the problem with data:

Temperature: The script said 48 h and next 8 days max temp. 24.7 and 24.6. But I see the openwethermap page the teperature in next 8 day max 28-30Celsius.

Rain forecast: The domoticz said no rain today and the next 48 hours. But the wether site said light rain tomorrow 0,34 mm/h. 8 days rain forecast data not right. Can you help me?
The only things that can cause this are different lat / lon settings in domoticz compared to what you entered on the site or a problem at the openweathermaps.org site's data. The script will only process the data it gets from the site by summing, determining the max. There is no other interpretation in the script.

The figures I get using this API, match with what I see on the openweathermap for my city.
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Atis
Posts: 37
Joined: Monday 30 March 2020 7:30
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Multi-day weather forecast to control device

Post by Atis »

waaren wrote: Tuesday 21 July 2020 12:06
Atis wrote: Tuesday 21 July 2020 9:22 Script is working but I have the problem with data:

Temperature: The script said 48 h and next 8 days max temp. 24.7 and 24.6. But I see the openwethermap page the teperature in next 8 day max 28-30Celsius.

Rain forecast: The domoticz said no rain today and the next 48 hours. But the wether site said light rain tomorrow 0,34 mm/h. 8 days rain forecast data not right. Can you help me?
The only things that can cause this are different lat / lon settings in domoticz compared to what you entered on the site or a problem at the openweathermaps.org site's data. The script will only process the data it gets from the site by summing, determining the max. There is no other interpretation in the script.

The figures I get using this API, match with what I see on the openweathermap for my city.
Which api using from weather api?


I have this:
Weather Current weather and forecast Free plan Hourly forecast: unavailable
Daily forecast: unavailable
Calls per minute: 60
3 hour forecast: 5 days

I see in json that correct rain and temp, but in domoticz data not good. I dont understand.
Last edited by Atis on Tuesday 21 July 2020 20:09, edited 1 time in total.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Atis wrote: Tuesday 21 July 2020 19:39 Which api using from weather api?
The one used in the script

Code: Select all

https://api.openweathermap.org/data/2.5/onecall?&units=metric&lat=<your lat>&lon=<your lon>appid=<your appid>
and compared with
owm.png
owm.png (206.71 KiB) Viewed 3326 times
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Atis
Posts: 37
Joined: Monday 30 March 2020 7:30
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Multi-day weather forecast to control device

Post by Atis »

Tomorrow json:

Code: Select all

1	
dt	1595412000
sunrise	1595387383
sunset	1595442632
temp	
day	23.03
min	20.23
max	28.27
night	23.58
eve	28.26
morn	22.22
feels_like	
day	24.32
night	23
eve	26.67
morn	22.86
pressure	1020
humidity	65
dew_point	16.22
wind_speed	1.04
wind_deg	339
weather	
0	
id	501
main	"Rain"
description	"moderate rain"
icon	"10d"
clouds	100
pop	0.92
rain	8.95
uvi	8.11
Domoticz said no rain and 26.1 max temp. In setup long and latitude correct.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Atis wrote: Tuesday 21 July 2020 20:43 rain 8.95
uvi 8.11

Domoticz said no rain and 26.1 max temp. In setup long and latitude correct.
Can you please share your lat /lon (use PM ) to help me debug ?
I guessed Budapest and the data from openweathermap GUI matches the API exactly when grabbed at the same time. Maybe the script execution frequency should go to once per hour if you want it to be more accurate for the next couple of hours ?

What devices are you looking at and have you executed the script just before comparing it with the call from your GUI ?

This is what I see and that looks about right
openweather.png
openweather.png (69.23 KiB) Viewed 3310 times
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Jan Jansen
Posts: 229
Joined: Wednesday 30 April 2014 20:27
Target OS: Raspberry Pi / ODroid
Domoticz version: Stable
Location: The Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by Jan Jansen »

@ waaren,

Thanks for sharing your nice script! I want to add the minimum temperatures but I get an error that I can't resolve myself.

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

]]--

local scriptVar = 'openWeatherMap'

return
{
    on = {
        timer =
        {
            'at 12:35' -- Once a day should be enough
        },

        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('Rain today')         -- 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 weatherText = dz.devices('WeatherForecast')    -- optional text Sensor

        local currentTemperature = dz.devices('Current Temperature') -- Optional virtual Temperature sensor
        local temperaturemax48Hours = dz.devices('Max Temperature next 48 hours') -- Optional virtual Temperature sensor
        local temperaturemin48Hours = dz.devices('Min Temperature next 48 hours') -- Optional virtual Temperature sensor
        local temperaturemax8Days = dz.devices('Max Temperature next 8 days') -- Optional virtual Temperature sensor
	 	local temperaturemin8Days = dz.devices('Min 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 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 get8DaysMaxTemperature(t)
            local maxTemperature = -100
            for _, record in ipairs(t) do
                if record.temp.max > maxTemperature then maxTemperature = record.temp.max end
             end
            return dz.utils.round(maxTemperature,1)
        end
        
        local function get8DaysMinTemperature(t)
            local minTemperature = -100
            for _, record in ipairs(t) do
                if record.temp.min < minTemperature then maxTemperature = record.temp.min end
             end
            return dz.utils.round(minTemperature,1)
        end

        local function get48HoursMaxTemperature(t)
            local maxTemperature = -100
            for _, record in ipairs(t) do
                if record.temperature.max > maxTemperature then maxTemperature = record.temperature.max end
             end
            return dz.utils.round(maxTemperature,1)
        end
        
        local function get48HoursMinTemperature(t)
            local minTemperature = -100
            for _, record in ipairs(t) do
                if record.temperature.min < minTemperature then minTemperature = record.temperature.min end
             end
            return dz.utils.round(minTemperature,1)
        end

        local function get48HoursRain(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
                    for id, mm in pairs(record.rain) do
                        dz.log(id)
                        totalmm = totalmm + mm
                    end
                end
            end
            return totalmm
        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 = get48HoursRain(rt.hourly)
            rt.rain8Days = get8DaysRain(rt.daily)

            rt.temperaturemax48Hours = get48HoursMaxTemperature(rt.hourly)
            rt.temperaturemin48Hours = get48HoursMinTemperature(rt.hourly)
            rt.temperaturemax8Days = get8DaysMaxTemperature(rt.daily)
            rt.temperaturemin8Days = get8DaysMinTemperature(rt.daily)
        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.temperature48Hours .. ' °C' .. '\n'
            text = text .. '8 days:    ' .. t.rain8Days .. ' mm, ' .. t.temperature8Days .. ' °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 updateDevices(rt)
            if deviceExists(currentRain) then currentRain.updateCustomSensor(rt.currentRain) end
            if deviceExists(rain48Hours) then rain48Hours.updateCustomSensor(rt.rain48Hours) end
            if deviceExists(rain8Days) then rain8Days.updateCustomSensor(rt.rain8Days) end

            if deviceExists(currentTemperature) then currentTemperature.updateTemperature(rt.current.temp) end
            if deviceExists(temperature48Hours) then temperature48Hours.updateTemperature(rt.temperaturemax48Hours) end
            if deviceExists(temperature48Hours) then temperature48Hours.updateTemperature(rt.temperature48minHours) end
            if deviceExists(temperature8Days) then temperature8Days.updateTemperature(rt.temperaturemax8Days) end
            if deviceExists(temperature8Days) then temperature8Days.updateTemperature(rt.temperaturemin8Days) 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
}

Code: Select all

 2020-07-22 12:35:00.617 Status: dzVents: Info: openWeatherMap: ------ Start internal script: Script #1:, trigger: "at 12:35"
2020-07-22 12:35:00.656 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain today: Custom sensor device adapter
2020-07-22 12:35:00.659 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain 48 hours: Custom sensor device adapter
2020-07-22 12:35:00.662 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain 8 days: Custom sensor device adapter
2020-07-22 12:35:00.665 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for WeatherForecast: Text device
2020-07-22 12:35:00.668 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Current Temperature: Temperature device adapter
2020-07-22 12:35:00.670 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Max Temperature next 48 hours: Temperature device adapter
2020-07-22 12:35:00.673 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Min Temperature next 48 hours: Temperature device adapter
2020-07-22 12:35:00.675 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Max Temperature next 8 days: Temperature device adapter
2020-07-22 12:35:00.677 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Min Temperature next 8 days: Temperature device adapter
2020-07-22 12:35:00.678 Status: dzVents: Debug: openWeatherMap: OpenURL: url = https://api.openweathermap.org/data/2.5/onecall?&units=metric&lat=51.8556&lon=5.8417&appid=1850f4e69177e9bd9f219ddbd525ab29
2020-07-22 12:35:00.678 Status: dzVents: Debug: openWeatherMap: OpenURL: method = GET
2020-07-22 12:35:00.678 Status: dzVents: Debug: openWeatherMap: OpenURL: post data = nil
2020-07-22 12:35:00.678 Status: dzVents: Debug: openWeatherMap: OpenURL: headers = nil
2020-07-22 12:35:00.678 Status: dzVents: Debug: openWeatherMap: OpenURL: callback = openWeatherMap
2020-07-22 12:35:00.679 Status: dzVents: Info: openWeatherMap: ------ Finished Script #1
2020-07-22 12:35:00.680 Status: EventSystem: Script event triggered: /home/pi/domoticz/dzVents/runtime/dzVents.lua
2020-07-22 12:35:03.328 Status: dzVents: Info: Handling httpResponse-events for: "openWeatherMap"
2020-07-22 12:35:03.328 Status: dzVents: Info: openWeatherMap: ------ Start internal script: Script #1: HTTPResponse: "openWeatherMap"
2020-07-22 12:35:03.441 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain today: Custom sensor device adapter
2020-07-22 12:35:03.444 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain 48 hours: Custom sensor device adapter
2020-07-22 12:35:03.446 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain 8 days: Custom sensor device adapter
2020-07-22 12:35:03.448 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for WeatherForecast: Text device
2020-07-22 12:35:03.451 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Current Temperature: Temperature device adapter
2020-07-22 12:35:03.453 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Max Temperature next 48 hours: Temperature device adapter
2020-07-22 12:35:03.456 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Min Temperature next 48 hours: Temperature device adapter
2020-07-22 12:35:03.458 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Max Temperature next 8 days: Temperature device adapter
2020-07-22 12:35:03.461 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Min Temperature next 8 days: Temperature device adapter
2020-07-22 12:35:03.461 Status: dzVents: Info: openWeatherMap: 1h
2020-07-22 12:35:03.462 Status: dzVents: Info: openWeatherMap: 1h
2020-07-22 12:35:03.462 Status: dzVents: Info: openWeatherMap: ------ Finished Script #1
2020-07-22 12:35:03.462 Status: dzVents: Info: openWeatherMap: ------ Start internal script: Weersvoorspelling: HTTPResponse: "openWeatherMap"
2020-07-22 12:35:03.539 Status: dzVents: Info: openWeatherMap: 1h
2020-07-22 12:35:03.539 Status: dzVents: Info: openWeatherMap: 1h
2020-07-22 12:35:03.541 Status: dzVents: Info: openWeatherMap: ------ Finished Weersvoorspelling
2020-07-22 12:35:03.543 Status: EventSystem: Script event triggered: /home/pi/domoticz/dzVents/runtime/dzVents.lua
2020-07-22 12:35:03.462 Error: dzVents: Error: (3.0.2) openWeatherMap: An error occurred when calling event handler Script #1
2020-07-22 12:35:03.462 Error: dzVents: Error: (3.0.2) openWeatherMap: ...domoticz/scripts/dzVents/generated_scripts/Script #1.lua:88: attempt to index a nil value (field 'temperature')
Hopefully you know a solution. Thanks in advance!

regards
Jan
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Jan Jansen wrote: Wednesday 22 July 2020 13:12 Thanks for sharing your nice script! I want to add the minimum temperatures but I get an error that I can't resolve myself.
Updated script with option to add virtual sensors for minimum temperature 48 hours and minimum temperature temp 8 days.

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

        history
        20200720 Start coding - shared on forum
        20200722 Added minimum temperature devices

]]--

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('Rain today')         -- 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 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
       -- ******** No changes required below this line

        local openWeatherURL = 'https://api.openweathermap.org/data/2.5/onecall?&units=metric'

        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 get8DaysMinMaxTemperature(t)
            local maxTemperature = -100
            local minTemperature = 100
            for _, record in ipairs(t) do
                if record.temp.max > maxTemperature then maxTemperature = record.temp.max end
                if record.temp.min < minTemperature then minTemperature = record.temp.min end
             end
            return dz.utils.round(maxTemperature,1), dz.utils.round(minTemperature,1)
        end

        local function get48HoursMinMaxTemperature(t)
            local maxTemperature = -100
            local minTemperature = 100
            for _, record in ipairs(t) do
                if record.temp > maxTemperature then maxTemperature = record.temp end
                if record.temp < minTemperature then minTemperature = record.temp end
             end
            return dz.utils.round(maxTemperature,1),dz.utils.round(minTemperature,1)
        end

        local function get48HoursRain(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
                    for id, mm in pairs(record.rain) do
                        totalmm = totalmm + mm
                    end
                end
            end
            return totalmm
        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 = get48HoursRain(rt.hourly)
            rt.rain8Days = get8DaysRain(rt.daily)

            rt.maxTemperature48Hours, rt.minTemperature48Hours  = get48HoursMinMaxTemperature(rt.hourly)
            rt.maxTemperature8Days, rt.minTemperature8Days = get8DaysMinMaxTemperature(rt.daily)
        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 updateDevices(rt)
            if deviceExists(currentRain) then currentRain.updateCustomSensor(rt.currentRain) end
            if deviceExists(rain48Hours) then rain48Hours.updateCustomSensor(rt.rain48Hours) end
            if deviceExists(rain8Days) then rain8Days.updateCustomSensor(rt.rain8Days) end

            if deviceExists(currentTemperature) then currentTemperature.updateTemperature(rt.current.temp) end
            if deviceExists(maxTemperature48Hours) then maxTemperature48Hours.updateTemperature(rt.maxTemperature48Hours) end
            if deviceExists(maxTemperature8Days) then maxTemperature8Days.updateTemperature(rt.maxTemperature8Days) end
            if deviceExists(minTemperature48Hours) then minTemperature48Hours.updateTemperature(rt.minTemperature48Hours) end
            if deviceExists(minTemperature8Days) then minTemperature8Days.updateTemperature(rt.minTemperature8Days) 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
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Updated version with optional average temperature sensors. Also include a warning in the comments

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)
Also explained in the wiki

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

        history
        20200720 Start coding - shared on forum
        20200722 Added average and minimum temperature devices

]]--

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('Rain today')         -- 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 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 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 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
            dz.log(avgTemperature)
            dz.log(avgHelper)
            dz.log(#t)

            avgTemperature = avgHelper / #t
            return dz.utils.round(maxTemperature,1), dz.utils.round(minTemperature,1), dz.utils.round(avgTemperature,1)
        end

        local function get48HoursTemperatures(t)
            local maxTemperature = -100
            local minTemperature = 100
            local avgHelper = 0

            for _, record in ipairs(t) do
                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)
        end

        local function get48HoursRain(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
                    for id, mm in pairs(record.rain) do
                        totalmm = totalmm + mm
                    end
                end
            end
            return totalmm
        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 = get48HoursRain(rt.hourly)
            rt.rain8Days = get8DaysRain(rt.daily)

            rt.maxTemperature48Hours, rt.minTemperature48Hours, rt.avgTemperature48Hours  = get48HoursTemperatures(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 updateDevices(rt)
            if deviceExists(currentRain) then currentRain.updateCustomSensor(rt.currentRain) end
            if deviceExists(rain48Hours) then rain48Hours.updateCustomSensor(rt.rain48Hours) end
            if deviceExists(rain8Days) then rain8Days.updateCustomSensor(rt.rain8Days) end

            if deviceExists(currentTemperature) then currentTemperature.updateTemperature(rt.current.temp) end
            if deviceExists(maxTemperature48Hours) then maxTemperature48Hours.updateTemperature(rt.maxTemperature48Hours) end
            if deviceExists(maxTemperature8Days) then maxTemperature8Days.updateTemperature(rt.maxTemperature8Days) end
            if deviceExists(minTemperature48Hours) then minTemperature48Hours.updateTemperature(rt.minTemperature48Hours) end
            if deviceExists(minTemperature8Days) then minTemperature8Days.updateTemperature(rt.minTemperature8Days) end
            if deviceExists(avgTemperature48Hours) then avgTemperature48Hours.updateTemperature(rt.avgTemperature48Hours) end
            if deviceExists(avgTemperature8Days) then avgTemperature8Days.updateTemperature(rt.avgTemperature8Days) 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
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Emerson
Posts: 6
Joined: Monday 27 October 2014 12:19
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: South East England
Contact:

Re: Multi-day weather forecast to control device

Post by Emerson »

@ waaren,

Thanks for sharing your script I have setup the requirements in domoticz: user variable, long, lat etc and the script runs, if i don't create the any virtual devices the script completes without errors;

Code: Select all

2020-07-27 14:24:00.307 Status: dzVents: Info: openWeatherMap: ------ Start external script: weather.lua:, trigger: at *:24
2020-07-27 14:24:00.309 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain today: Custom sensor device adapter
2020-07-27 14:24:00.309 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Rain 48 hours
2020-07-27 14:24:00.310 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Rain 8 days
2020-07-27 14:24:00.310 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: WeatherForecast
2020-07-27 14:24:00.310 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Current Temperature
2020-07-27 14:24:00.310 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Max Temperature next 48 hours
2020-07-27 14:24:00.310 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Max Temperature next 8 days
2020-07-27 14:24:00.311 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Min Temperature next 48 hours
2020-07-27 14:24:00.311 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Min Temperature next 8 days
2020-07-27 14:24:00.311 Status: dzVents: Debug: openWeatherMap: OpenURL: url = https://api.openweathermap.org/data/2.5/onecall?&units=metric&lat=51.62143342246289&lon=-0.7175364494323&appid=xxxxxxxxxxx
2020-07-27 14:24:00.311 Status: dzVents: Debug: openWeatherMap: OpenURL: method = GET
2020-07-27 14:24:00.311 Status: dzVents: Debug: openWeatherMap: OpenURL: post data = nil
2020-07-27 14:24:00.311 Status: dzVents: Debug: openWeatherMap: OpenURL: headers = nil
2020-07-27 14:24:00.311 Status: dzVents: Debug: openWeatherMap: OpenURL: callback = openWeatherMap
2020-07-27 14:24:00.311 Status: dzVents: Info: openWeatherMap: ------ Finished weather.lua
if i add a virtual device (it doesn't matter which one) in the case of the below it is a virtual custom device called "Rain today" the script errors;

Code: Select all

2020-07-27 14:24:01.143 Status: dzVents: Info: openWeatherMap: ------ Start external script: weather.lua: HTTPResponse: "openWeatherMap"
2020-07-27 14:24:01.196 Status: dzVents: Debug: openWeatherMap: Processing device-adapter for Rain today: Custom sensor device adapter
2020-07-27 14:24:01.196 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Rain 48 hours
2020-07-27 14:24:01.196 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Rain 8 days
2020-07-27 14:24:01.197 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: WeatherForecast
2020-07-27 14:24:01.197 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Current Temperature
2020-07-27 14:24:01.197 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Max Temperature next 48 hours
2020-07-27 14:24:01.197 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Max Temperature next 8 days
2020-07-27 14:24:01.197 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Min Temperature next 48 hours
2020-07-27 14:24:01.198 Status: dzVents: Error (2.4.19): openWeatherMap: There is no device with that name or id: Min Temperature next 8 days
2020-07-27 14:24:01.198 Status: dzVents: Error (2.4.19): openWeatherMap: An error occured when calling event handler weather
2020-07-27 14:24:01.198 Status: dzVents: Error (2.4.19): openWeatherMap: /home/pi/domoticz/scripts/dzVents/scripts/weather.lua:137: attempt to call field 'deviceExists' (a nil value)
2020-07-27 14:24:01.198 Status: dzVents: Info: openWeatherMap: ------ Finished weather.lua
I am at a loss as to the problem
Emerson
Raspberry Pi + Domoticz + RFXtrx, LightwaveRF (dimmers, sockets, PIR's) Owl CM113, Oregon Scientific Temp / Humidity Sensors, Huacam CCTV Cameras, MySensors Lux and CO, ESP8266 NodeMCU temperature sensors
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

Emerson wrote: Monday 27 July 2020 15:45 2020-07-27 14:24:01.198 Status: dzVents: Error (2.4.19): openWeatherMap: /home/pi/domoticz/scripts/dzVents/scripts/weather.lua:137: attempt to call field 'deviceExists' (a nil value)
The function deviceExists is not available in your version of dzVents. it was introduced in dzVents 2.4.28
You can find the dzVents - domoticz version relation here
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Emerson
Posts: 6
Joined: Monday 27 October 2014 12:19
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: South East England
Contact:

Re: Multi-day weather forecast to control device

Post by Emerson »

@ waaren,

Thanks for the quick reply, that solved that mystery, better update to latest stable them

Emerson
Raspberry Pi + Domoticz + RFXtrx, LightwaveRF (dimmers, sockets, PIR's) Owl CM113, Oregon Scientific Temp / Humidity Sensors, Huacam CCTV Cameras, MySensors Lux and CO, ESP8266 NodeMCU temperature sensors
spider85
Posts: 5
Joined: Wednesday 04 February 2015 16:45
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Multi-day weather forecast to control device

Post by spider85 »

waaren wrote: Wednesday 22 July 2020 22:01 Updated version with optional average temperature sensors. Also include a warning in the comments

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)
Also explained in the wiki

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

        history
        20200720 Start coding - shared on forum
        20200722 Added average and minimum temperature devices

]]--

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('Rain today')         -- 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 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 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 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
            dz.log(avgTemperature)
            dz.log(avgHelper)
            dz.log(#t)

            avgTemperature = avgHelper / #t
            return dz.utils.round(maxTemperature,1), dz.utils.round(minTemperature,1), dz.utils.round(avgTemperature,1)
        end

        local function get48HoursTemperatures(t)
            local maxTemperature = -100
            local minTemperature = 100
            local avgHelper = 0

            for _, record in ipairs(t) do
                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)
        end

        local function get48HoursRain(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
                    for id, mm in pairs(record.rain) do
                        totalmm = totalmm + mm
                    end
                end
            end
            return totalmm
        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 = get48HoursRain(rt.hourly)
            rt.rain8Days = get8DaysRain(rt.daily)

            rt.maxTemperature48Hours, rt.minTemperature48Hours, rt.avgTemperature48Hours  = get48HoursTemperatures(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 updateDevices(rt)
            if deviceExists(currentRain) then currentRain.updateCustomSensor(rt.currentRain) end
            if deviceExists(rain48Hours) then rain48Hours.updateCustomSensor(rt.rain48Hours) end
            if deviceExists(rain8Days) then rain8Days.updateCustomSensor(rt.rain8Days) end

            if deviceExists(currentTemperature) then currentTemperature.updateTemperature(rt.current.temp) end
            if deviceExists(maxTemperature48Hours) then maxTemperature48Hours.updateTemperature(rt.maxTemperature48Hours) end
            if deviceExists(maxTemperature8Days) then maxTemperature8Days.updateTemperature(rt.maxTemperature8Days) end
            if deviceExists(minTemperature48Hours) then minTemperature48Hours.updateTemperature(rt.minTemperature48Hours) end
            if deviceExists(minTemperature8Days) then minTemperature8Days.updateTemperature(rt.minTemperature8Days) end
            if deviceExists(avgTemperature48Hours) then avgTemperature48Hours.updateTemperature(rt.avgTemperature48Hours) end
            if deviceExists(avgTemperature8Days) then avgTemperature8Days.updateTemperature(rt.avgTemperature8Days) 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
}
Hi Waaren,

How and where do i need to put the APi and lat long?
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by waaren »

spider85 wrote: Thursday 06 August 2020 14:45 How and where do i need to put the APi and lat long?
the API key goes here
uservariable.png
uservariable.png (68.04 KiB) Viewed 3000 times


and the lat long goes here
Location.png
Location.png (49.53 KiB) Viewed 3000 times
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
kiddigital
Posts: 435
Joined: Thursday 10 August 2017 6:52
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Multi-day weather forecast to control device

Post by kiddigital »

There is a Pull Request on Github (https://github.com/domoticz/domoticz/pull/4284) for a big update of the OpenWeatherMap module in Domoticz which also includes the 8 day weather forecast as separate sensors including min and max temperature, probability of precipitation (rain, drizzle, snow, etc), etc.

If/once this Pull Request is merged into the beta, it can be tested to see if it has enough possibilities to control things like garden sprinklers, etc.
One RPi with Domoticz, RFX433e, aeon labs z-wave plus stick GEN5, ha-bridge 5.4.0 for Alexa, Philips Hue Bridge, Pimoroni Automation Hat
One RPi with Pi foundation standard touch screen to display Dashticz
spider85
Posts: 5
Joined: Wednesday 04 February 2015 16:45
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Multi-day weather forecast to control device

Post by spider85 »

waaren wrote: Thursday 06 August 2020 15:10
spider85 wrote: Thursday 06 August 2020 14:45 How and where do i need to put the APi and lat long?
the API key goes here
uservariable.png



and the lat long goes here
Location.png
Tnx, got it working, is it possible to get the max temp for 24h (for the next day)?
If it is possible i could make a timing thing for my garden sprinklers.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests