Skip to content

Commit

Permalink
Release 4.0.0 - Breaking Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
xirixiz committed Jan 28, 2020
1 parent 7d79fa0 commit ca3e96b
Show file tree
Hide file tree
Showing 13 changed files with 87 additions and 1,406 deletions.
2 changes: 1 addition & 1 deletion custom_components/afvalwijzer/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Afvalwijzer",
"documentation": "https://github.com/xirixiz/Home-Assistant-Sensor-Afvalwijzer",
"requirements": [
"bs4==0.0.1"
"afvaldienst==0.3.0"
],
"dependencies": [],
"codeowners": [
Expand Down
238 changes: 59 additions & 179 deletions custom_components/afvalwijzer/sensor.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
"""
@ Authors : Bram van Dartel
@ Date : 10/12/2019
@ Date : 28/01/2020
@ Description : Afvalwijzer Json/Scraper Sensor - It queries mijnafvalwijzer.nl or afvalstoffendienstkalender.nl.
sensor:
- platform: afvalwijzer
url: mijnafvalwijzer.nl (optional, default mijnafvalwijzer.nl)
postcode: 1111AA
huisnummer: 1
toevoeging: A (optional)
label_geen: 'Bla' (optional, default Geen)
23-02-2019 - Back to JSON release instead of scraper
23-02-2019 - Move scraper url, cleanup, and some minor doc fixes
24-02-2019 - Scraper debug log url fix
25-02-2019 - Update to new custom_sensor location
07-03-2019 - Make compatible for afvalstoffendienstkalender.nl as well
25-03-2019 - Remove Python 3.7.x f-strings, back to old format for beteer compatibility
26-04-2019 - Make compatible with hass 0.92
22-09-2019 - Add bs4 as a requirement in manifest.json (for hassio)
10-12-2019 - Fix whitespace bug
28-01-2020 - Rebuild from scratch! Use Python library! Breaking changes!
"""

VERSION = '3.0.12'
VERSION = '4.0.0'

import logging
from Afvaldienst import Afvaldienst
from datetime import date, datetime, timedelta

import bs4
import requests
import logging

import homeassistant.helpers.config_validation as cv
import voluptuous as vol
Expand All @@ -44,78 +26,59 @@
ICON = 'mdi:delete-empty'
SENSOR_PREFIX = 'trash_'

CONST_URL = 'url'
CONST_POSTCODE = 'postcode'
CONST_HUISNUMMER = 'huisnummer'
CONST_TOEVOEGING = 'toevoeging'
CONST_LABEL_NONE = 'label_geen'
CONST_PROVIDER = 'provider'
CONST_ZIPCODE = 'zipcode'
CONST_HOUSENUMBER = 'housenumber'
CONST_SUFFIX = 'suffix'
CONST_LABEL = 'default_label'

SCAN_INTERVAL = timedelta(seconds=30)
SCAN_INTERVAL = timedelta(seconds=5)
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=3600)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONST_URL, default="mijnafvalwijzer.nl"): cv.string,
vol.Required(CONST_POSTCODE): cv.string,
vol.Required(CONST_HUISNUMMER): cv.string,
vol.Optional(CONST_TOEVOEGING, default=""): cv.string,
vol.Optional(CONST_LABEL_NONE, default="Geen"): cv.string,
vol.Optional(CONST_PROVIDER, default="mijnafvalwijzer"): cv.string,
vol.Required(CONST_ZIPCODE): cv.string,
vol.Required(CONST_HOUSENUMBER): cv.string,
vol.Optional(CONST_SUFFIX, default=""): cv.string,
vol.Optional(CONST_LABEL, default="Geen"): cv.string,
})


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the sensor platform."""
# Setup JSON request (add sensor/devices)
url = config.get(CONST_URL)
postcode = config.get(CONST_POSTCODE)
huisnummer = config.get(CONST_HUISNUMMER)
toevoeging = config.get(CONST_TOEVOEGING)

if None in (postcode, huisnummer):
logger.error("Postcode or huisnummer not set!")

url = ("https://json.{0}/?method=postcodecheck&postcode={1}&street=&huisnummer={2}&toevoeging={3}&platform=phone&langs=nl&").format(url,postcode,huisnummer,toevoeging)
logger.debug("Json request url: {}".format(url))
response = requests.get(url)

if response.status_code != requests.codes.ok:
logger.exception("Error doing API request")
else:
logger.debug("API request ok {}".format(response.status_code))

json_obj = response.json()
json_data = (json_obj['data']['ophaaldagen']['data'] + json_obj['data']['ophaaldagenNext']['data'])

# Get unique trash shortname(s)
uniqueTrashShortNames = []
allTrashNames = ['firstdate', 'firstwastetype', 'today', 'tomorrow', 'next']
uniqueTrashShortNames.extend(allTrashNames)
sensors = []
provider = config.get(CONST_PROVIDER)
zipcode = config.get(CONST_ZIPCODE)
housenumber = config.get(CONST_HOUSENUMBER)
suffix = config.get(CONST_SUFFIX)

for item in json_data:
element = item["nameType"]
if element not in uniqueTrashShortNames:
uniqueTrashShortNames.append(element)
afvaldienst = Afvaldienst(provider, zipcode, housenumber, suffix)

logger.debug("uniqueTrashShortNames succesfully added: {}".format(uniqueTrashShortNames))
# Get trash types to create sensors from
trashTypesDefault = afvaldienst.trash_type_list
trashTypesAdditional = afvaldienst.trash_schedule_today_json + afvaldienst.trash_schedule_tomorrow_json + afvaldienst.trash_schedule_next_days_json
for item in trashTypesAdditional:
trashTypesDefault.append(item['key'])

data = (TrashCollectionSchedule(url, allTrashNames, config))
fetch_trash_data = (TrashSchedule(afvaldienst, config))

for name in uniqueTrashShortNames:
sensors.append(TrashCollectionSensor(name, data, config))
# Setup sensors
sensors = []
for name in trashTypesDefault:
sensors.append(TrashSensor(hass, name, fetch_trash_data, afvaldienst, config))
add_devices(sensors)

logger.debug("Object succesfully added as sensor(s): {}".format(sensors))


class TrashCollectionSensor(Entity):
class TrashSensor(Entity):
"""Representation of a Sensor."""
def __init__(self, name, data, config):
def __init__(self, hass, name, fetch_trash_data, afvaldienst, config):
"""Initialize the sensor."""
self._hass = hass
self._name = name
self.data = data
self.fetch_trash_data = fetch_trash_data
self._afvaldienst = afvaldienst
self.attributes = {}
self.config = config
self._state = self.config.get(CONST_LABEL_NONE)
self._state = self.config.get(CONST_LABEL)

@property
def name(self):
Expand All @@ -132,121 +95,38 @@ def icon(self):
"""Set the default sensor icon."""
return ICON

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

def update(self):
"""Fetch new state data for the sensor."""
self.data.update()
self._state = self.config.get(CONST_LABEL_NONE)
self.fetch_trash_data.update()
self._state = self.config.get(CONST_LABEL)

for item in self.data.data:
logger.debug("Update called for item: {}".format(item))
for item in self.fetch_trash_data.trash_schedule_default:
attributes = {}
attributes['next_pickup_in_days'] = item['days_remaining']
if item['key'] == self._name:

self._state = item['value']
self.attributes = attributes

for item in self.fetch_trash_data.trash_schedule_additional:
if item['key'] == self._name:
if item['value'] != 'None':
self._state = item['value']


class TrashCollectionSchedule(object):
class TrashSchedule(object):
"""Fetch new state data for the sensor."""
def __init__(self, url, allTrashNames, config):
def __init__(self, afvaldienst, config):
"""Fetch vars."""
self._url = url
self._allTrashNames = allTrashNames
self.data = None
self._afvaldienst = afvaldienst
self._config = config

@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Fetch new state data for the sensor."""
response = requests.get(self._url)
json_obj = response.json()
json_data = (json_obj['data']['ophaaldagen']['data'] + json_obj['data']['ophaaldagenNext']['data'])

