Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ omit =
homeassistant/components/light/yeelightsunflower.py
homeassistant/components/light/zengge.py
homeassistant/components/lirc.py
homeassistant/components/lock/kiwi.py
homeassistant/components/lock/lockitron.py
homeassistant/components/lock/nello.py
homeassistant/components/lock/nuki.py
Expand Down
57 changes: 30 additions & 27 deletions homeassistant/components/alarm_control_panel/arlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.arlo/
"""
import asyncio
import logging

import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.components.alarm_control_panel import (
AlarmControlPanel, PLATFORM_SCHEMA)
from homeassistant.components.arlo import (DATA_ARLO, CONF_ATTRIBUTION)
from homeassistant.components.arlo import (
DATA_ARLO, CONF_ATTRIBUTION, SIGNAL_UPDATE_ARLO)
from homeassistant.const import (
ATTR_ATTRIBUTION, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED)
Expand All @@ -36,21 +38,20 @@
})


@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Arlo Alarm Control Panels."""
data = hass.data[DATA_ARLO]
arlo = hass.data[DATA_ARLO]

if not data.base_stations:
if not arlo.base_stations:
return

home_mode_name = config.get(CONF_HOME_MODE_NAME)
away_mode_name = config.get(CONF_AWAY_MODE_NAME)
base_stations = []
for base_station in data.base_stations:
for base_station in arlo.base_stations:
base_stations.append(ArloBaseStation(base_station, home_mode_name,
away_mode_name))
async_add_devices(base_stations, True)
add_devices(base_stations, True)


class ArloBaseStation(AlarmControlPanel):
Expand All @@ -68,37 +69,39 @@ def icon(self):
"""Return icon."""
return ICON

async def async_added_to_hass(self):
"""Register callbacks."""
async_dispatcher_connect(
self.hass, SIGNAL_UPDATE_ARLO, self._update_callback)

@callback
def _update_callback(self):
"""Call update method."""
self.async_schedule_update_ha_state(True)

@property
def state(self):
"""Return the state of the device."""
return self._state

def update(self):
"""Update the state of the device."""
# PyArlo sometimes returns None for mode. So retry 3 times before
# returning None.
num_retries = 3
i = 0
while i < num_retries:
mode = self._base_station.mode
if mode:
self._state = self._get_state_from_mode(mode)
return
i += 1
self._state = None

@asyncio.coroutine
def async_alarm_disarm(self, code=None):
_LOGGER.debug("Updating Arlo Alarm Control Panel %s", self.name)
mode = self._base_station.mode
if mode:
self._state = self._get_state_from_mode(mode)
else:
self._state = None

async def async_alarm_disarm(self, code=None):
"""Send disarm command."""
self._base_station.mode = DISARMED

@asyncio.coroutine
def async_alarm_arm_away(self, code=None):
async def async_alarm_arm_away(self, code=None):
"""Send arm away command. Uses custom mode."""
self._base_station.mode = self._away_mode_name

@asyncio.coroutine
def async_alarm_arm_home(self, code=None):
async def async_alarm_arm_home(self, code=None):
"""Send arm home command. Uses custom mode."""
self._base_station.mode = self._home_mode_name

