Skip to content

Commit

Permalink
Add AfterShip sensor for packages
Browse files Browse the repository at this point in the history
Why:

 * I receive a lot of packages from many different shipping companies.
 * I would like to see in haas how many packages are being delivered.

This change addreses the need by:

 * Adding a sensor for AfterShip (aftership.com)
 * AfterShip supports ~490 couriers world wide thus should cover
   almost any sensible tracking.

Notes:
  - For now this sensor assumes you somehow have added trackings to
    aftership manually.
  - Future idea is to expose service that allows adding a tracking
    based on incoming mails.
  - Other improvments would be to add map markers for package locations.

Related:
- https://community.home-assistant.io/t/package-tracking/858
- https://community.home-assistant.io/t/aftership-package-tracking/24068
- https://community.home-assistant.io/t/aftership-shipment-tracking-platform/14074
- https://community.home-assistant.io/t/aftership-state-card/57912
  • Loading branch information
maxandersen committed Nov 27, 2018
1 parent 145677e commit 25cb2fb
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 0 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,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/arest.py
Expand Down
161 changes: 161 additions & 0 deletions homeassistant/components/sensor/aftership.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
"""
Sensor for AfterShip.
Gives a sensor of all non-delivered packages recorded in AfterShip.
Requires an api key which can be aquired from
https://secure.aftership.com/#/settings/api.
Example configuration:
sensor:
- platform: aftership
api_key: AFTERSHIP_API_KEY
"""
from datetime import timedelta
import logging

import voluptuous as vol

from homeassistant.components.sensor import (DOMAIN, PLATFORM_SCHEMA)

from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME)

import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
from homeassistant.exceptions import PlatformNotReady

REQUIREMENTS = ['pyaftership==0.0.5']

_LOGGER = logging.getLogger(__name__)

ATTRIBUTION = 'Information provided by AfterShip'

DEFAULT_NAME = 'aftership'

TITLE = 'title'
SLUG = 'slug'
TRACKING_NUMBER = 'tracking_number'

ICON = 'mdi:package-variant-closed'

MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30)

SERVICE_NEW_TRACKING = 'aftership_new_tracking'

NEW_TRACKING_SERVICE_SCHEMA = vol.Schema({
vol.Required(TITLE): cv.string,
vol.Required(SLUG): cv.string,
vol.Required(TRACKING_NUMBER): cv.string,
})

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

_LOGGER = logging.getLogger(__name__)

def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the AfterShip sensor platform."""
from pyaftership import AfterShip

apikey = config.get(CONF_API_KEY)
name = config.get(CONF_NAME)

## todo: pyaftership hides api-key errors. For now just warn if result is empty
result = AfterShip().get_trackings(apikey)

if not result['success']:
_LOGGER.warn("Connection error for AfterShip during startup. Could just be intermittent.")
raise PlatformNotReady
elif not result['data']:
_LOGGER.error("No tracking data found. Check AfterShip API key is correct")
return

add_entities([AfterShipSensor(apikey, name)], True)

def handle_new_tracking(call):
"""Call when a user creates a new Afterhip tracking from HASS."""
from pyaftership import AfterShip
title = call.data[TITLE]
slug = call.data[SLUG]
tracking_number = call.data[TRACKING_NUMBER]

_aftership = AfterShip()
result = _aftership.add_tracking(apikey, slug, title, tracking_number)

if not result['success']:
_LOGGER.debug("Created Aftership tracking")
else:
_LOGGER.error("Failed to create new tracking")

hass.services.register(DOMAIN, SERVICE_NEW_TRACKING, handle_new_tracking,
schema=NEW_TRACKING_SERVICE_SCHEMA)


class AfterShipSensor(Entity):
"""Representation of a AfterShip sensor."""

def __init__(self, apikey, name):
"""Initialize the AfterShip sensor."""
from pyaftership import AfterShip
self._name = name
self._attributes = None
self._state = None
self._api = AfterShip()
self._apikey = apikey

@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 the state attributes."""
return self._attributes

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

@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Update device state."""
from pyaftership import AfterShip

status_to_ignore = { 'Delivered' }
trackingstop = self._api.get_trackings(self._apikey)
status_counts = {}
not_delivered_count = 0

for tracking in trackingstop['data']['trackings']:
status = tracking['tag']
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

3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ abodepy==0.14.0
# homeassistant.components.media_player.frontier_silicon
afsapi==0.0.4

# homeassistant.components.sensor.aftership
pyaftership==0.0.5

# homeassistant.components.device_tracker.asuswrt
aioasuswrt==1.1.2

Expand Down

0 comments on commit 25cb2fb

Please sign in to comment.