diff --git a/.coveragerc b/.coveragerc index ff5bb876b8a3e55fe16441d8766d74499760adc2..d1125c591469996ddb2ac77d8fed5c30de32bbe5 100644 --- a/.coveragerc +++ b/.coveragerc @@ -693,6 +693,7 @@ omit = homeassistant/components/route53.py homeassistant/components/scene/hunterdouglas_powerview.py homeassistant/components/scene/lifx_cloud.py + homeassistant/components/sensor/aftership.py homeassistant/components/sensor/airvisual.py homeassistant/components/sensor/alpha_vantage.py homeassistant/components/sensor/ambient_station.py diff --git a/homeassistant/components/sensor/aftership.py b/homeassistant/components/sensor/aftership.py new file mode 100644 index 0000000000000000000000000000000000000000..eb5188a95cb869c39508e4edfa8d11c7fc33ac81 --- /dev/null +++ b/homeassistant/components/sensor/aftership.py @@ -0,0 +1,128 @@ +""" +Support for non-delivered packages recorded in AfterShip. + +For more details about this platform, please refer to the documentation at +https://www.home-assistant.io/components/sensor.aftership/ +""" +from datetime import timedelta +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME +from homeassistant.helpers.aiohttp_client import async_get_clientsession +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +REQUIREMENTS = ['pyaftership==0.1.2'] + +_LOGGER = logging.getLogger(__name__) + +ATTRIBUTION = 'Information provided by AfterShip' + +CONF_SLUG = 'slug' +CONF_TITLE = 'title' +CONF_TRACKING_NUMBER = 'tracking_number' + +DEFAULT_NAME = 'aftership' + +ICON = 'mdi:package-variant-closed' + +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_API_KEY): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): + """Set up the AfterShip sensor platform.""" + from pyaftership.tracker import Tracking + + apikey = config[CONF_API_KEY] + name = config[CONF_NAME] + + session = async_get_clientsession(hass) + aftership = Tracking(hass.loop, session, apikey) + + await aftership.get_trackings() + + if not aftership.meta or aftership.meta['code'] != 200: + _LOGGER.error("No tracking data found. Check API key is correct: %s", + aftership.meta) + return + + async_add_entities([AfterShipSensor(aftership, name)], True) + + +class AfterShipSensor(Entity): + """Representation of a AfterShip sensor.""" + + def __init__(self, aftership, name): + """Initialize the sensor.""" + self._attributes = {} + self._name = name + self._state = None + self.aftership = aftership + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + return 'packages' + + @property + def device_state_attributes(self): + """Return attributes for the sensor.""" + return self._attributes + + @property + def icon(self): + """Icon to use in the frontend.""" + return ICON + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + async def async_update(self): + """Get the latest data from the AfterShip API.""" + await self.aftership.get_trackings() + + if not self.aftership.meta: + _LOGGER.error("Unknown errors when querying") + return + if self.aftership.meta['code'] != 200: + _LOGGER.error( + "Errors when querying AfterShip. %s", str(self.aftership.meta)) + return + + status_to_ignore = {'delivered'} + status_counts = {} + not_delivered_count = 0 + + for tracking in self.aftership.trackings['trackings']: + status = tracking['tag'].lower() + name = tracking['tracking_number'] + status_counts[status] = status_counts.get(status, 0)+1 + if status not in status_to_ignore: + not_delivered_count += 1 + else: + _LOGGER.debug("Ignoring %s as it has status: %s", name, status) + + self._attributes = { + ATTR_ATTRIBUTION: ATTRIBUTION, + **status_counts + } + + self._state = not_delivered_count diff --git a/requirements_all.txt b/requirements_all.txt index ec85e22da17dccfafb28dde31566d6b893314d61..412b274b08f5023c161752a50c39622725e707db 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -881,6 +881,9 @@ pyW800rf32==0.1 # homeassistant.components.ads pyads==2.2.6 +# homeassistant.components.sensor.aftership +pyaftership==0.1.2 + # homeassistant.components.sensor.airvisual pyairvisual==2.0.1