Netatmo binary sensor (#3455)

* Basic support for Netatmo welcome binary sensors

Signed-off-by: Hugo D. (jabesq) <jabesq@gmail.com>

* Bug fixes and optimization for Netatmo devices

Signed-off-by: Hugo D. (jabesq) <jabesq@gmail.com>

* pylint fixes

* Bug Fixing and optimization for Netatmo devices

Signed-off-by: Hugo D. (jabesq) <jabesq@gmail.com>

* Add unique_id for cameras to avoid duplicate
And global config to disable discovery for netatmo devices

Signed-off-by: Hugo D. (jabesq) <jabesq@gmail.com>
This commit is contained in:
Hugo Dupras 2016-10-09 17:45:12 +02:00 committed by Paulus Schoutsen
parent 154eacef6c
commit 1d0df63615
3 changed files with 180 additions and 37 deletions

View File

@ -0,0 +1,128 @@
"""
Support for the Netatmo binary sensors.
The binary sensors based on events seen by the NetatmoCamera
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.netatmo/
"""
import logging
import voluptuous as vol
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.components.netatmo import WelcomeData
from homeassistant.loader import get_component
from homeassistant.const import CONF_MONITORED_CONDITIONS
from homeassistant.helpers import config_validation as cv
DEPENDENCIES = ["netatmo"]
_LOGGER = logging.getLogger(__name__)
# These are the available sensors mapped to binary_sensor class
SENSOR_TYPES = {
"Someone known": "motion",
"Someone unknown": "motion",
"Motion": "motion",
}
CONF_HOME = 'home'
CONF_CAMERAS = 'cameras'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOME): cv.string,
vol.Optional(CONF_CAMERAS, default=[]):
vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_MONITORED_CONDITIONS, default=SENSOR_TYPES.keys()):
vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]),
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup access to Netatmo binary sensor."""
netatmo = get_component('netatmo')
home = config.get(CONF_HOME, None)
import lnetatmo
try:
data = WelcomeData(netatmo.NETATMO_AUTH, home)
except lnetatmo.NoDevice:
return None
if data.get_camera_names() == []:
return None
sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES)
for camera_name in data.get_camera_names():
if CONF_CAMERAS in config:
if config[CONF_CAMERAS] != [] and \
camera_name not in config[CONF_CAMERAS]:
continue
for variable in sensors:
add_devices([WelcomeBinarySensor(data, camera_name, home,
variable)])
class WelcomeBinarySensor(BinarySensorDevice):
"""Represent a single binary sensor in a Netatmo Welcome device."""
def __init__(self, data, camera_name, home, sensor):
"""Setup for access to the Netatmo camera events."""
self._data = data
self._camera_name = camera_name
self._home = home
if home:
self._name = home + ' / ' + camera_name
else:
self._name = camera_name
self._sensor_name = sensor
self._name += ' ' + sensor
camera_id = data.welcomedata.cameraByName(camera=camera_name,
home=home)['id']
self._unique_id = "Welcome_binary_sensor {0} - {1}".format(self._name,
camera_id)
self.update()
@property
def name(self):
"""The name of the Netatmo device and this sensor."""
return self._name
@property
def unique_id(self):
"""Return the unique ID for this sensor."""
return self._unique_id
@property
def sensor_class(self):
"""Return the class of this sensor, from SENSOR_CLASSES."""
return SENSOR_TYPES.get(self._sensor_name)
@property
def is_on(self):
"""Return true if binary sensor is on."""
return self._state
def update(self):
"""Request an update from the Netatmo API."""
self._data.update()
self._data.welcomedata.updateEvent(home=self._data.home)
if self._sensor_name == "Someone known":
self._state =\
self._data.welcomedata.someoneKnownSeen(self._home,
self._camera_name)
elif self._sensor_name == "Someone unknown":
self._state =\
self._data.welcomedata.someoneUnknownSeen(self._home,
self._camera_name)
elif self._sensor_name == "Motion":
self._state =\
self._data.welcomedata.motionDetected(self._home,
self._camera_name)
else:
return None

View File

@ -5,12 +5,11 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.netatmo/ https://home-assistant.io/components/camera.netatmo/
""" """
import logging import logging
from datetime import timedelta
import requests import requests
import voluptuous as vol import voluptuous as vol
from homeassistant.util import Throttle from homeassistant.components.netatmo import WelcomeData
from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA) from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA)
from homeassistant.loader import get_component from homeassistant.loader import get_component
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
@ -22,8 +21,6 @@ _LOGGER = logging.getLogger(__name__)
CONF_HOME = 'home' CONF_HOME = 'home'
CONF_CAMERAS = 'cameras' CONF_CAMERAS = 'cameras'
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOME): cv.string, vol.Optional(CONF_HOME): cv.string,
vol.Optional(CONF_CAMERAS, default=[]): vol.Optional(CONF_CAMERAS, default=[]):
@ -43,8 +40,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return None return None
for camera_name in data.get_camera_names(): for camera_name in data.get_camera_names():
if config[CONF_CAMERAS] != []: if CONF_CAMERAS in config:
if camera_name not in config[CONF_CAMERAS]: if config[CONF_CAMERAS] != [] and \
camera_name not in config[CONF_CAMERAS]:
continue continue
add_devices([WelcomeCamera(data, camera_name, home)]) add_devices([WelcomeCamera(data, camera_name, home)])
@ -61,6 +59,10 @@ class WelcomeCamera(Camera):
self._name = home + ' / ' + camera_name self._name = home + ' / ' + camera_name
else: else:
self._name = camera_name self._name = camera_name
camera_id = data.welcomedata.cameraByName(camera=camera_name,
home=home)['id']
self._unique_id = "Welcome_camera {0} - {1}".format(self._name,
camera_id)
self._vpnurl, self._localurl = self._data.welcomedata.cameraUrls( self._vpnurl, self._localurl = self._data.welcomedata.cameraUrls(
camera=camera_name camera=camera_name
) )
@ -87,31 +89,7 @@ class WelcomeCamera(Camera):
"""Return the name of this Netatmo Welcome device.""" """Return the name of this Netatmo Welcome device."""
return self._name return self._name
@property
class WelcomeData(object): def unique_id(self):
"""Get the latest data from NetAtmo.""" """Return the unique ID for this sensor."""
return self._unique_id
def __init__(self, auth, home=None):
"""Initialize the data object."""
self.auth = auth
self.welcomedata = None
self.camera_names = []
self.home = home
def get_camera_names(self):
"""Return all module available on the API as a list."""
self.update()
if not self.home:
for home in self.welcomedata.cameras:
for camera in self.welcomedata.cameras[home].values():
self.camera_names.append(camera['name'])
else:
for camera in self.welcomedata.cameras[self.home].values():
self.camera_names.append(camera['name'])
return self.camera_names
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Call the NetAtmo API to update the data."""
import lnetatmo
self.welcomedata = lnetatmo.WelcomeData(self.auth)