Expand All @@ -125,4 +128,4 @@ def _get_state_from_mode(self, mode):
return STATE_ALARM_ARMED_HOME
elif mode == self._away_mode_name:
return STATE_ALARM_ARMED_AWAY
return None
return mode
38 changes: 36 additions & 2 deletions homeassistant/components/arlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
https://home-assistant.io/components/arlo/
"""
import logging
from datetime import timedelta

import voluptuous as vol
from requests.exceptions import HTTPError, ConnectTimeout

from homeassistant.helpers import config_validation as cv
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
from homeassistant.const import (
CONF_USERNAME, CONF_PASSWORD, CONF_SCAN_INTERVAL)
from homeassistant.helpers.event import track_time_interval
from homeassistant.helpers.dispatcher import dispatcher_send

REQUIREMENTS = ['pyarlo==0.1.2']
REQUIREMENTS = ['pyarlo==0.1.6']

_LOGGER = logging.getLogger(__name__)

Expand All @@ -25,10 +29,16 @@
NOTIFICATION_ID = 'arlo_notification'
NOTIFICATION_TITLE = 'Arlo Component Setup'

SCAN_INTERVAL = timedelta(seconds=60)

SIGNAL_UPDATE_ARLO = "arlo_update"

CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL):
cv.time_period,
}),
}, extra=vol.ALLOW_EXTRA)

Expand All @@ -38,14 +48,25 @@ def setup(hass, config):
conf = config[DOMAIN]
username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD)
scan_interval = conf.get(CONF_SCAN_INTERVAL)

try:
from pyarlo import PyArlo

arlo = PyArlo(username, password, preload=False)
if not arlo.is_connected:
return False

# assign refresh period to base station thread
arlo_base_station = next((
station for station in arlo.base_stations), None)

if arlo_base_station is None:
return False

arlo_base_station.refresh_rate = scan_interval.total_seconds()
hass.data[DATA_ARLO] = arlo

except (ConnectTimeout, HTTPError) as ex:
_LOGGER.error("Unable to connect to Netgear Arlo: %s", str(ex))
hass.components.persistent_notification.create(
Expand All @@ -55,4 +76,17 @@ def setup(hass, config):
title=NOTIFICATION_TITLE,
notification_id=NOTIFICATION_ID)
return False

def hub_refresh(event_time):
"""Call ArloHub to refresh information."""
_LOGGER.info("Updating Arlo Hub component")
hass.data[DATA_ARLO].update(update_cameras=True,
update_base_station=True)
dispatcher_send(hass, SIGNAL_UPDATE_ARLO)

# register service
hass.services.register(DOMAIN, 'update', hub_refresh)

# register scan interval for ArloHub
track_time_interval(hass, hub_refresh, scan_interval)
return True
98 changes: 98 additions & 0 deletions homeassistant/components/binary_sensor/tahoma.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
Support for Tahoma binary sensors.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.tahoma/
"""

import logging
from datetime import timedelta

from homeassistant.components.binary_sensor import (
BinarySensorDevice)
from homeassistant.components.tahoma import (
DOMAIN as TAHOMA_DOMAIN, TahomaDevice)
from homeassistant.const import (STATE_OFF, STATE_ON, ATTR_BATTERY_LEVEL)

DEPENDENCIES = ['tahoma']

_LOGGER = logging.getLogger(__name__)

SCAN_INTERVAL = timedelta(seconds=120)


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up Tahoma controller devices."""
_LOGGER.debug("Setup Tahoma Binary sensor platform")
controller = hass.data[TAHOMA_DOMAIN]['controller']
devices = []
for device in hass.data[TAHOMA_DOMAIN]['devices']['smoke']:
devices.append(TahomaBinarySensor(device, controller))
add_devices(devices, True)


class TahomaBinarySensor(TahomaDevice, BinarySensorDevice):
"""Representation of a Tahoma Binary Sensor."""

def __init__(self, tahoma_device, controller):
"""Initialize the sensor."""
super().__init__(tahoma_device, controller)

self._state = None
self._icon = None
self._battery = None

@property
def is_on(self):
"""Return the state of the sensor."""
return bool(self._state == STATE_ON)

@property
def device_class(self):
"""Return the class of the device."""
if self.tahoma_device.type == 'rtds:RTDSSmokeSensor':
return 'smoke'
return None

@property
def icon(self):
"""Icon for device by its type."""
return self._icon

@property
def device_state_attributes(self):
"""Return the device state attributes."""
attr = {}
super_attr = super().device_state_attributes
if super_attr is not None:
attr.update(super_attr)

if self._battery is not None:
attr[ATTR_BATTERY_LEVEL] = self._battery
return attr

def update(self):
"""Update the state."""
self.controller.get_states([self.tahoma_device])
if self.tahoma_device.type == 'rtds:RTDSSmokeSensor':
if self.tahoma_device.active_states['core:SmokeState']\
== 'notDetected':
self._state = STATE_OFF
else:
self._state = STATE_ON

if 'core:SensorDefectState' in self.tahoma_device.active_states:
# Set to 'lowBattery' for low battery warning.
self._battery = self.tahoma_device.active_states[
'core:SensorDefectState']
else:
self._battery = None

if self._state == STATE_ON:
self._icon = "mdi:fire"
elif self._battery == 'lowBattery':
self._icon = "mdi:battery-alert"
else:
self._icon = None

_LOGGER.debug("Update %s, state: %s", self._name, self._state)
Loading