today = datetime.today().strftime('%Y-%m-%d')
dateConvert = datetime.strptime(today, '%Y-%m-%d') + timedelta(days=1)
tomorrow = datetime.strftime(dateConvert, '%Y-%m-%d')

trashType = {}
trashNext = {}
trashToday = {}
trashTomorrow = {}
multiTrashToday = []
multiTrashTomorrow = []
trashSchedule = []

# Some date count functions for next
def d(s):
[year, month, day] = map(int, s.split('-'))
return date(year, month, day)

def days(start, end):
return (d(end) - d(start)).days

# Collect upcoming trash pickup dates for unique trash
for name in self._allTrashNames:
for item in json_data:
name = item["nameType"]
dateConvert = datetime.strptime(item['date'], '%Y-%m-%d').strftime('%d-%m-%Y')

if name not in trashType:
if item['date'] >= today:
trash = {}
trashType[name] = item["nameType"]
trash['key'] = item['nameType']
trash['value'] = dateConvert
trashSchedule.append(trash)

if item['date'] > today:
if len(trashNext) == 0:
trashType[name] = "next"
trashNext['key'] = "next"
trashNext['value'] = (days(today, item['date']))
trashSchedule.append(trashNext)

if item['date'] == today:
trashType[name] = "today"
trashToday['key'] = "today"
trashSchedule.append(trashToday)
multiTrashToday.append(item['nameType'])
if len(multiTrashToday) != 0:
trashToday['value'] = ', '.join(multiTrashToday).strip()

