Netatmo Presence (#5122)

* Netatmo Presence

* Travis

* Remove def camera_stream
This commit is contained in:
Giel Janssens 2017-01-17 08:10:18 +01:00 committed by Paulus Schoutsen
parent fd5c2ad08f
commit c72f8b1a06
4 changed files with 160 additions and 71 deletions

View File

@ -1,19 +1,19 @@
"""
Support for the Netatmo binary sensors.
The binary sensors based on events seen by the NetatmoCamera
The binary sensors based on events seen by the Netatmo cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.netatmo/
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.components.netatmo import CameraData
from homeassistant.loader import get_component
from homeassistant.const import CONF_MONITORED_CONDITIONS, CONF_TIMEOUT
from homeassistant.const import CONF_TIMEOUT, CONF_OFFSET
from homeassistant.helpers import config_validation as cv
DEPENDENCIES = ["netatmo"]
@ -22,24 +22,37 @@ _LOGGER = logging.getLogger(__name__)
# These are the available sensors mapped to binary_sensor class
SENSOR_TYPES = {
"Someone known": 'occupancy',
"Someone unknown": 'motion',
"Motion": 'motion',
WELCOME_SENSOR_TYPES = {
"Someone known": "motion",
"Someone unknown": "motion",
"Motion": "motion",
"Tag Vibration": 'vibration',
"Tag Open": 'opening',
"Tag Open": 'opening'
}
PRESENCE_SENSOR_TYPES = {
"Outdoor motion": "motion",
"Outdoor human": "motion",
"Outdoor animal": "motion",
"Outdoor vehicle": "motion"
}
CONF_HOME = 'home'
CONF_CAMERAS = 'cameras'
CONF_WELCOME_SENSORS = 'welcome_sensors'
CONF_PRESENCE_SENSORS = 'presence_sensors'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOME): cv.string,
vol.Optional(CONF_TIMEOUT): cv.positive_int,
vol.Optional(CONF_OFFSET): cv.positive_int,
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)]),
vol.Optional(
CONF_WELCOME_SENSORS, default=WELCOME_SENSOR_TYPES.keys()):
vol.All(cv.ensure_list, [vol.In(WELCOME_SENSOR_TYPES)]),
vol.Optional(
CONF_PRESENCE_SENSORS, default=PRESENCE_SENSOR_TYPES.keys()):
vol.All(cv.ensure_list, [vol.In(PRESENCE_SENSOR_TYPES)]),
})
@ -49,48 +62,68 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
netatmo = get_component('netatmo')
home = config.get(CONF_HOME, None)
timeout = config.get(CONF_TIMEOUT, 15)
offset = config.get(CONF_OFFSET, 90)
module_name = None
import lnetatmo
try:
data = WelcomeData(netatmo.NETATMO_AUTH, home)
data = CameraData(netatmo.NETATMO_AUTH, home)
if data.get_camera_names() == []:
return None
except lnetatmo.NoDevice:
return None
sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES)
welcome_sensors = config.get(
CONF_WELCOME_SENSORS, WELCOME_SENSOR_TYPES)
presence_sensors = config.get(
CONF_PRESENCE_SENSORS, PRESENCE_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:
if variable in ('Tag Vibration', 'Tag Open'):
continue
add_devices([WelcomeBinarySensor(data, camera_name, module_name,
home, timeout, variable)])
camera_type = data.get_camera_type(camera=camera_name, home=home)
if camera_type == "NACamera":
if CONF_CAMERAS in config:
if config[CONF_CAMERAS] != [] and \
camera_name not in config[CONF_CAMERAS]:
continue
for variable in welcome_sensors:
add_devices([NetatmoBinarySensor(data, camera_name,
module_name, home, timeout,
offset, camera_type,
variable)])
if camera_type == "NOC":
if CONF_CAMERAS in config:
if config[CONF_CAMERAS] != [] and \
camera_name not in config[CONF_CAMERAS]:
continue
for variable in presence_sensors:
add_devices([NetatmoBinarySensor(data, camera_name,
module_name, home, timeout,
offset, camera_type,
variable)])
for module_name in data.get_module_names(camera_name):
for variable in sensors:
for variable in welcome_sensors:
if variable in ('Tag Vibration', 'Tag Open'):
add_devices([WelcomeBinarySensor(data, camera_name,
add_devices([NetatmoBinarySensor(data, camera_name,
module_name, home,
timeout, variable)])
timeout, offset,
camera_type,
variable)])
class WelcomeBinarySensor(BinarySensorDevice):
"""Represent a single binary sensor in a Netatmo Welcome device."""
class NetatmoBinarySensor(BinarySensorDevice):
"""Represent a single binary sensor in a Netatmo Camera device."""
def __init__(self, data, camera_name, module_name, home, timeout, sensor):
def __init__(self, data, camera_name, module_name, home,
timeout, offset, camera_type, sensor):
"""Setup for access to the Netatmo camera events."""
self._data = data
self._camera_name = camera_name
self._module_name = module_name
self._home = home
self._timeout = timeout
self._offset = offset
if home:
self._name = home + ' / ' + camera_name
else:
@ -99,10 +132,11 @@ class WelcomeBinarySensor(BinarySensorDevice):
self._name += ' / ' + module_name
self._sensor_name = sensor
self._name += ' ' + sensor
camera_id = data.welcomedata.cameraByName(camera=camera_name,
camera_id = data.camera_data.cameraByName(camera=camera_name,
home=home)['id']
self._unique_id = "Welcome_binary_sensor {0} - {1}".format(self._name,
self._unique_id = "Netatmo_binary_sensor {0} - {1}".format(self._name,
camera_id)
self._cameratype = camera_type
self.update()
@property
@ -118,7 +152,12 @@ class WelcomeBinarySensor(BinarySensorDevice):
@property
def sensor_class(self):
"""Return the class of this sensor, from SENSOR_CLASSES."""
return SENSOR_TYPES.get(self._sensor_name)
if self._cameratype == "NACamera":
return WELCOME_SENSOR_TYPES.get(self._sensor_name)
elif self._cameratype == "NOC":
return PRESENCE_SENSOR_TYPES.get(self._sensor_name)
else:
return None
@property
def is_on(self):
@ -130,30 +169,54 @@ class WelcomeBinarySensor(BinarySensorDevice):
self._data.update()
self._data.update_event()
if self._sensor_name == "Someone known":
self._state =\
self._data.welcomedata.someoneKnownSeen(self._home,
if self._cameratype == "NACamera":
if self._sensor_name == "Someone known":
self._state =\
self._data.camera_data.someoneKnownSeen(self._home,
self._camera_name,
self._timeout*60)
elif self._sensor_name == "Someone unknown":
self._state =\
self._data.welcomedata.someoneUnknownSeen(self._home,
elif self._sensor_name == "Someone unknown":
self._state =\
self._data.camera_data.someoneUnknownSeen(
self._home, self._camera_name, self._timeout*60)
elif self._sensor_name == "Motion":
self._state =\
self._data.camera_data.motionDetected(self._home,
self._camera_name,
self._timeout*60)
elif self._sensor_name == "Motion":
self._state =\
self._data.welcomedata.motionDetected(self._home,
self._camera_name,
self._timeout*60)
else:
return None
elif self._cameratype == "NOC":
if self._sensor_name == "Outdoor motion":
self._state =\
self._data.camera_data.outdoormotionDetected(
self._home, self._camera_name, self._offset)
elif self._sensor_name == "Outdoor human":
self._state =\
self._data.camera_data.humanDetected(self._home,
self._camera_name,
self._offset)
elif self._sensor_name == "Outdoor animal":
self._state =\
self._data.camera_data.animalDetected(self._home,
self._camera_name,
self._offset)
elif self._sensor_name == "Outdoor vehicle":
self._state =\
self._data.camera_data.carDetected(self._home,
self._camera_name,
self._offset)
else:
return None
elif self._sensor_name == "Tag Vibration":
self._state =\
self._data.welcomedata.moduleMotionDetected(self._home,
self._data.camera_data.moduleMotionDetected(self._home,
self._module_name,
self._camera_name,
self._timeout*60)
elif self._sensor_name == "Tag Open":
self._state =\
self._data.welcomedata.moduleOpened(self._home,
self._data.camera_data.moduleOpened(self._home,
self._module_name,
self._camera_name)
else:

View File

@ -1,15 +1,15 @@
"""
Support for the Netatmo Welcome camera.
Support for the Netatmo cameras.
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 requests
import voluptuous as vol
from homeassistant.components.netatmo import WelcomeData
from homeassistant.components.netatmo import CameraData
from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA)
from homeassistant.loader import get_component
from homeassistant.helpers import config_validation as cv
@ -30,41 +30,43 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup access to Netatmo Welcome cameras."""
"""Setup access to Netatmo cameras."""
netatmo = get_component('netatmo')
home = config.get(CONF_HOME)
import lnetatmo
try:
data = WelcomeData(netatmo.NETATMO_AUTH, home)
data = CameraData(netatmo.NETATMO_AUTH, home)
for camera_name in data.get_camera_names():
camera_type = data.get_camera_type(camera=camera_name, home=home)
if CONF_CAMERAS in config:
if config[CONF_CAMERAS] != [] and \
camera_name not in config[CONF_CAMERAS]:
continue
add_devices([WelcomeCamera(data, camera_name, home)])
add_devices([NetatmoCamera(data, camera_name, home, camera_type)])
except lnetatmo.NoDevice:
return None
class WelcomeCamera(Camera):
"""Representation of the images published from Welcome camera."""
class NetatmoCamera(Camera):
"""Representation of the images published from a Netatmo camera."""
def __init__(self, data, camera_name, home):
def __init__(self, data, camera_name, home, camera_type):
"""Setup for access to the Netatmo camera images."""
super(WelcomeCamera, self).__init__()
super(NetatmoCamera, self).__init__()
self._data = data
self._camera_name = camera_name
if home:
self._name = home + ' / ' + camera_name
else:
self._name = camera_name
camera_id = data.welcomedata.cameraByName(camera=camera_name,
camera_id = data.camera_data.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.camera_data.cameraUrls(
camera=camera_name
)
self._cameratype = camera_type
def camera_image(self):
"""Return a still image response from the camera."""
@ -79,15 +81,30 @@ class WelcomeCamera(Camera):
_LOGGER.error('Welcome VPN url changed: %s', error)
self._data.update()
(self._vpnurl, self._localurl) = \
self._data.welcomedata.cameraUrls(camera=self._camera_name)
self._data.camera_data.cameraUrls(camera=self._camera_name)
return None
return response.content
@property
def name(self):
"""Return the name of this Netatmo Welcome device."""
"""Return the name of this Netatmo camera device."""
return self._name
@property
def brand(self):
"""Camera brand."""
return "Netatmo"
@property
def model(self):
"""Camera model."""
if self._cameratype == "NOC":
return "Presence"
elif self._cameratype == "NACamera":
return "Welcome"
else:
return None
@property
def unique_id(self):
"""Return the unique ID for this sensor."""

View File

@ -18,7 +18,7 @@ from homeassistant.util import Throttle
REQUIREMENTS = [
'https://github.com/jabesq/netatmo-api-python/archive/'
'v0.8.1.zip#lnetatmo==0.8.1']
'v0.9.0.zip#lnetatmo==0.9.0']
_LOGGER = logging.getLogger(__name__)
@ -53,7 +53,8 @@ def setup(hass, config):
config[DOMAIN][CONF_API_KEY], config[DOMAIN][CONF_SECRET_KEY],
config[DOMAIN][CONF_USERNAME], config[DOMAIN][CONF_PASSWORD],
'read_station read_camera access_camera '
'read_thermostat write_thermostat')
'read_thermostat write_thermostat '
'read_presence access_presence')
except HTTPError:
_LOGGER.error("Unable to connect to Netatmo API")
return False
@ -65,27 +66,28 @@ def setup(hass, config):
return True
class WelcomeData(object):
class CameraData(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_data = None
self.camera_names = []
self.module_names = []
self.home = home
self.camera_type = None
def get_camera_names(self):
"""Return all camera 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():
for home in self.camera_data.cameras:
for camera in self.camera_data.cameras[home].values():
self.camera_names.append(camera['name'])
else:
for camera in self.welcomedata.cameras[self.home].values():
for camera in self.camera_data.cameras[self.home].values():
self.camera_names.append(camera['name'])
return self.camera_names
@ -93,20 +95,27 @@ class WelcomeData(object):
"""Return all module available on the API as a list."""
self.module_names = []
self.update()
cam_id = self.welcomedata.cameraByName(camera=camera_name,
cam_id = self.camera_data.cameraByName(camera=camera_name,
home=self.home)['id']
for module in self.welcomedata.modules.values():
for module in self.camera_data.modules.values():
if cam_id == module['cam_id']:
self.module_names.append(module['name'])
return self.module_names
def get_camera_type(self, camera=None, home=None, cid=None):
"""Return all module available on the API as a list."""
for camera_name in self.camera_names:
self.camera_type = self.camera_data.cameraType(camera_name)
return self.camera_type
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Call the Netatmo API to update the data."""
import lnetatmo
self.welcomedata = lnetatmo.WelcomeData(self.auth, size=100)
self.camera_data = lnetatmo.CameraData(self.auth, size=100)
@Throttle(MIN_TIME_BETWEEN_EVENT_UPDATES)
def update_event(self):
"""Call the Netatmo API to update the list of events."""
self.welcomedata.updateEvent(home=self.home)
"""Call the Netatmo API to update the events."""
self.camera_data.updateEvent(
home=self.home, cameratype=self.camera_type)

View File

@ -214,7 +214,7 @@ https://github.com/danieljkemp/onkyo-eiscp/archive/python3.zip#onkyo-eiscp==0.9.
# https://github.com/deisi/fritzconnection/archive/b5c14515e1c8e2652b06b6316a7f3913df942841.zip#fritzconnection==0.4.6
# homeassistant.components.netatmo
https://github.com/jabesq/netatmo-api-python/archive/v0.8.1.zip#lnetatmo==0.8.1
https://github.com/jabesq/netatmo-api-python/archive/v0.9.0.zip#lnetatmo==0.9.0
# homeassistant.components.neato
https://github.com/jabesq/pybotvac/archive/v0.0.1.zip#pybotvac==0.0.1