New version needed to enable script to deal with situations where afvalwijzer shows pickup dates for two years.
Code: Select all
--[[ getGarbageDates.lua for [ dzVents >= 2.4.28 ]
This script is only useful in those areas of the Netherlands where the household garbage collector is connected to afvalwijzer.nl
Enter your zipcode and housenumber in the appropriate place between the lines starting with --++++
Next is to set your virtual text and or virtual alert device.
the text device will contain the most nearby collectdates for the various types of household garbage
the alert device will contain the date and type for the garbage collection that will arrive first
A notification is send in the morning when garbage collection will happen today and in the evening when garbage collection will happen tomorrow.
History:
20180705: Start Coding
20180725: First public release
20180819: Changed target URL to mijnafvalwijzer
20181108: use curl because of badly formatted json return
20200614: sort lines before posting them to text device
20200614: code cleanup
20200614: Prepared for period close to end of year (ophaaldagenNext)
20200615: Fixed notification bug
20200615: Add choice for notification subsystem(s)
20200830: Change method of determining next collection dates
20200930: Scraping HTTP return because http://json.mijnafvalwijzer.nl/ - only accepts calls from paying customers
20201118: Use scriptVar for httpResponse, -callBack and marker
20201118: Don't assume this year but get year(s) from response
]]--
local scriptVar = 'getGarbage_20201118'
return
{
on =
{
timer =
{
'at 18:10',
'at 08:10',
},
devices =
{
'getGarbage', -- Only for test purposes can be ignored
},
httpResponses =
{
scriptVar, -- Trigger to handle HTTP response
},
},
logging =
{
level = domoticz.LOG_ERROR, -- set to LOG_DEBUG when something does not work as expected
marker = scriptVar,
},
data =
{
garbage =
{
initial = {}, -- Keep a copy of yeardates just in case
},
},
execute = function(dz, item)
--++++--------------------- Mandatory: Set your values and device names below this Line --------------------------------------
local myZipcode = '1111AA' -- Your zipcode like '3085RA'
local myHousenumber = 1 -- Your housenumber like 38
local myTextDevice = 'Garbage type pickup dates' -- Name with quotes or idx without when created as virtual text device
local myAlertDevice = 'Next garbage pickup date' -- Name with quotes or idx without when created as virtual alert device
local myNotificationTable =
{
-- table with one or more notification systems.
-- uncomment the notification systems that you want to be used
-- Can be one or more of
-- dz.NSS_FIREBASE_CLOUD_MESSAGING,
-- dz.NSS_PUSHOVER,
-- dz.NSS_HTTP,
-- dz.NSS_KODI,
-- dz.NSS_LOGITECH_MEDIASERVER,
-- dz.NSS_NMA,
-- dz.NSS_PROWL,
-- dz.NSS_PUSHALOT,
-- dz.NSS_PUSHBULLET,
-- dz.NSS_PUSHOVER,
-- dz.NSS_PUSHSAFER,
dz.NSS_TELEGRAM,
}
local myGarbageLabels =
{
['Restafval'] = 'Kliko', --'Restafval',
['Plastic'] = 'Plastic', --'Plastic, Blik en Drank kartons',
['Papier'] = 'Papier en karton',
['Textiel'] = 'Textiel',
['Kerstbomen'] = 'Kerstbomen',
['Groente'] = 'Groente, Fruit en Tuinafval'
}
--++++---------------------------- No changes required below this line --------------------------------------------
local months =
{
['januari'] = 1,
['februari'] = 2,
['maart'] = 3,
['april'] = 4,
['mei'] = 5,
['juni'] = 6,
['juli'] = 7,
['augustus'] = 8,
['september'] = 9,
['oktober'] = 10,
['november'] = 11,
['december'] = 12,
}
local function collectGarbageDates(delay)
local getGarbage_url = 'https://www.mijnafvalwijzer.nl/nl/' .. myZipcode .. '/' .. myHousenumber
dz.openURL(
{
url = getGarbage_url ,
callback = scriptVar,
}).afterSec(delay)
end
-- Add entry to log and notify to set subsystems
local function errorMessage(message)
dz.log(message,dz.LOG_ERROR)
dz.notify('Garbage',message, dz.PRIORITY_HIGH, dz.SOUND_DEFAULT, "" , myNotificationTable)
end
local function convertDateFormat(dateString, fromPattern, toFormat)
local fromPattern = fromPattern or '(%d+)-(%d+)-(%d+)'
local toFormat = toFormat or '%a %d %b'
local runyear, runmonth, runday= dateString:match(fromPattern)
return os.date(toFormat, os.time({year = runyear, month = runmonth, day = runday}) )
end
local function text(lines)
if dz.utils.deviceExists(myTextDevice) then
dz.devices(myTextDevice).updateText( '<tt>' .. table.concat(lines, '\n') .. '</tt>\n')
end
end
local function alertLevel(delta)
if delta < 2 then return dz.ALERTLEVEL_RED end
if delta < 3 then return dz.ALERTLEVEL_YELLOW end
if delta < 4 then return dz.ALERTLEVEL_ORANGE end
return dz.ALERTLEVEL_GREEN
end
local function alert(lines)
if dz.utils.deviceExists(myAlertDevice) then
dz.devices(myAlertDevice).updateAlertSensor(alertLevel(lines.delta), lines[1])
end
if dz.time.matchesRule('at 08:00-17:00') and lines.delta == 0 then
dz.notify('Huisafval',lines[1]:match('%: (.*)') .. ' will be collected today', dz.PRIORITY_NORMAL,dz.SOUND_DEFAULT, "" , myNotificationTable)
elseif dz.time.matchesRule('at 18:00-22:00') and lines.delta == 1 then
dz.notify('Huisafval',lines[1]:match('%: (.*)') .. ' will be collected tomorrow', dz.PRIORITY_NORMAL,dz.SOUND_DEFAULT, "" , myNotificationTable)
end
end
function table.merge (t1, t2)
for k,v in ipairs(t2) do
table.insert(t1, v)
end
return t1
end
local function selectRecords(t)
dz.data.garbage = t -- store for future use
for date in pairs(t) do
if date < dz.time.rawDate then
t[date] = nil
end
end
return t
end
local function makeLines(t)
-- dz.utils.dumpTable(t)
local startDate = dz.time
local futureDay = 0
local lineCounter = 1
local textLines = {}
while lineCounter < 5 and futureDay < 60 do
local traverseDate = startDate.addDays(futureDay).rawDate
if t[traverseDate] then
local textLine = convertDateFormat(traverseDate) .. ': ' .. table.concat(t[traverseDate], ' & ')
if lineCounter == 1 then textLines['delta'] = futureDay end
textLines[lineCounter] = textLine
lineCounter = lineCounter + 1
end
futureDay = futureDay + 1
end
return textLines
end
local function handleResponse(t, freshData)
local garbage = {}
if freshData then
local year = '%d%d%d%d'
local date = ''
local garbageYear, dutchDate
for line in t:gmatch('[^\r\n]+') do -- read response line by line
if line:find('<div id=%"jaar%-' .. year .. '%" class=%"ophaaldagen%">') then
garbageYear = line:match(year)
elseif line:find('<span class=%"span%-line%-break%">%a+%s%d+%s%a') then
dutchDate = line:match('%b><'):sub(2,-2)
date = (garbageYear or dz.time.year) .. '-' ..
dz.utils.leadingZeros(months[dutchDate:match('%a+%s+%d+%s+(%a+)')],2) .. '-' ..
dz.utils.leadingZeros(dutchDate:match('%a+%s+(%d+)'),2)
elseif line:find('<span class=%"afvaldescr%">') then
local garbageLong = line:match('%b><'):sub(2,-2)
if garbage[date] then
table.insert(garbage[date], myGarbageLabels[garbageLong:match("(%a+)%.*")])
else
garbage[date] = { myGarbageLabels[garbageLong:match("(%a+)%.*")] }
end
end
end
elseif t ~= nil and next(dz.data.garbage) then
garbage = t
else
errorMessage('Problem with response and no previous data')
return
end
textLines = makeLines(selectRecords(garbage))
alert(textLines)
text(textLines)
end
-- Main
if item.isHTTPResponse then
if item.ok then
handleResponse(item.data, true)
else
errorMessage('Problem with response (not ok) Using previous data')
handleResponse(dz.data.garbage)
collectGarbageDates(600) -- response not OK, try again after 10 minutes
end
else
collectGarbageDates(1)
end
end
}