Refactor USPS into component with Sensors+Camera (#8679)
* Inital USPS Camera expansion * Cleanup debugging, add camera change interval * Change to local nomail image * Explicitly pass in date * Move camera date info to model property * Fix copy typo * Fix hound line-length * Fix lint whitespace * Fix requirements * Bump myusps version, clarify interval, alter update scheme * Add units * Code cleanup, address comments * Use built-in scan interval, remove nomail image * Remove logging line
This commit is contained in:
parent
6215e27de4
commit
ecc249aa27
5 changed files with 226 additions and 50 deletions
|
@ -176,6 +176,9 @@ omit =
|
|||
homeassistant/components/notify/twilio_sms.py
|
||||
homeassistant/components/notify/twilio_call.py
|
||||
|
||||
homeassistant/components/usps.py
|
||||
homeassistant/components/*/usps.py
|
||||
|
||||
homeassistant/components/velbus.py
|
||||
homeassistant/components/*/velbus.py
|
||||
|
||||
|
@ -519,7 +522,6 @@ omit =
|
|||
homeassistant/components/sensor/uber.py
|
||||
homeassistant/components/sensor/upnp.py
|
||||
homeassistant/components/sensor/ups.py
|
||||
homeassistant/components/sensor/usps.py
|
||||
homeassistant/components/sensor/vasttrafik.py
|
||||
homeassistant/components/sensor/waqi.py
|
||||
homeassistant/components/sensor/xbox_live.py
|
||||
|
|
94
homeassistant/components/camera/usps.py
Normal file
94
homeassistant/components/camera/usps.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
"""
|
||||
Support for a camera made up of usps mail images.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/camera.usps/
|
||||
"""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from homeassistant.components.camera import Camera
|
||||
from homeassistant.components.usps import DATA_USPS
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['usps']
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=10)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up USPS mail camera."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
usps = hass.data[DATA_USPS]
|
||||
add_devices([USPSCamera(usps)])
|
||||
|
||||
|
||||
class USPSCamera(Camera):
|
||||
"""Representation of the images available from USPS."""
|
||||
|
||||
def __init__(self, usps):
|
||||
"""Initialize the USPS camera images."""
|
||||
super().__init__()
|
||||
|
||||
self._usps = usps
|
||||
self._name = self._usps.name
|
||||
self._session = self._usps.session
|
||||
|
||||
self._mail_img = []
|
||||
self._last_mail = None
|
||||
self._mail_index = 0
|
||||
self._mail_count = 0
|
||||
|
||||
self._timer = None
|
||||
|
||||
def camera_image(self):
|
||||
"""Update the camera's image if it has changed."""
|
||||
self._usps.update()
|
||||
try:
|
||||
self._mail_count = len(self._usps.mail)
|
||||
except TypeError:
|
||||
# No mail
|
||||
return None
|
||||
|
||||
if self._usps.mail != self._last_mail:
|
||||
# Mail items must have changed
|
||||
self._mail_img = []
|
||||
if len(self._usps.mail) >= 1:
|
||||
self._last_mail = self._usps.mail
|
||||
for article in self._usps.mail:
|
||||
_LOGGER.debug("Fetching article image: %s", article)
|
||||
img = self._session.get(article['image']).content
|
||||
self._mail_img.append(img)
|
||||
|
||||
try:
|
||||
return self._mail_img[self._mail_index]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of this camera."""
|
||||
return '{} mail'.format(self._name)
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
"""Return date of mail as model."""
|
||||
try:
|
||||
return 'Date: {}'.format(self._usps.mail[0]['date'])
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Update the mail image index periodically."""
|
||||
return True
|
||||
|
||||
def update(self):
|
||||
"""Update mail image index."""
|
||||
if self._mail_index < (self._mail_count - 1):
|
||||
self._mail_index += 1
|
||||
else:
|
||||
self._mail_index = 0
|
|
@ -6,65 +6,44 @@ https://home-assistant.io/components/sensor.usps/
|
|||
"""
|
||||
from collections import defaultdict
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||
from homeassistant.const import (CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
|
||||
ATTR_ATTRIBUTION)
|
||||
from homeassistant.components.usps import DATA_USPS
|
||||
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_DATE
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.util import slugify
|
||||
from homeassistant.util.dt import now, parse_datetime
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['myusps==1.1.2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'usps'
|
||||
SCAN_INTERVAL = timedelta(minutes=30)
|
||||
COOKIE = 'usps_cookies.pickle'
|
||||
DEPENDENCIES = ['usps']
|
||||
|
||||
STATUS_DELIVERED = 'delivered'
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_NAME): cv.string
|
||||
})
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Setup the USPS platform."""
|
||||
import myusps
|
||||
try:
|
||||
cookie = hass.config.path(COOKIE)
|
||||
session = myusps.get_session(
|
||||
config.get(CONF_USERNAME), config.get(CONF_PASSWORD),
|
||||
cookie_path=cookie)
|
||||
except myusps.USPSError:
|
||||
_LOGGER.exception('Could not connect to My USPS')
|
||||
return False
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
add_devices([USPSPackageSensor(session, config.get(CONF_NAME)),
|
||||
USPSMailSensor(session, config.get(CONF_NAME))], True)
|
||||
usps = hass.data[DATA_USPS]
|
||||
add_devices([USPSPackageSensor(usps),
|
||||
USPSMailSensor(usps)], True)
|
||||
|
||||
|
||||
class USPSPackageSensor(Entity):
|
||||
"""USPS Package Sensor."""
|
||||
|
||||
def __init__(self, session, name):
|
||||
def __init__(self, usps):
|
||||
"""Initialize the sensor."""
|
||||
self._session = session
|
||||
self._name = name
|
||||
self._usps = usps
|
||||
self._name = self._usps.name
|
||||
self._attributes = None
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return '{} packages'.format(self._name or DOMAIN)
|
||||
return '{} packages'.format(self._name)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -73,16 +52,16 @@ class USPSPackageSensor(Entity):
|
|||
|
||||
def update(self):
|
||||
"""Update device state."""
|
||||
import myusps
|
||||
self._usps.update()
|
||||
status_counts = defaultdict(int)
|
||||
for package in myusps.get_packages(self._session):
|
||||
for package in self._usps.packages:
|
||||
status = slugify(package['primary_status'])
|
||||
if status == STATUS_DELIVERED and \
|
||||
parse_datetime(package['date']).date() < now().date():
|
||||
continue
|
||||
status_counts[status] += 1
|
||||
self._attributes = {
|
||||
ATTR_ATTRIBUTION: myusps.ATTRIBUTION
|
||||
ATTR_ATTRIBUTION: self._usps.attribution
|
||||
}
|
||||
self._attributes.update(status_counts)
|
||||
self._state = sum(status_counts.values())
|
||||
|
@ -97,21 +76,26 @@ class USPSPackageSensor(Entity):
|
|||
"""Icon to use in the frontend."""
|
||||
return 'mdi:package-variant-closed'
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return 'packages'
|
||||
|
||||
|
||||
class USPSMailSensor(Entity):
|
||||
"""USPS Mail Sensor."""
|
||||
|
||||
def __init__(self, session, name):
|
||||
def __init__(self, usps):
|
||||
"""Initialize the sensor."""
|
||||
self._session = session
|
||||
self._name = name
|
||||
self._usps = usps
|
||||
self._name = self._usps.name
|
||||
self._attributes = None
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return '{} mail'.format(self._name or DOMAIN)
|
||||
return '{} mail'.format(self._name)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -120,18 +104,29 @@ class USPSMailSensor(Entity):
|
|||
|
||||
def update(self):
|
||||
"""Update device state."""
|
||||
import myusps
|
||||
self._state = len(myusps.get_mail(self._session))
|
||||
self._usps.update()
|
||||
if self._usps.mail is not None:
|
||||
self._state = len(self._usps.mail)
|
||||
else:
|
||||
self._state = 0
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
import myusps
|
||||
return {
|
||||
ATTR_ATTRIBUTION: myusps.ATTRIBUTION
|
||||
}
|
||||
attr = {}
|
||||
attr[ATTR_ATTRIBUTION] = self._usps.attribution
|
||||
try:
|
||||
attr[ATTR_DATE] = self._usps.mail[0]['date']
|
||||
except IndexError:
|
||||
pass
|
||||
return attr
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Icon to use in the frontend."""
|
||||
return 'mdi:mailbox'
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return 'pieces'
|
||||
|
|
85
homeassistant/components/usps.py
Normal file
85
homeassistant/components/usps.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
Support for USPS packages and mail.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/usps/
|
||||
"""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_USERNAME, CONF_PASSWORD)
|
||||
from homeassistant.helpers import (config_validation as cv, discovery)
|
||||
from homeassistant.util import Throttle
|
||||
from homeassistant.util.dt import now
|
||||
|
||||
REQUIREMENTS = ['myusps==1.1.3']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'usps'
|
||||
DATA_USPS = 'data_usps'
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30)
|
||||
COOKIE = 'usps_cookies.pickle'
|
||||
|
||||
USPS_TYPE = ['sensor', 'camera']
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DOMAIN): cv.string,
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Use config values to set up a function enabling status retrieval."""
|
||||
conf = config[DOMAIN]
|
||||
username = conf.get(CONF_USERNAME)
|
||||
password = conf.get(CONF_PASSWORD)
|
||||
name = conf.get(CONF_NAME)
|
||||
|
||||
import myusps
|
||||
try:
|
||||
cookie = hass.config.path(COOKIE)
|
||||
session = myusps.get_session(username, password, cookie_path=cookie)
|
||||
except myusps.USPSError:
|
||||
_LOGGER.exception('Could not connect to My USPS')
|
||||
return False
|
||||
|
||||
hass.data[DATA_USPS] = USPSData(session, name)
|
||||
|
||||
for component in USPS_TYPE:
|
||||
discovery.load_platform(hass, component, DOMAIN, {}, config)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class USPSData(object):
|
||||
"""Stores the data retrieved from USPS.
|
||||
|
||||
For each entity to use, acts as the single point responsible for fetching
|
||||
updates from the server.
|
||||
"""
|
||||
|
||||
def __init__(self, session, name):
|
||||
"""Initialize the data oject."""
|
||||
self.session = session
|
||||
self.name = name
|
||||
self.packages = []
|
||||
self.mail = []
|
||||
self.attribution = None
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
def update(self, **kwargs):
|
||||
"""Fetch the latest info from USPS."""
|
||||
import myusps
|
||||
self.packages = myusps.get_packages(self.session)
|
||||
self.mail = myusps.get_mail(self.session, now().date())
|
||||
self.attribution = myusps.ATTRIBUTION
|
||||
_LOGGER.debug("Mail, request date: %s, list: %s",
|
||||
now().date(), self.mail)
|
||||
_LOGGER.debug("Package list: %s", self.packages)
|
|
@ -412,8 +412,8 @@ miniupnpc==1.9
|
|||
# homeassistant.components.tts
|
||||
mutagen==1.38
|
||||
|
||||
# homeassistant.components.sensor.usps
|
||||
myusps==1.1.2
|
||||
# homeassistant.components.usps
|
||||
myusps==1.1.3
|
||||
|
||||
# homeassistant.components.media_player.nad
|
||||
# homeassistant.components.media_player.nadtcp
|
||||
|
|
Loading…
Add table
Reference in a new issue