From 54a64fb8d914ee406cfcadd4ffcac24b07c0db91 Mon Sep 17 00:00:00 2001 From: John Arild Berentsen Date: Fri, 21 Oct 2016 22:41:17 +0200 Subject: [PATCH] Add support for verisure file camera. (#3952) --- homeassistant/components/camera/verisure.py | 102 ++++++++++++++++++++ homeassistant/components/verisure.py | 22 ++++- 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 homeassistant/components/camera/verisure.py diff --git a/homeassistant/components/camera/verisure.py b/homeassistant/components/camera/verisure.py new file mode 100644 index 00000000000..cc98dc5f363 --- /dev/null +++ b/homeassistant/components/camera/verisure.py @@ -0,0 +1,102 @@ +""" +Camera that loads a picture from a local file. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/camera.verisure/ +""" +import logging +import os + +from homeassistant.components.camera import Camera +from homeassistant.const import EVENT_HOMEASSISTANT_STOP +from homeassistant.components.verisure import HUB as hub +from homeassistant.components.verisure import CONF_SMARTCAM + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Camera.""" + if not int(hub.config.get(CONF_SMARTCAM, 1)): + return False + directory_path = hass.config.config_dir + if not os.access(directory_path, os.R_OK): + _LOGGER.error("file path %s is not readable", directory_path) + return False + hub.update_smartcam() + smartcams = [] + smartcams.extend([ + VerisureSmartcam(hass, value.deviceLabel, directory_path) + for value in hub.smartcam_status.values()]) + add_devices(smartcams) + + +class VerisureSmartcam(Camera): + """Local camera.""" + + def __init__(self, hass, device_id, directory_path): + """Initialize Verisure File Camera component.""" + super().__init__() + + self._device_id = device_id + self._directory_path = directory_path + self._image = None + self._image_id = None + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, + self.delete_image) + + def camera_image(self): + """Return image response.""" + self.check_imagelist() + if not self._image: + _LOGGER.debug('No image to display') + return + _LOGGER.debug('Trying to open %s', self._image) + with open(self._image, 'rb') as file: + return file.read() + + def check_imagelist(self): + """Check the contents of the image list.""" + hub.update_smartcam_imagelist() + if (self._device_id not in hub.smartcam_dict or + not hub.smartcam_dict[self._device_id]): + return + images = hub.smartcam_dict[self._device_id] + new_image_id = images[0] + _LOGGER.debug('self._device_id=%s, self._images=%s, ' + 'self._new_image_id=%s', self._device_id, + images, new_image_id) + if (new_image_id == '-1' or + self._image_id == new_image_id): + _LOGGER.debug('The image is the same, or loading image_id') + return + _LOGGER.debug('Download new image %s', new_image_id) + hub.my_pages.smartcam.download_image(self._device_id, + new_image_id, + self._directory_path) + if self._image_id: + _LOGGER.debug('Old image_id=%s', self._image_id) + self.delete_image(self) + + else: + _LOGGER.debug('No old image, only new %s', new_image_id) + + self._image_id = new_image_id + self._image = os.path.join(self._directory_path, + '{}{}'.format( + self._image_id, + '.jpg')) + + def delete_image(self, event): + """Delete an old image.""" + remove_image = os.path.join(self._directory_path, + '{}{}'.format( + self._image_id, + '.jpg')) + _LOGGER.debug('Deleting old image %s', remove_image) + os.remove(remove_image) + + @property + def name(self): + """Return the name of this camera.""" + return hub.smartcam_status[self._device_id].location diff --git a/homeassistant/components/verisure.py b/homeassistant/components/verisure.py index 878d9a8d6a2..0c760d899c8 100644 --- a/homeassistant/components/verisure.py +++ b/homeassistant/components/verisure.py @@ -27,7 +27,7 @@ CONF_LOCKS = 'locks' CONF_MOUSE = 'mouse' CONF_SMARTPLUGS = 'smartplugs' CONF_THERMOMETERS = 'thermometers' - +CONF_SMARTCAM = 'smartcam' DOMAIN = 'verisure' HUB = None @@ -43,6 +43,7 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_MOUSE, default=True): cv.boolean, vol.Optional(CONF_SMARTPLUGS, default=True): cv.boolean, vol.Optional(CONF_THERMOMETERS, default=True): cv.boolean, + vol.Optional(CONF_SMARTCAM, default=True): cv.boolean, }), }, extra=vol.ALLOW_EXTRA) @@ -55,7 +56,8 @@ def setup(hass, config): if not HUB.login(): return False - for component in ('sensor', 'switch', 'alarm_control_panel', 'lock'): + for component in ('sensor', 'switch', 'alarm_control_panel', 'lock', + 'camera'): discovery.load_platform(hass, component, DOMAIN, {}, config) return True @@ -72,6 +74,8 @@ class VerisureHub(object): self.climate_status = {} self.mouse_status = {} self.smartplug_status = {} + self.smartcam_status = {} + self.smartcam_dict = {} self.config = domain_config self._verisure = verisure @@ -133,6 +137,20 @@ class VerisureHub(object): self.my_pages.smartplug.get, self.smartplug_status) + @Throttle(timedelta(seconds=30)) + def update_smartcam(self): + """Update the status of the smartcam.""" + self.update_component( + self.my_pages.smartcam.get, + self.smartcam_status) + + @Throttle(timedelta(seconds=30)) + def update_smartcam_imagelist(self): + """Update the imagelist for the camera.""" + _LOGGER.debug('Running update imagelist') + self.smartcam_dict = self.my_pages.smartcam.get_imagelist() + _LOGGER.debug('New dict: %s', self.smartcam_dict) + @property def available(self): """Return True if hub is available."""