View File

@ -5,14 +5,16 @@ For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/netatmo/ https://home-assistant.io/components/netatmo/
""" """
import logging import logging
from datetime import timedelta
from urllib.error import HTTPError from urllib.error import HTTPError
import voluptuous as vol import voluptuous as vol
from homeassistant.const import ( from homeassistant.const import (
CONF_API_KEY, CONF_PASSWORD, CONF_USERNAME) CONF_API_KEY, CONF_PASSWORD, CONF_USERNAME, CONF_DISCOVERY)
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle
REQUIREMENTS = [ REQUIREMENTS = [
'https://github.com/jabesq/netatmo-api-python/archive/' 'https://github.com/jabesq/netatmo-api-python/archive/'
@ -25,6 +27,9 @@ CONF_SECRET_KEY = 'secret_key'
DOMAIN = 'netatmo' DOMAIN = 'netatmo'
NETATMO_AUTH = None NETATMO_AUTH = None
DEFAULT_DISCOVERY = True
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10)
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
@ -32,6 +37,7 @@ CONFIG_SCHEMA = vol.Schema({
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_SECRET_KEY): cv.string, vol.Required(CONF_SECRET_KEY): cv.string,
vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean,
}) })
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
@ -50,7 +56,38 @@ def setup(hass, config):
_LOGGER.error("Unable to connect to Netatmo API") _LOGGER.error("Unable to connect to Netatmo API")
return False return False
for component in 'camera', 'sensor': if config[DOMAIN][CONF_DISCOVERY]:
discovery.load_platform(hass, component, DOMAIN, {}, config) for component in 'camera', 'sensor', 'binary_sensor':
discovery.load_platform(hass, component, DOMAIN, {}, config)
return True return True
class WelcomeData(object):
"""Get the latest data from Netatmo."""
def __init__(self, auth, home=None):
"""Initialize the data object."""
self.auth = auth
self.welcomedata = None
self.camera_names = []
self.home = home
def get_camera_names(self):
"""Return all module available on the API as a list."""
self.camera_names = []
self.update()
if not self.home:
for home in self.welcomedata.cameras:
for camera in self.welcomedata.cameras[home].values():
self.camera_names.append(camera['name'])
else:
for camera in self.welcomedata.cameras[self.home].values():
self.camera_names.append(camera['name'])
return self.camera_names
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Call the Netatmo API to update the data."""
import lnetatmo
self.welcomedata = lnetatmo.WelcomeData(self.auth)