Simple weather forecast for outside activities (Nederland)

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

Moderator: leecollings

Post Reply
HvdW
Posts: 663
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Simple weather forecast for outside activities (Nederland)

Post by HvdW »

I like biking, but I am a nice weather biker.
Due to time constraints I must plan in advance.
So I suggested DeepSeek to write me a script with a 10 day forecast.
To prepare:
- get yourself a key for the API at meteoserver.nl
- Make a dummy device type TEXT and name it 'Er op uit'
- change the script according to where you live (my_home_town) and replace the abcdef1234 with you API key
That's all.

Code: Select all

--[[
ErOpUit Weather Display Script
Fetches weather forecast from Meteoserver.nl API and displays in Domoticz text sensor

API Information:
- Source: Meteoserver.nl (https://www.meteoserver.nl)
- Free plan: 500 calls per month
- API documentation: https://www.meteoserver.nl/API.html

Weather data fields explanation:
-- dag → forecast date (dd-mm-yyyy)
-- avg_temp → average temperature (°C)
-- min_temp → minimum temperature (°C)
-- max_temp → maximum temperature (°C)
-- windr → wind direction in degrees (0 = North, 90 = East, 180 = South, 270 = West)
-- windrltr → wind direction in letters (N, E, S, W)
-- winds → wind speed (Beaufort scale)
-- windb → wind force (Beaufort, rounded)
-- windkmh → wind speed in kilometers per hour (km/h)
-- windknp → wind speed in knots (knots)
-- tot_neersl → total precipitation in millimeters (mm)
-- neersl_perc_dag → chance of precipitation during the day (%)
-- tot_zond → total sunshine duration in minutes
-- zond_perc_dag → percentage of the day with sunshine (%)
-- sup → sunrise (hour:minute)
-- sunder → sunset (hour:minute)
-- toestand → general weather condition (e.g., rain, cloudy, sunny)

Display format for each day:
DD-MM 🌫️ ☀️ 🌦️ 😊 10-15-20°C
Where:
- DD-MM: Date (day-month)
- 🌫️: Wind indicator (🌫️=calm, 🍃=light, 🌬️=moderate, 💨=strong, 🌪️=stormy)
- ☀️: Cloud cover (☀️=sunny, 🌤️=mostly sunny, ⛅=partly cloudy, 🌥️=cloudy, ☁️=overcast)
- 🌦️: Precipitation (☀️=dry, 🌤️=light clouds, ⛅=cloudy, 🌦️=light rain, 🌧️=rain, ⛈️=heavy rain/thunder)
- 😊: Temperature feeling (🥶=freezing, 😰=cold, 🤔=chilly, 😊=pleasant, 😎=perfect, 🔥=warm, 🥵=hot)
- 10-15-20°C: Min-Avg-Max temperatures

Script triggers: 07:45, 12:45, 18:45 (Meteoserver updates at 7:30, 12:30, 18:30)
]]--

return {
    active = true,
    on = {
        timer = { 'at 07:45', 'at 12:45', 'at 18:45', },  -- Meteoserver publishes at 7:30, 12:30 and 18:30
        httpResponses = { 'erOpUitCallback' }
    },
    logging = {
        level = domoticz.LOG_DEBUG,
        marker = 'ErOpUit',
    },
    
    execute = function(domoticz, item)
        if item.isTimer then
            local url = 'https://data.meteoserver.nl/api/dagverwachting.php?locatie=my_home_town&key=abcdef1234'
            domoticz.log('Start ophalen weerdata van: ' .. url, domoticz.LOG_INFO)
            domoticz.openURL({
                url = url,
                method = 'GET',
                callback = 'erOpUitCallback'
            })
            
        elseif item.isHTTPResponse then
            domoticz.log('HTTP callback ontvangen: ' .. item.callback, domoticz.LOG_INFO)
            domoticz.log('HTTP Status: ' .. tostring(item.statusCode), domoticz.LOG_INFO)

            if item.statusCode ~= 200 then
                domoticz.log('Fout bij ophalen weerdata: status ' .. tostring(item.statusCode), domoticz.LOG_ERROR)
                return
            end

            local success, data = pcall(domoticz.utils.fromJSON, item.data)
            if not success or not data then
                domoticz.log('Kon JSON niet parsen', domoticz.LOG_ERROR)
                return
            end

            -- Compacte logging van de data structuur
            domoticz.log('Data structuur - plaatsnaam: ' .. tostring(data.plaatsnaam and data.plaatsnaam[1] and data.plaatsnaam[1].plaats), domoticz.LOG_DEBUG)
            domoticz.log('Aantal dagen in data: ' .. tostring(data.data and #data.data), domoticz.LOG_DEBUG)

            if not data.data or type(data.data) ~= 'table' then
                domoticz.log('Ongeldige data structuur: data.data niet gevonden', domoticz.LOG_ERROR)
                return
            end

            local weatherData = data.data
            domoticz.log('Aantal dagen ontvangen: ' .. tostring(#weatherData), domoticz.LOG_INFO)

            -- Compacte logging per dag (3 items per regel)
            domoticz.log('Detail informatie per dag:', domoticz.LOG_DEBUG)
            for i, dayData in ipairs(weatherData) do
                if i >= 2 and i <= 10 then -- Alleen de relevante dagen loggen
                    local dag = dayData.dag or 'onbekend'
                    local max_temp = tonumber(dayData.max_temp or 0)
                    local rain = tonumber(dayData.tot_neersl or 0)
                    local zon = tonumber(dayData.zond_perc_dag or 0)
                    local wind = tonumber(dayData.winds or 0) -- windkracht (0-12)
                    
                    domoticz.log(string.format('Dag %d: %s - max: %d°C - regen: %dmm - zon: %d%% - windkracht: %d', 
                        i, dag, max_temp, rain, zon, wind), domoticz.LOG_DEBUG)
                end
            end

            local output = ''

            -- Wind-emoji mapping based on wind force (Beaufort scale 0-12)
            local windEmoji = {
                [1] = '🌫️',  -- 0-2 Beaufort - calm/light
                [2] = '🍃',  -- 3-4 Beaufort - gentle breeze
                [3] = '🌬️',  -- 5-6 Beaufort - moderate wind
                [4] = '💨',  -- 7-8 Beaufort - strong wind
                [5] = '🌪️'   -- 9+ Beaufort - stormy
            }

            -- Process days 2 to 10 (9-day forecast starting from tomorrow)
            for i = 2, 10 do
                if not weatherData[i] then
                    domoticz.log('Geen data voor dag ' .. i, domoticz.LOG_WARNING)
                    break
                end
                
                local datum = weatherData[i].dag:sub(1, 5) -- Extract "dd-mm" from "dd-mm-yyyy"
                
                local min_temp = tonumber(weatherData[i].min_temp or 0)
                local avg_temp = tonumber(weatherData[i].avg_temp or 0)
                local max_temp = tonumber(weatherData[i].max_temp or 0)
                local rain = tonumber(weatherData[i].tot_neersl or 0)
                local zon = tonumber(weatherData[i].zond_perc_dag or 0)
                local wind = tonumber(weatherData[i].winds or 0) -- wind force (Beaufort 0-12)

                -- Format temperatures as 2 digits
                local min_str = string.format("%02d", min_temp)
                local avg_str = string.format("%02d", avg_temp) 
                local max_str = string.format("%02d", max_temp)

                -- Determine wind emoji based on Beaufort scale
                local wind_emoji = windEmoji[1]  -- default calm
                if wind >= 9 then wind_emoji = windEmoji[5]
                elseif wind >= 7 then wind_emoji = windEmoji[4]
                elseif wind >= 5 then wind_emoji = windEmoji[3]
                elseif wind >= 3 then wind_emoji = windEmoji[2]
                end

                -- Cloud cover emoji (based on sunshine percentage)
                local wolk = '☀️' -- >80% sunshine
                if zon <= 20 then wolk = '☁️'      -- <20% sunshine - overcast
                elseif zon <= 40 then wolk = '🌥️' -- 20-40% sunshine - cloudy
                elseif zon <= 60 then wolk = '⛅' -- 40-60% sunshine - partly cloudy
                elseif zon <= 80 then wolk = '🌤️' -- 60-80% sunshine - mostly sunny
                end
                
                -- Precipitation emoji
                local regen_emoji = '☀️'      -- 0mm - sunny/dry
                if rain > 20 then regen_emoji = '⛈️'      -- >20mm - heavy rain/thunder
                elseif rain > 10 then regen_emoji = '🌧️'   -- 10-20mm - rain
                elseif rain > 5 then regen_emoji = '🌦️'    -- 5-10mm - light rain
                elseif rain > 2 then regen_emoji = '⛅'     -- 2-5mm - cloudy/showers
                elseif rain > 0.5 then regen_emoji = '🌤️'  -- 0.5-2mm - light clouds
                end

                -- Temperature feeling emoji (based on max temperature)
                local temp_emoji = '🥶' -- <10°C: freezing
                if max_temp >= 10 and max_temp <= 12 then temp_emoji = '😰' -- 10-12°C: cold
                elseif max_temp >= 13 and max_temp <= 15 then temp_emoji = '🤔' -- 13-15°C: chilly
                elseif max_temp >= 16 and max_temp <= 18 then temp_emoji = '😊' -- 16-18°C: pleasant
                elseif max_temp >= 19 and max_temp <= 22 then temp_emoji = '😎' -- 19-22°C: perfect
                elseif max_temp >= 23 and max_temp <= 26 then temp_emoji = '🔥' -- 23-26°C: warm
                elseif max_temp > 26 then temp_emoji = '🥵' -- >26°C: hot
                end
                  
                -- Build output line: date WIND clouds precipitation temperature_feeling min-avg-max°C
                output = output .. datum .. ' ' .. wind_emoji .. ' ' .. wolk .. ' ' .. regen_emoji .. ' ' .. temp_emoji .. ' ' .. min_str .. '-' .. avg_str .. '-' .. max_str .. '°C\n'
                
                domoticz.log(string.format('Dag %d: %s - windkracht:%d %s %s %s %s-%s-%s°C', 
                    i, datum, wind, wind_emoji, wolk, regen_emoji, min_str, avg_str, max_str), domoticz.LOG_INFO)
            end

            domoticz.log('Opgebouwde output: ' .. output, domoticz.LOG_INFO)

            local device = domoticz.devices('Er op uit')
            if device then
                device.updateText(output)
                domoticz.log('Device "Er op uit" bijgewerkt', domoticz.LOG_INFO)
            else
                domoticz.log('Device "Er op uit" niet gevonden!', domoticz.LOG_ERROR)
            end
        end
    end
}
signal-2025-09-22-222143.jpeg
signal-2025-09-22-222143.jpeg (58.71 KiB) Viewed 30 times
Bugs bug me.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest