Garbage pickup date (mijnafvalwijzer.nl) custom_component

This is scary, almost the same :smile:

The solution i came up with works like this:

- alias: 'Notify Lametric - Afvalkalender GFT'
  trigger:
     - platform: time
       minutes: '/60'
       seconds: 00
  condition:
    - condition: template
        value_template: >-
          {%- if (as_timestamp(now()) > (as_timestamp(states.calendar.afvalkalender.attributes.start_time) - 21600)) and ( as_timestamp( states.calendar.afvalkalender.attributes.start_time ) ) - ( as_timestamp( now() ) > 0 ) -%}
            true
          {%- endif -%}
    - condition: template
      value_template: "{{ states.calendar.afvalkalender.attributes.message  == 'GFT' }}"
  action:
  - service: notify.lametric_woonkamer
    data:
      message: "{{ states.calendar.afvalkalender.attributes.description }} wordt morgen opgehaald"
      data:
        sound: 'notification3'
        icon: 'i17004'

For the three different types of garbage pickups (paper, regular and lawn-and-leaf) i use three different automations to show a notification on my Lametric Time every hour from 6pm the day before the actual pick-up date.

"""
@ Author      : Daniel Palstra & Bram van Dartel
@ Date        : 06/12/2017
@ Description : MijnAfvalwijzer Sensor - It queries mijnafvalwijzer.nl.
@ Notes:        Copy this file and place it in your
                "Home Assistant Config folder\custom_components\sensor\" folder.
"""
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (CONF_NAME)
from homeassistant.util import Throttle

from urllib.request import urlopen
from datetime import timedelta
import json
import argparse
import datetime
import logging

import voluptuous as vol

_LOGGER = logging.getLogger(__name__)

ICON = 'mdi:delete-empty'

TRASH_TYPES = [{1: "gft"}, {2: "pmd"}, {3: "papier"}, {4: "restafval"}]
SCAN_INTERVAL = timedelta(minutes=1)
#SCAN_INTERVAL = timedelta(seconds=15)

