It had the warning at a provincial level.
The new version (with approach at local level) can be found at https://www.atlasleefomgeving.nl/stookwijzer
It is updated 4 times a day at 4, 10, 16 and 22 o'clock.
Besides the current alert, with information on Air quality level and windspeed, it also gives a 6, 12 and 18 hour forecast warninglevel.
As far as I can see now always the first two as final and the last two as not final.
Here I show the approach with my modified DzVents script:
- Starts with calculating a boundery box around the latitude and longitude coordinates found in Domoticz settings.
- Gets the last known json information.
- Detects level, LKI, Windspeed for the first time. and calculates the hh:mm for next tree times (6, 12 and 18 hr later).
- Times are given in the code color for the level that is found for that time.
- Updates the alert level and adds the information in text.
- Optional send email (once) when level increased to code red.
You need to create an custom alert device and insert the IDX number.
I configured it to run 10 minutes after the given times. Here is the new t-StookAlert-RIVM script.
Code: Select all
-- 09-02-2025 Script by Jan Peppink, https://ict.peppink.nl
-- Modified from my earlier RIVM Stookalert script, because of changed URL with new approach
-- The stookalert is moved to https://www.atlasleefomgeving.nl/stookwijzer
-- It now gives a local advice for unfavorable weather conditions (wind) and poor air quality.
-- With a Stookalert, the RIVM calls on people not to burn wood.
-- This can prevent inconvenience for people in the area.
-- Results in advice_0, with 0=yellow, 1=orange, 2=red. and a forecast 6, 12 and 18 hours ahead.
-- I translate code yellow to green. With yellow they avoid green as a Clearly allowed. :-)
-- Green = No alert, Orange = Warning, Red = RIVM Stookalert.
-- Setting alertLevel by constant: domoticz.ALERTLEVEL_GREY, ALERTLEVEL_GREEN, ALERTLEVEL_YELLOW, ALERTLEVEL_ORANGE, ALERTLEVEL_RED
-- Getting alertLevel by number: 0=gray, 1=green, 2=yellow, 3=orange, 4=red
--- Your settings ----------------------------------------------------------------
-- First set the used device index numbers and variables you might want to change.
local SA_alert_idx = 99999 -- Set to the idx of the custom Alert sensor you have to create for this script
local SA_emailTo = '' -- Optional: Set to your E-mail adres to sent Alert notification once.
----------------------------------------------------------------------------------
return {
on = {
timer = {
--'every 2 minutes', --Only for testing
'at 4:10',
'at 10:10',
'at 16:10',
'at 22:10',
},
httpResponses = {
'triggerSA' -- must match with the callback passed to the openURL command
},
},
logging = {
-- Level can be domoticz.LOG_INFO, domoticz.LOG_STATUS, domoticz.LOG_ERROR or domoticz.LOG_DEBUG
level = domoticz.LOG_STATUS,
--level = domoticz.LOG_DEBUG,
marker = 'Stook-Alert',
},
execute = function(dz, triggeredItem)
-- Set Local environment =================
--local _u = dz.utils -- Holds subset of handy utilities.
--local _h = dz.helpers -- Holds the global functions in global_data
--local _d = dz.globalData -- Holds the global data
-- Get coordinates from settings and adjust a little to create BBox retangle around our location.
local lat_max = dz.settings.location.latitude + 0.000001
local long_max = dz.settings.location.longitude + 0.000001
local lat_min = dz.settings.location.latitude - 0.000001
local long_min = dz.settings.location.longitude - 0.000001
-- set RIVM url, with the BBox coordinates.
local rivmurl='https://data.rivm.nl/geo/alo/wms?service=WMS&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&QUERY_LAYERS=stookwijzer_v2&LAYERS=stookwijzer_v2&info_format=application/json&feature_count=2&I=0&J=0&WIDTH=1&HEIGHT=1&CRS=CRS:84&BBOX=' .. long_min .. ',' .. lat_min .. ',' .. long_max .. ',' .. lat_max
local alertLevel = dz.ALERTLEVEL_GREY -- Holds the alertLevel (color) to set
local alertText = ''
-- Use some color variables
local htmlAdviceColor = '#000000;' -- Default = Black
local htmlForecastColor = '#000000;' -- Default = Black
local cMagenta = '#ff00ff;'
local cDarkGray = '#808080;'
local cGreen = '#008000;'
local cBlue = '#0000FF;'
local cYellow = '#ffff00;'
local cDarkYellow = '#ffdb00;'
local cOrange = '#ffa500;'
local cRed = '#ff0000;'
--Adjust lineheight
local lineHeight = 1.1
-- Local Functions go here =============
local function addHours(timeStr, hours)
-- Add number of hours to the timeStr given as hh:mm.
local h, m = timeStr:match("(%d+):(%d+)")
local newH = tonumber(h) + hours
local newM = tonumber(m)
newH = newH % 24 -- Ensure hours are within 0-23 range
newM = newM + math.floor((newH - tonumber(h)) * 60)
newM = newM % 60 -- Ensure minutes are within 0-59 range
return string.format("%02d:%02d", newH, newM)
end
-----------------------------
local function setColor(level)
-- Return the color for a given level.
local color = ''
if level == 0 then
color = cGreen
elseif level == 1 then
color = cOrange
else
color = cRed
end
return color
end
-- Now start to do something ============
if (triggeredItem.isTimer) then
dz.openURL({
url = rivmurl,
method = 'GET',
callback = 'triggerSA', -- see httpResponses above.
})
end
if (triggeredItem.isHTTPResponse) then
if (triggeredItem.ok) then
if (triggeredItem.isJSON) then
-- We have some result. Store in table.
local result_table = triggeredItem.json
if type(result_table) == "table" then
dz.log( 'result_table: type = ' .. type(result_table), dz.LOG_DEBUG )
local features_table = result_table['features']
if type(features_table) == "table" then
dz.log( 'features_table: type = ' .. type(features_table), dz.LOG_DEBUG )
local properties_table = features_table[1]['properties']
if type(properties_table) == "table" then
dz.log( 'properties_table: type = ' .. type(properties_table), dz.LOG_DEBUG )
-- Example output
--"properties": {
-- "pc4": "3411",
-- "model_runtime": "07-02-2025 16:00",
-- "lki": 2,
-- "wind": 7.8,
-- "wind_bft": 4,
-- "advies_0": 0,
-- "advies_6": 0,
-- "advies_12": 0,
-- "advies_18": 0,
-- "definitief_0": true,
-- "definitief_6": true,
-- "definitief_12": false,
-- "definitief_18": false,
-- "windrichting": -1
--}
local lki = properties_table.lki
local wind = properties_table.wind
-- Advies level
local advies_0hr = properties_table.advies_0
local advies_6hr = properties_table.advies_6
local advies_12hr = properties_table.advies_12
local advies_18hr = properties_table.advies_18
-- Calculate the time for the forecast hours
local firsttime = properties_table.model_runtime:sub(-5)
local add6hr = addHours( firsttime, 6 )
local add12hr = addHours( firsttime, 12 )
local add18hr = addHours( firsttime, 18 )
-- Set colors for forecast hours based on level
local color0hr = setColor( advies_0hr )
local color6hr = setColor( advies_6hr )
local color12hr = setColor( advies_12hr )
local color18hr = setColor( advies_18hr )
-- Log most important content -- What do we have now?
dz.log( 'Advies_0 = ' .. advies_0hr .. ', ' .. firsttime .. 'uur, code '.. color0hr .. '; LKI: ' .. lki .. '; Wind: ' .. wind .. ' m/s', dz.LOG_DEBUG )
dz.log( 'Advies_6 = ' .. advies_6hr .. ', ' .. add6hr .. 'uur, code ' .. color6hr, dz.LOG_DEBUG )
dz.log( 'Advies_12 = ' .. advies_12hr .. ', ' .. add12hr .. 'uur, code ' .. color12hr, dz.LOG_DEBUG )
dz.log( 'Advies_18 = ' .. advies_18hr .. ', ' .. add18hr .. 'uur, code ' .. color18hr, dz.LOG_DEBUG )
-- Create the alert text with calculated color
local text0hr = '<span style="line-height:' .. lineHeight .. '; color: ' .. color0hr .. '">' .. firsttime ..' uur</span>'
local text6h = '<span style="color: ' .. color6hr .. '">' .. add6hr ..' uur</span>'
local text12h = '<span style="color: ' .. color12hr .. '">' .. add12hr ..' uur</span>'
local text18h = '<span style="color: ' .. color18hr .. '">' .. add18hr ..' uur</span>'
-- Now evaluate the results for firsttime level ============
if advies_0hr == 0 then
-- Set alertLevel Green.
alertText = text0hr .. ' Geen stookalert (LKI: ' .. lki .. ' Wind: ' .. wind .. ' m/s)<br>' .. text6h .. ' - ' .. text12h .. ' - ' .. text18h
alertLevel = dz.ALERTLEVEL_GREEN
dz.devices(SA_alert_idx).updateAlertSensor( alertLevel, alertText )
elseif advies_0hr == 1 then
alertText = text0hr .. ' Stookalert (LKI: ' .. lki .. ' Wind: ' .. wind .. ' m/s)<br>' .. text6h .. ' - ' .. text12h .. ' - ' .. text18h
-- Set alertLevel Orange.
alertLevel = dz.ALERTLEVEL_ORANGE
dz.devices(SA_alert_idx).updateAlertSensor( alertLevel, alertText )
elseif advies_0hr == 2 then
-- RIVM alert!
alertText = text0hr .. ' Stookalert! (LKI: ' .. lki .. ' Wind: ' .. wind .. ' m/s)<br>' .. text6h .. ' - ' .. text12h .. ' - ' .. text18h
-- Set alertLevel Red.
alertLevel = dz.ALERTLEVEL_RED
-- Only send notification when RIVM alert increases the last stored alertLevel to red (=4).
if dz.devices(SA_alert_idx).color < 4 and SA_emailTo ~= '' then
-- alertLevel increased, so send notification.
dz.email( 'Stookalert!', 'Stookalert - LKI:' .. lki .. ' Wind: ' .. wind , SA_emailTo, 0)
end
-- Update with new alertLevel and alertText.
dz.devices(SA_alert_idx).updateAlertSensor( alertLevel, alertText )
end
else
dz.log( 'No properties_table found', dz.LOG_ERROR )
end --properties_table
else
dz.log( 'No features_table found', dz.LOG_ERROR )
end --features_table
else
dz.log( 'No result_table found', dz.LOG_ERROR )
end --result_table
else
dz.log( 'JSON - NOT OK', dz.LOG_ERROR )
end -- isJSON
else
dz.log( 'Item NOT OK', dz.LOG_ERROR )
end --triggeredItem-OK
end -- isHTTPResponse
end -- execute
}
-- That's All --------------------------------------------------
You can also take a look at my Dutch local 'Stookwijzer'. That gives more information, is more configurable for the forecast and can update per hour.