if item['date'] == tomorrow:
trashType[name] = "tomorrow"
trashTomorrow['key'] = "tomorrow"
trashSchedule.append(trashTomorrow)
multiTrashTomorrow.append(item['nameType'])
if len(multiTrashTomorrow) != 0:
trashTomorrow['value'] = ', '.join(multiTrashTomorrow).strip()

# Setup scraper request
url = self._config.get(CONST_URL)
postcode = self._config.get(CONST_POSTCODE)
huisnummer = self._config.get(CONST_HUISNUMMER)
toevoeging = self._config.get(CONST_TOEVOEGING)
scraper_url = ("https://www.{0}/nl/{1}/{2}/{3}").format(url, postcode, huisnummer, toevoeging)
logger.debug("Scraper request url: {}".format(scraper_url))
scraper_response = requests.get(scraper_url)

if scraper_response.status_code != requests.codes.ok:
logger.exception("Error doing scrape request")
else:
logger.debug("Scrape request ok {}".format(scraper_response.status_code))

scraper_data = bs4.BeautifulSoup(scraper_response.text, "html.parser")

# Append firstDate and firstWasteType
trashFirstDate = {}
trashFirstDate['key'] = 'firstdate'
trashFirstDate['value'] = scraper_data.find('p', attrs={'class':'firstDate'}).text
trashSchedule.append(trashFirstDate)
logger.debug("Data succesfully added {}".format(trashFirstDate))

firstWasteType = {}
firstWasteType['key'] = 'firstwastetype'
firstWasteType['value'] = scraper_data.find('p', attrs={'class':'firstWasteType'}).text
trashSchedule.append(firstWasteType)
logger.debug("Data succesfully added {}".format(firstWasteType))

# Return collected data
logger.debug("trashSchedule content {}".format(trashSchedule))

self.data = trashSchedule
self.trash_schedule_default = self._afvaldienst.trash_schedulefull_json
self.trash_schedule_additional = self._afvaldienst.trash_schedule_today_json + self._afvaldienst.trash_schedule_tomorrow_json + self._afvaldienst.trash_schedule_next_days_json
Loading

0 comments on commit ca3e96b

Please sign in to comment.