DEFAULT_NAME = 'MijnAfvalwijzer Sensor'
SENSOR_PREFIX = 'trash_'
CONST_POSTCODE = "postcode"
CONST_HUISNUMMER = "huisnummer"

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
    vol.Required(CONST_POSTCODE): cv.string,
    vol.Required(CONST_HUISNUMMER): cv.string,
})


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up date afval sensor."""
    postcode = config.get(CONST_POSTCODE)
    huisnummer = config.get(CONST_HUISNUMMER)
    url = ("http://json.mijnafvalwijzer.nl/?"
       "method=postcodecheck&postcode={0}&street=&huisnummer={1}&toevoeging=&platform=phone&langs=nl&").format(postcode,huisnummer)
    data = TrashCollectionSchedule(url, TRASH_TYPES)

    devices = []
    for trash_type in TRASH_TYPES:
        #print(trash_type.values())
        for t in trash_type.values():
            devices.append(TrashCollectionSensor(t, data))
    add_devices(devices)


class TrashCollectionSensor(Entity):
    """Representation of a Sensor."""

    def __init__(self, name, data):
        """Initialize the sensor."""
        self._state = None
        self._name = name
        self.data = data

    @property
    def name(self):
        """Return the name of the sensor."""
        return SENSOR_PREFIX + self._name

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def icon(self):
        """Return the icon to use in the frontend."""
        return ICON

    def update(self):
        """Fetch new state data for the sensor.

        This is the only method that should fetch new data for Home Assistant.
        """
        self.data.update()
        #print(self.data.data)
        for d in self.data.data:
            if d['name_type'] == self._name:
                self._state = d['pickup_date']


class TrashCollectionSchedule(object):

    def __init__(self, url, trash_types):
        self._url = url
        self._trash_types = trash_types
        self.data = None

    @Throttle(SCAN_INTERVAL)
    def update(self):
        response = urlopen(self._url)
        string = response.read().decode('utf-8')
        json_obj = json.loads(string)
        today = datetime.date.today().strftime("%Y-%m-%d")
        tschedule = []

        for name in TRASH_TYPES:
            for item in json_obj['data']['ophaaldagen']['data'] or json_obj['data']['ophaaldagenNext']['data']:
                if item['date'] > today:
                    if item['nameType'] in name.values():
                        trash = {}
                        #trash['shortcode'] = (next(iter(name.values())))
                        trash['name_type'] = item['nameType']
                        trash['pickup_date'] = (str(datetime.datetime.strptime(item['date'], "%Y-%m-%d")))
                        #trash['pickup_date'] = (str(datetime.datetime.strptime(item['date'], "%Y-%m-%d") + datetime.timedelta(days=0)))
                        tschedule.append(trash)
                        self.data = tschedule
                        break
1 Like

And the mijnafvalwijzer platform:

- platform: mijnafvalwijzer
  postcode: 1111AA
  huisnummer: 1

And the sensor platform:

- platform: template
  sensors:
    trash_restafval_date:
      friendly_name: 'Grijze bak'
      value_template: '{{ as_timestamp(states.sensor.trash_restafval.state) | timestamp_custom("%Y-%m-%d") }}'

And an automated notify a day before at 20:00 hours:

- alias: 'Trash - Grijze bak'
  trigger:
    - platform: time
      hours: 20 
      minutes: 0
      seconds: 0
  condition:
    - condition: template
      value_template: '{{ now().strftime("%Y-%m-%d") == (as_timestamp(states.sensor.trash_restafval.state) - (24*3600)) | timestamp_custom("%Y-%m-%d") }}'
  action:
    - service: notify.family
      data_template:
        message: 'Het is vandaag - {{ now().strftime("%Y-%m-%d") }}. De grijze bak wordt morgen geleegd!.'

And a group:

trash_pickup:
  name: "Trash Pickup"
  control: hidden
  entities:
    - sensor.trash_restafval_date
2 Likes

This looks great and is a good start. Unfortunately the city I live in uses slightly different codes for the various of garbage collections (one of which breaks the code).

For my installation I had to add the following trash types:

TRASH_TYPES = [{1: "gft"}, {2: "pmd"}, {3: "papier"}, {4: "restafval"}, {5: "restgft"}, {6: "plastic"}]

Due to some incompatible nameType’s in the JSON I also had to change to the type property, see code below:

        for name in TRASH_TYPES:
            for item in json_obj['data']['ophaaldagen']['data'] or json_obj['data']['ophaaldagenNext']['data']:
                if item['date'] > today:
                    if item['type'] in name.values():
                        trash = {}
                        #trash['shortcode'] = (next(iter(name.values())))
                        trash['name_type'] = item['type']
                        trash['pickup_date'] = (str(datetime.datetime.strptime(item['date'], "%Y-%m-%d")))
                        #trash['pickup_date'] = (str(datetime.datetime.strptime(item['date'], "%Y-%m-%d") + datetime.timedelta(days=0)))
                        tschedule.append(trash)
                        self.data = tschedule
                        break

This was caused by the following JSON:

{
        "nameType": "rest\/gft",
	"type": "restgft",
	"date": "2018-01-22"
}, {
	"nameType": "plastic ",
	"type": "plastic",
	"date": "2018-01-29"
}
2 Likes

HI @xirixiz

trying your code, been looking for something like this before, so thanks!

I’ve made the following package containing the code above:

homeassistant:
  platform: mijnafvalwijzer
  postcode: !secret postcode
  huisnummer: !secret huisnummer

sensor:
  - platform: template
    sensors:
      trash_restafval_date:
        friendly_name: 'Grijze bak'
        value_template: '{{ as_timestamp(states.sensor.trash_restafval.state) | timestamp_custom("%Y-%m-%d") }}'

automation:
  - alias: 'Trash - Grijze bak'
    trigger:
      - platform: time
        hours: 20 
        minutes: 0
        seconds: 0
    condition:
      - condition: template
        value_template: '{{ now().strftime("%Y-%m-%d") == (as_timestamp(states.sensor.trash_restafval.state) - (24*3600)) | timestamp_custom("%Y-%m-%d") }}'
    action:
      - service: notify.family
        data_template:
          message: 'Het is vandaag - {{ now().strftime("%Y-%m-%d") }}. De grijze bak wordt morgen geleegd!.'

group:
  trash_pickup:
    name: "Trash Pickup"
    control: hidden
    entities:
      - sensor.trash_restafval_date

the python component in /custom_component/sensor as instructed .

Because I didnt know what to do with the platform, I put it directly under homeassistant: which is accepted fine, and all checks are green.

Running it after reboot gives the following error though:

WARNING (MainThread) [homeassistant.config] Package package_afvalwijzer contains invalid customize

which is strange because there’s no customize in it…

also, the sensor.trash_restafval_date is created but no state is set, it is Unknown.
Maybe the platform definition is incorrect? How should i define that? Please have a look.

followup question:
will this component automatically create sensors for Paper, GFT and Plastics also?

Cheers, and thanks

Hi @Mariusthvdb,

It seems that the problem is at json.afvalwijzer.nl. Try to enter the following url with your postal code and housenumber:

I receive the following error at the moment:
Op dit moment is het erg druk. Probeert u het later nog eens. Onze excuses voor het ongemak.

Cheers

not sure if im doing this correctly but clicking the link above indeed results in your message. Entering the code and number into the json from the component renders the same btw, so it must be busy :wink:

"http://json.mijnafvalwijzer.nl/?"
       "method=postcodecheck&postcode={0}&street=&huisnummer={1}&toevoeging=&platform=phone&langs=nl&"

about the code above here, you’re sure the double " " and " " are necessary in the url?

in your code, you mention the mijnafvalwijzer platform. How is this entered in the configuration files? Where do you out that? It is the first time i see a platform like that, so sorry if I ask the obvious…

hi @xirixiz

where did you put the - platform: mijnafvalwijzer declaration? I cant get it to work somehow…

----edit----

cool, finally managed to sort this… added the other garbage pickups :wink:

platform: mijnafvalwijzer
postcode: !secret postcode
huisnummer: !secret huisnummer

is to be placed under sensor: . I have it in a separate package so it reads:

##########################################################################################
## MijnAfvalWijzer Custom Component 
## created by @xirixiz, more info on 
## https://community.home-assistant.io/t/garbage-pickup-date-mijnafvalwijzer-nl-custom-component/34631
# place this package in /config/packages
# place the custom component mijnafvalwijzer.py in /config/custom_components/sensor
##########################################################################################
homeassistant:
  customize:
    sensor.trash_restafval_date:
      entity_picture: /local/mijnafvalwijzer/restafval.png
    sensor.trash_plastic_date:
      entity_picture: /local/mijnafvalwijzer/plastic.png
    sensor.trash_gft_date:
      entity_picture: /local/mijnafvalwijzer/gft.png
    sensor.trash_papier_date:
      entity_picture: /local/mijnafvalwijzer/papier.png

sensor:
  - platform: mijnafvalwijzer
    postcode: !secret postcode
    huisnummer: !secret huisnummer

  - platform: template
    sensors:
      trash_restafval_date:
        friendly_name: 'Restafval'
        value_template: '{{ as_timestamp(states.sensor.trash_restafval.state) | timestamp_custom("%Y-%m-%d") }}'
      trash_plastic_date:
        friendly_name: 'Plastic'
        value_template: '{{ as_timestamp(states.sensor.trash_plastic.state) | timestamp_custom("%Y-%m-%d") }}'
      trash_gft_date:
        friendly_name: 'Gft'
        value_template: '{{ as_timestamp(states.sensor.trash_gft.state) | timestamp_custom("%Y-%m-%d") }}'
      trash_papier_date:
        friendly_name: 'Papier'
        value_template: '{{ as_timestamp(states.sensor.trash_papier.state) | timestamp_custom("%Y-%m-%d") }}'

automation:
  - alias: 'Trash - Restafval'
    trigger:
      - platform: time
        hours: 20 
        minutes: 0
        seconds: 0
    condition:
      - condition: template
        value_template: '{{ now().strftime("%Y-%m-%d") == (as_timestamp(states.sensor.trash_restafval.state) - (24*3600)) | timestamp_custom("%Y-%m-%d") }}'
    action:
      - service: notify.notify
        data_template:
          message: 'Het is vandaag - {{ now().strftime("%Y-%m-%d") }}. Restafval wordt morgen opgehaald!.'

  - alias: 'Trash - Plastic'
    trigger:
      - platform: time
        hours: 20 
        minutes: 0
        seconds: 0
    condition:
      - condition: template
        value_template: '{{ now().strftime("%Y-%m-%d") == (as_timestamp(states.sensor.trash_plastic.state) - (24*3600)) | timestamp_custom("%Y-%m-%d") }}'
    action:
      - service: notify.notify
        data_template:
          message: 'Het is vandaag - {{ now().strftime("%Y-%m-%d") }}. Plastic wordt morgen opgehaald!.'

  - alias: 'Trash - Gft'
    trigger:
      - platform: time
        hours: 20 
        minutes: 0
        seconds: 0
    condition:
      - condition: template
        value_template: '{{ now().strftime("%Y-%m-%d") == (as_timestamp(states.sensor.trash_gft.state) - (24*3600)) | timestamp_custom("%Y-%m-%d") }}'
    action:
      - service: notify.notify
        data_template:
          message: 'Het is vandaag - {{ now().strftime("%Y-%m-%d") }}. Gft wordt morgen opgehaald!.'

  - alias: 'Trash - Papier'
    trigger:
      - platform: time
        hours: 20 
        minutes: 0
        seconds: 0
    condition:
      - condition: template
        value_template: '{{ now().strftime("%Y-%m-%d") == (as_timestamp(states.sensor.trash_papier.state) - (24*3600)) | timestamp_custom("%Y-%m-%d") }}'
    action:
      - service: notify.notify
        data_template:
          message: 'Het is vandaag - {{ now().strftime("%Y-%m-%d") }}. Papier wordt morgen opgehaald!.'

group:
  trash_pickup:
    name: "Trash Pickup"
    control: hidden
    entities:
      - sensor.trash_restafval_date
      - sensor.trash_plastic_date
      - sensor.trash_gft_date
      - sensor.trash_papier_date

next:
check why plastic won’t work yet (today!! which might be it coming to think of it), and add some nice persistent notifications, so not to forget the pickup! :wink:
btw, ive added the ‘official’ entity_pictures from Saver:

23

13
Can upload here, if interested.

some small edits, mainly to do with time representation in the frontend card:

  trash_plastic_verpakkingsafval_date:
    friendly_name: 'Plastic'
    value_template: '{{ as_timestamp(states.sensor.trash_plastic_verpakkingsafval.state) 
                       | timestamp_custom("%A %d %B") }}'

As you can see above, the name of the Trash_name was "plastic verpakkingsafval" and not plastic
changed all references in the python component and the package accordingly (except the sensor name, which would become too long for the card to display nicely…).

final result (without date order yet, hope to be able to realize that), and maybe change the date representation in ‘Today!’ if applicable;-)

Card:
49

More - info:

42

Cheers,
Marius

1 Like

hi Again, @xirixiz

trying to create a persistent notification on the day itself, ive been testing this:

condition:

  • condition: template
    value_template: ‘{{ now().strftime("%Y-%m-%d") ==
    (as_timestamp(states.sensor.trash_plastic_verpakkingsafval.state))
    | timestamp_custom("%Y-%m-%d") }}’

the timestamp gives None though…

dont really understand because

the night before this does work:

condition:

  • condition: template
    value_template: ‘{{ now().strftime("%Y-%m-%d") ==
    (as_timestamp(states.sensor.trash_plastic_verpakkingsafval.state) -
    (24*3600)) | timestamp_custom("%Y-%m-%d") }}’

and ive only token out the substraction…

- 
                     (24*3600)

please have a look why this wouldn’t work?

also, since there’s a lot of info on the afvalwijzer page http://json.mijnafvalwijzer.nl/?method=postcodecheck&postcode={code}&street=&huisnummer={number}&toevoeging=&platform=phone&langs=nl&

i was wondering if we couldn’t create a Rest_sensor for it and extract all info out of it with a template.

this is working, but throws all of the homepage in the sensor data…

- platform: jsonrest
  resource: http://json.mijnafvalwijzer.nl/?method=postcodecheck&postcode=POSTALCODE&street=&huisnummer=NUMBER
  method: GET
  name: Afvalwijzer info
#  scan_interval: 3600 

Ive made it to
{{states.sensor.afvalwijzer_info.attributes.data.ophaaldagen.data[1].date}} for the first date, or {{states.sensor.afvalwijzer_info.attributes.data.ophaaldagen.data[-1].date}}, and anything in between, but thats not very useful yet. Would need the date of today, and tomorrow, so some logic would need to be implemented i guess.

to show:

showing all Ophaaldagen.

How can i extract further in that list? a bit stuck because of the brackets… [] and {}

Cheers,
Marius

what about using node-red then getting that to send mqtt to HA

not sure, wha would that take? never really worked with NR, only installed the add-in…

Hi Marius,

That is the problem I struggled with all the time…no good array to parse resulting in only a list of all pickup days in the current year.

I’ll check it again if I can create a more solid solution.

Cheers

cool, thanks!

please have a look why the "today’ automation doesnt work either. Its nice to be warned the day before, but id love to have the warning on the day itself too.

Ive just noticed (in my json-sensor) that they switch very quickly showing the next pickup day, while it is still ‘today’. might make it a bit difficult, if the pickupday=today condition is never met ;-((

Anyways, thanks for the component. I like it a lot!

Is also working, but it only shows what trash is going to be picked up Today.

well thats nice, and maybe an automation can be built on the other notification:
if tomorrow is a pickup day, show this scrape tomorrow…? something like that?

Seems a bit wird these scrape sensors, not as ‘programmable’ as the regular api sensors. But maybe there’s no other way…

btw, i think there’s also a Nextday? maybe thats scalable too? That way we would have both. Current and next.

thats very nice! How can we use that in Hassio? Don’t think i’ve ran a bash script before in the setup.

btw, might i ask if you have any experience with the techniques used in this Epson cartridge level program. I have it working up to the actual ink-levels, but down think i use the correct ‘scraping’ technique.
Maybe you can guide meow to proceed, thx!

Would you mind to share youre complete (working) code for this garbage collection . I’m fighting for several days
now but i’m not able to get this working. What I want is to trigger at let say 8:00PM and if there is a garbage pickup scheduled in the google calendar within the next 24 hours and then select , based on the message parameter (GFT, PLASTIC, RESTAFVAL), a correct message and picture to send a notify with telegram.

Thanks in advance.

@proton999
In order to keep this thread clean, I’ve created a new thread, See my solution here: https://community.home-assistant.io/t/another-way-of-garbage-pickup-notifications

hi,
its a bit off, have a look:

07

today is Restafval, not Papier…
maybe theres a typo in your sensor value, it’s showing the . after restafval?

made a customization for this:

sensor.afval_soort:
  templates:
    entity_picture: >
     if (entity.state = 'Papier') return '/local/mijnafvalwijzer/papier.png';
     else if (entity.state = 'Gft' ) return '/local/mijnafvalwijzer/gft.png';
     else if (entity.state = 'Plastic verpakkingsafval') return '/local/mijnafvalwijzer/plastic.png';
     else if (entity.state = 'Restafval') return '/local/mijnafvalwijzer/restafval.png';
     else return '/local/mijnafvalwijzer/kliko.png';

13

cool.
Cheers,
Marius

1 Like