Merge remote-tracking branch 'refs/remotes/balloob/dev' into dev
commit
7823fb9788
|
@ -87,13 +87,21 @@ def setup(hass, config):
|
|||
lambda item: util.split_entity_id(item)[0])
|
||||
|
||||
for domain, ent_ids in by_domain:
|
||||
# We want to block for all calls and only return when all calls
|
||||
# have been processed. If a service does not exist it causes a 10
|
||||
# second delay while we're blocking waiting for a response.
|
||||
# But services can be registered on other HA instances that are
|
||||
# listening to the bus too. So as a in between solution, we'll
|
||||
# block only if the service is defined in the current HA instance.
|
||||
blocking = hass.services.has_service(domain, service.service)
|
||||
|
||||
# Create a new dict for this call
|
||||
data = dict(service.data)
|
||||
|
||||
# ent_ids is a generator, convert it to a list.
|
||||
data[ATTR_ENTITY_ID] = list(ent_ids)
|
||||
|
||||
hass.services.call(domain, service.service, data, True)
|
||||
hass.services.call(domain, service.service, data, blocking)
|
||||
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service)
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service)
|
||||
|
|
|
@ -67,7 +67,7 @@ class VerisureAlarm(alarm.AlarmControlPanel):
|
|||
self._state = STATE_ALARM_DISARMED
|
||||
elif verisure.ALARM_STATUS[self._id].status == 'armedhome':
|
||||
self._state = STATE_ALARM_ARMED_HOME
|
||||
elif verisure.ALARM_STATUS[self._id].status == 'armedaway':
|
||||
elif verisure.ALARM_STATUS[self._id].status == 'armed':
|
||||
self._state = STATE_ALARM_ARMED_AWAY
|
||||
elif verisure.ALARM_STATUS[self._id].status != 'pending':
|
||||
_LOGGER.error(
|
||||
|
|
|
@ -11,6 +11,7 @@ import logging
|
|||
|
||||
from homeassistant.const import HTTP_OK, HTTP_UNPROCESSABLE_ENTITY
|
||||
from homeassistant.util import template
|
||||
from homeassistant.helpers.service import call_from_config
|
||||
|
||||
DOMAIN = 'alexa'
|
||||
DEPENDENCIES = ['http']
|
||||
|
@ -23,6 +24,7 @@ API_ENDPOINT = '/api/alexa'
|
|||
CONF_INTENTS = 'intents'
|
||||
CONF_CARD = 'card'
|
||||
CONF_SPEECH = 'speech'
|
||||
CONF_ACTION = 'action'
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
|
@ -80,6 +82,7 @@ def _handle_alexa(handler, path_match, data):
|
|||
|
||||
speech = config.get(CONF_SPEECH)
|
||||
card = config.get(CONF_CARD)
|
||||
action = config.get(CONF_ACTION)
|
||||
|
||||
# pylint: disable=unsubscriptable-object
|
||||
if speech is not None:
|
||||
|
@ -89,6 +92,9 @@ def _handle_alexa(handler, path_match, data):
|
|||
response.add_card(CardType[card['type']], card['title'],
|
||||
card['content'])
|
||||
|
||||
if action is not None:
|
||||
call_from_config(handler.server.hass, action, True)
|
||||
|
||||
handler.write_json(response.as_dict())
|
||||
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ https://home-assistant.io/components/automation/
|
|||
import logging
|
||||
|
||||
from homeassistant.bootstrap import prepare_setup_platform
|
||||
from homeassistant.util import split_entity_id
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
from homeassistant.components import logbook
|
||||
from homeassistant.helpers.service import call_from_config
|
||||
|
||||
DOMAIN = 'automation'
|
||||
|
||||
|
@ -19,8 +19,6 @@ DEPENDENCIES = ['group']
|
|||
|
||||
CONF_ALIAS = 'alias'
|
||||
CONF_SERVICE = 'service'
|
||||
CONF_SERVICE_ENTITY_ID = 'entity_id'
|
||||
CONF_SERVICE_DATA = 'data'
|
||||
|
||||
CONF_CONDITION = 'condition'
|
||||
CONF_ACTION = 'action'
|
||||
|
@ -96,22 +94,7 @@ def _get_action(hass, config, name):
|
|||
_LOGGER.info('Executing %s', name)
|
||||
logbook.log_entry(hass, name, 'has been triggered', DOMAIN)
|
||||
|
||||
domain, service = split_entity_id(config[CONF_SERVICE])
|
||||
service_data = config.get(CONF_SERVICE_DATA, {})
|
||||
|
||||
if not isinstance(service_data, dict):
|
||||
_LOGGER.error("%s should be a dictionary", CONF_SERVICE_DATA)
|
||||
service_data = {}
|
||||
|
||||
if CONF_SERVICE_ENTITY_ID in config:
|
||||
try:
|
||||
service_data[ATTR_ENTITY_ID] = \
|
||||
config[CONF_SERVICE_ENTITY_ID].split(",")
|
||||
except AttributeError:
|
||||
service_data[ATTR_ENTITY_ID] = \
|
||||
config[CONF_SERVICE_ENTITY_ID]
|
||||
|
||||
hass.services.call(domain, service, service_data)
|
||||
call_from_config(hass, config)
|
||||
|
||||
return action
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ def setup_scanner(hass, config, see):
|
|||
location = ''
|
||||
if data['event'] == 'enter':
|
||||
|
||||
if data['desc'] == 'home':
|
||||
if data['desc'].lower() == 'home':
|
||||
location = STATE_HOME
|
||||
else:
|
||||
location = data['desc']
|
||||
|
|
|
@ -7,16 +7,15 @@ For more details about this platform, please refer to the documentation at
|
|||
https://home-assistant.io/components/light.vera/
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
|
||||
from requests.exceptions import RequestException
|
||||
from homeassistant.components.switch.vera import VeraSwitch
|
||||
|
||||
from homeassistant.components.light import ATTR_BRIGHTNESS
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, STATE_ON
|
||||
|
||||
REQUIREMENTS = ['pyvera==0.2.2']
|
||||
REQUIREMENTS = ['pyvera==0.2.3']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -59,7 +58,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
|||
|
||||
lights = []
|
||||
for device in devices:
|
||||
extra_data = device_data.get(device.deviceId, {})
|
||||
extra_data = device_data.get(device.device_id, {})
|
||||
exclude = extra_data.get('exclude', False)
|
||||
|
||||
if exclude is not True:
|
||||
|
@ -86,5 +85,5 @@ class VeraLight(VeraSwitch):
|
|||
else:
|
||||
self.vera_device.switch_on()
|
||||
|
||||
self.last_command_send = time.time()
|
||||
self.is_on_status = True
|
||||
self._state = STATE_ON
|
||||
self.update_ha_state()
|
||||
|
|
|
@ -20,7 +20,7 @@ from homeassistant.components.media_player import (
|
|||
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK,
|
||||
MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO)
|
||||
|
||||
REQUIREMENTS = ['pychromecast==0.6.13']
|
||||
REQUIREMENTS = ['pychromecast==0.6.14']
|
||||
CONF_IGNORE_CEC = 'ignore_cec'
|
||||
CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png'
|
||||
SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
|
||||
|
|
|
@ -35,7 +35,7 @@ SUPPORT_PLEX = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
|
|||
|
||||
|
||||
def config_from_file(filename, config=None):
|
||||
''' Small configuration file management function'''
|
||||
""" Small configuration file management function. """
|
||||
if config:
|
||||
# We're writing configuration
|
||||
try:
|
||||
|
@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
|||
|
||||
# pylint: disable=too-many-branches
|
||||
def setup_plexserver(host, token, hass, add_devices_callback):
|
||||
''' Setup a plexserver based on host parameter'''
|
||||
""" Setup a plexserver based on host parameter. """
|
||||
import plexapi.server
|
||||
import plexapi.exceptions
|
||||
|
||||
|
|
|
@ -149,9 +149,9 @@ class MQTT(object):
|
|||
}
|
||||
|
||||
if client_id is None:
|
||||
self._mqttc = mqtt.Client()
|
||||
self._mqttc = mqtt.Client(protocol=mqtt.MQTTv311)
|
||||
else:
|
||||
self._mqttc = mqtt.Client(client_id)
|
||||
self._mqttc = mqtt.Client(client_id, protocol=mqtt.MQTTv311)
|
||||
|
||||
self._mqttc.user_data_set(self.userdata)
|
||||
|
||||
|
|
|
@ -70,5 +70,8 @@ class EliqSensor(Entity):
|
|||
|
||||
def update(self):
|
||||
""" Gets the latest data. """
|
||||
response = self.api.get_data_now(channelid=self.channel_id)
|
||||
self._state = int(response.power)
|
||||
try:
|
||||
response = self.api.get_data_now(channelid=self.channel_id)
|
||||
self._state = int(response.power)
|
||||
except TypeError: # raised by eliqonline library on any HTTP error
|
||||
pass
|
||||
|
|
|
@ -13,14 +13,14 @@ from homeassistant.util import Throttle
|
|||
from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
REQUIREMENTS = ['pyowm==2.2.1']
|
||||
REQUIREMENTS = ['pyowm==2.3.0']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SENSOR_TYPES = {
|
||||
'weather': ['Condition', ''],
|
||||
'temperature': ['Temperature', ''],
|
||||
'wind_speed': ['Wind speed', 'm/s'],
|
||||
'humidity': ['Humidity', '%'],
|
||||
'pressure': ['Pressure', 'hPa'],
|
||||
'pressure': ['Pressure', 'mbar'],
|
||||
'clouds': ['Cloud coverage', '%'],
|
||||
'rain': ['Rain', 'mm'],
|
||||
'snow': ['Snow', 'mm']
|
||||
|
|
|
@ -15,7 +15,7 @@ from homeassistant.const import (
|
|||
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
|
||||
TEMP_CELCIUS, TEMP_FAHRENHEIT, EVENT_HOMEASSISTANT_STOP)
|
||||
|
||||
REQUIREMENTS = ['pyvera==0.2.2']
|
||||
REQUIREMENTS = ['pyvera==0.2.3']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -56,7 +56,7 @@ def get_devices(hass, config):
|
|||
|
||||
vera_sensors = []
|
||||
for device in devices:
|
||||
extra_data = device_data.get(device.deviceId, {})
|
||||
extra_data = device_data.get(device.device_id, {})
|
||||
exclude = extra_data.get('exclude', False)
|
||||
|
||||
if exclude is not True:
|
||||
|
@ -85,18 +85,14 @@ class VeraSensor(Entity):
|
|||
self.current_value = ''
|
||||
self._temperature_units = None
|
||||
|
||||
self.controller.register(vera_device)
|
||||
self.controller.on(
|
||||
vera_device, self._update_callback)
|
||||
self.controller.register(vera_device, self._update_callback)
|
||||
|
||||
def _update_callback(self, _device):
|
||||
""" Called by the vera device callback to update state. """
|
||||
_LOGGER.info(
|
||||
'Subscription update for %s', self.name)
|
||||
self.update_ha_state(True)
|
||||
|
||||
def __str__(self):
|
||||
return "%s %s %s" % (self.name, self.vera_device.deviceId, self.state)
|
||||
return "%s %s %s" % (self.name, self.vera_device.device_id, self.state)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -119,18 +115,18 @@ class VeraSensor(Entity):
|
|||
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
|
||||
|
||||
if self.vera_device.is_armable:
|
||||
armed = self.vera_device.refresh_value('Armed')
|
||||
armed = self.vera_device.get_value('Armed')
|
||||
attr[ATTR_ARMED] = 'True' if armed == '1' else 'False'
|
||||
|
||||
if self.vera_device.is_trippable:
|
||||
last_tripped = self.vera_device.refresh_value('LastTrip')
|
||||
last_tripped = self.vera_device.get_value('LastTrip')
|
||||
if last_tripped is not None:
|
||||
utc_time = dt_util.utc_from_timestamp(int(last_tripped))
|
||||
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
|
||||
utc_time)
|
||||
else:
|
||||
attr[ATTR_LAST_TRIP_TIME] = None
|
||||
tripped = self.vera_device.refresh_value('Tripped')
|
||||
tripped = self.vera_device.get_value('Tripped')
|
||||
attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False'
|
||||
|
||||
attr['Vera Device Id'] = self.vera_device.vera_device_id
|
||||
|
@ -143,7 +139,6 @@ class VeraSensor(Entity):
|
|||
|
||||
def update(self):
|
||||
if self.vera_device.category == "Temperature Sensor":
|
||||
self.vera_device.refresh_value('CurrentTemperature')
|
||||
current_temp = self.vera_device.get_value('CurrentTemperature')
|
||||
vera_temp_units = self.vera_device.veraController.temperature_units
|
||||
|
||||
|
@ -161,10 +156,9 @@ class VeraSensor(Entity):
|
|||
|
||||
self.current_value = current_temp
|
||||
elif self.vera_device.category == "Light Sensor":
|
||||
self.vera_device.refresh_value('CurrentLevel')
|
||||
self.current_value = self.vera_device.get_value('CurrentLevel')
|
||||
elif self.vera_device.category == "Sensor":
|
||||
tripped = self.vera_device.refresh_value('Tripped')
|
||||
tripped = self.vera_device.get_value('Tripped')
|
||||
self.current_value = 'Tripped' if tripped == '1' else 'Not Tripped'
|
||||
else:
|
||||
self.current_value = 'Unknown'
|
||||
|
|
|
@ -25,7 +25,7 @@ SENSOR_TYPES = {
|
|||
'precipitation': ['Condition', 'mm'],
|
||||
'temperature': ['Temperature', '°C'],
|
||||
'windSpeed': ['Wind speed', 'm/s'],
|
||||
'pressure': ['Pressure', 'hPa'],
|
||||
'pressure': ['Pressure', 'mbar'],
|
||||
'windDirection': ['Wind direction', '°'],
|
||||
'humidity': ['Humidity', '%'],
|
||||
'fog': ['Fog', '%'],
|
||||
|
|
|
@ -7,19 +7,21 @@ For more details about this platform, please refer to the documentation at
|
|||
https://home-assistant.io/components/switch.vera/
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
from requests.exceptions import RequestException
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
from homeassistant.const import (
|
||||
ATTR_BATTERY_LEVEL,
|
||||
ATTR_TRIPPED,
|
||||
ATTR_ARMED,
|
||||
ATTR_LAST_TRIP_TIME,
|
||||
EVENT_HOMEASSISTANT_STOP)
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
STATE_ON,
|
||||
STATE_OFF)
|
||||
|
||||
REQUIREMENTS = ['pyvera==0.2.2']
|
||||
REQUIREMENTS = ['pyvera==0.2.3']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -60,7 +62,7 @@ def get_devices(hass, config):
|
|||
|
||||
vera_switches = []
|
||||
for device in devices:
|
||||
extra_data = device_data.get(device.deviceId, {})
|
||||
extra_data = device_data.get(device.device_id, {})
|
||||
exclude = extra_data.get('exclude', False)
|
||||
|
||||
if exclude is not True:
|
||||
|
@ -75,7 +77,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||
add_devices(get_devices(hass, config))
|
||||
|
||||
|
||||
class VeraSwitch(ToggleEntity):
|
||||
class VeraSwitch(SwitchDevice):
|
||||
""" Represents a Vera Switch. """
|
||||
|
||||
def __init__(self, vera_device, controller, extra_data=None):
|
||||
|
@ -86,19 +88,17 @@ class VeraSwitch(ToggleEntity):
|
|||
self._name = self.extra_data.get('name')
|
||||
else:
|
||||
self._name = self.vera_device.name
|
||||
self.is_on_status = False
|
||||
# for debouncing status check after command is sent
|
||||
self.last_command_send = 0
|
||||
self._state = STATE_OFF
|
||||
|
||||
self.controller.register(vera_device)
|
||||
self.controller.on(
|
||||
vera_device, self._update_callback)
|
||||
self.controller.register(vera_device, self._update_callback)
|
||||
|
||||
def _update_callback(self, _device):
|
||||
""" Called by the vera device callback to update state. """
|
||||
_LOGGER.info(
|
||||
'Subscription update for %s', self.name)
|
||||
self.update_ha_state(True)
|
||||
if self.vera_device.is_switched_on():
|
||||
self._state = STATE_ON
|
||||
else:
|
||||
self._state = STATE_OFF
|
||||
self.update_ha_state()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -113,18 +113,18 @@ class VeraSwitch(ToggleEntity):
|
|||
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
|
||||
|
||||
if self.vera_device.is_armable:
|
||||
armed = self.vera_device.refresh_value('Armed')
|
||||
armed = self.vera_device.get_value('Armed')
|
||||
attr[ATTR_ARMED] = 'True' if armed == '1' else 'False'
|
||||
|
||||
if self.vera_device.is_trippable:
|
||||
last_tripped = self.vera_device.refresh_value('LastTrip')
|
||||
last_tripped = self.vera_device.get_value('LastTrip')
|
||||
if last_tripped is not None:
|
||||
utc_time = dt_util.utc_from_timestamp(int(last_tripped))
|
||||
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
|
||||
utc_time)
|
||||
else:
|
||||
attr[ATTR_LAST_TRIP_TIME] = None
|
||||
tripped = self.vera_device.refresh_value('Tripped')
|
||||
tripped = self.vera_device.get_value('Tripped')
|
||||
attr[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False'
|
||||
|
||||
attr['Vera Device Id'] = self.vera_device.vera_device_id
|
||||
|
@ -132,14 +132,14 @@ class VeraSwitch(ToggleEntity):
|
|||
return attr
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
self.last_command_send = time.time()
|
||||
self.vera_device.switch_on()
|
||||
self.is_on_status = True
|
||||
self._state = STATE_ON
|
||||
self.update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
self.last_command_send = time.time()
|
||||
self.vera_device.switch_off()
|
||||
self.is_on_status = False
|
||||
self._state = STATE_OFF
|
||||
self.update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
|
@ -149,13 +149,4 @@ class VeraSwitch(ToggleEntity):
|
|||
@property
|
||||
def is_on(self):
|
||||
""" True if device is on. """
|
||||
return self.is_on_status
|
||||
|
||||
def update(self):
|
||||
# We need to debounce the status call after turning switch on or off
|
||||
# because the vera has some lag in updating the device status
|
||||
try:
|
||||
if (self.last_command_send + 5) < time.time():
|
||||
self.is_on_status = self.vera_device.is_switched_on()
|
||||
except RequestException:
|
||||
_LOGGER.warning('Could not update status for %s', self.name)
|
||||
return self._state == STATE_ON
|
||||
|
|
|
@ -12,7 +12,7 @@ from homeassistant.components.switch import SwitchDevice
|
|||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, STATE_STANDBY, EVENT_HOMEASSISTANT_STOP)
|
||||
|
||||
REQUIREMENTS = ['pywemo==0.3.7']
|
||||
REQUIREMENTS = ['pywemo==0.3.8']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
_WEMO_SUBSCRIPTION_REGISTRY = None
|
||||
|
@ -69,15 +69,14 @@ class WemoSwitch(SwitchDevice):
|
|||
def _update_callback(self, _device, _params):
|
||||
""" Called by the wemo device callback to update state. """
|
||||
_LOGGER.info(
|
||||
'Subscription update for %s, sevice=%s',
|
||||
self.name, _device)
|
||||
'Subscription update for %s',
|
||||
_device)
|
||||
self.update_ha_state(True)
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
""" No polling should be needed with subscriptions """
|
||||
# but leave in for initial version in case of issues.
|
||||
return True
|
||||
""" No polling needed with subscriptions """
|
||||
return False
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
|
|
|
@ -28,7 +28,7 @@ DISCOVER_SWITCHES = 'verisure.switches'
|
|||
DISCOVER_ALARMS = 'verisure.alarm_control_panel'
|
||||
|
||||
DEPENDENCIES = ['alarm_control_panel']
|
||||
REQUIREMENTS = ['vsure==0.4.3']
|
||||
REQUIREMENTS = ['vsure==0.4.5']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ def extract_entity_ids(hass, service):
|
|||
service_ent_id = service.data[ATTR_ENTITY_ID]
|
||||
|
||||
if isinstance(service_ent_id, str):
|
||||
return group.expand_entity_ids(hass, [service_ent_id.lower()])
|
||||
return group.expand_entity_ids(hass, [service_ent_id])
|
||||
|
||||
return [ent_id for ent_id in group.expand_entity_ids(hass, service_ent_id)]
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
"""Service calling related helpers."""
|
||||
import logging
|
||||
|
||||
from homeassistant.util import split_entity_id
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
|
||||
CONF_SERVICE = 'service'
|
||||
CONF_SERVICE_ENTITY_ID = 'entity_id'
|
||||
CONF_SERVICE_DATA = 'data'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def call_from_config(hass, config, blocking=False):
|
||||
"""Call a service based on a config hash."""
|
||||
if not isinstance(config, dict) or CONF_SERVICE not in config:
|
||||
_LOGGER.error('Missing key %s: %s', CONF_SERVICE, config)
|
||||
return
|
||||
|
||||
try:
|
||||
domain, service = split_entity_id(config[CONF_SERVICE])
|
||||
except ValueError:
|
||||
_LOGGER.error('Invalid service specified: %s', config[CONF_SERVICE])
|
||||
return
|
||||
|
||||
service_data = config.get(CONF_SERVICE_DATA)
|
||||
|
||||
if service_data is None:
|
||||
service_data = {}
|
||||
elif isinstance(service_data, dict):
|
||||
service_data = dict(service_data)
|
||||
else:
|
||||
_LOGGER.error("%s should be a dictionary", CONF_SERVICE_DATA)
|
||||
service_data = {}
|
||||
|
||||
entity_id = config.get(CONF_SERVICE_ENTITY_ID)
|
||||
if isinstance(entity_id, str):
|
||||
service_data[ATTR_ENTITY_ID] = [ent.strip() for ent in
|
||||
entity_id.split(",")]
|
||||
elif entity_id is not None:
|
||||
service_data[ATTR_ENTITY_ID] = entity_id
|
||||
|
||||
hass.services.call(domain, service, service_data, blocking)
|
|
@ -59,7 +59,7 @@ tellcore-py==1.1.2
|
|||
# homeassistant.components.light.vera
|
||||
# homeassistant.components.sensor.vera
|
||||
# homeassistant.components.switch.vera
|
||||
pyvera==0.2.2
|
||||
pyvera==0.2.3
|
||||
|
||||
# homeassistant.components.wink
|
||||
# homeassistant.components.light.wink
|
||||
|
@ -69,7 +69,7 @@ pyvera==0.2.2
|
|||
python-wink==0.3.1
|
||||
|
||||
# homeassistant.components.media_player.cast
|
||||
pychromecast==0.6.13
|
||||
pychromecast==0.6.14
|
||||
|
||||
# homeassistant.components.media_player.kodi
|
||||
jsonrpc-requests==0.1
|
||||
|
@ -135,7 +135,7 @@ python-forecastio==1.3.3
|
|||
https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3
|
||||
|
||||
# homeassistant.components.sensor.openweathermap
|
||||
pyowm==2.2.1
|
||||
pyowm==2.3.0
|
||||
|
||||
# homeassistant.components.sensor.rpi_gpio
|
||||
# homeassistant.components.switch.rpi_gpio
|
||||
|
@ -173,7 +173,7 @@ hikvision==0.4
|
|||
orvibo==1.1.0
|
||||
|
||||
# homeassistant.components.switch.wemo
|
||||
pywemo==0.3.7
|
||||
pywemo==0.3.8
|
||||
|
||||
# homeassistant.components.tellduslive
|
||||
tellive-py==0.5.2
|
||||
|
@ -191,7 +191,7 @@ python-nest==2.6.0
|
|||
radiotherm==1.2
|
||||
|
||||
# homeassistant.components.verisure
|
||||
vsure==0.4.3
|
||||
vsure==0.4.5
|
||||
|
||||
# homeassistant.components.zwave
|
||||
pydispatcher==2.0.5
|
||||
|
|
|
@ -4,12 +4,14 @@ tests.components.sensor.test_yr
|
|||
|
||||
Tests Yr sensor.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.components.sensor as sensor
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('betamax_session')
|
||||
|
@ -26,14 +28,18 @@ class TestSensorYr:
|
|||
self.hass.stop()
|
||||
|
||||
def test_default_setup(self, betamax_session):
|
||||
now = datetime(2016, 1, 5, 1, tzinfo=dt_util.UTC)
|
||||
|
||||
with patch('homeassistant.components.sensor.yr.requests.Session',
|
||||
return_value=betamax_session):
|
||||
assert sensor.setup(self.hass, {
|
||||
'sensor': {
|
||||
'platform': 'yr',
|
||||
'elevation': 0,
|
||||
}
|
||||
})
|
||||
with patch('homeassistant.components.sensor.yr.dt_util.utcnow',
|
||||
return_value=now):
|
||||
assert sensor.setup(self.hass, {
|
||||
'sensor': {
|
||||
'platform': 'yr',
|
||||
'elevation': 0,
|
||||
}
|
||||
})
|
||||
|
||||
state = self.hass.states.get('sensor.yr_symbol')
|
||||
|
||||
|
|
|
@ -27,12 +27,13 @@ API_URL = "http://127.0.0.1:{}{}".format(SERVER_PORT, alexa.API_ENDPOINT)
|
|||
HA_HEADERS = {const.HTTP_HEADER_HA_AUTH: API_PASSWORD}
|
||||
|
||||
hass = None
|
||||
calls = []
|
||||
|
||||
|
||||
@patch('homeassistant.components.http.util.get_local_ip',
|
||||
return_value='127.0.0.1')
|
||||
def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name
|
||||
""" Initalizes a Home Assistant server. """
|
||||
"""Initalize a Home Assistant server for testing this module."""
|
||||
global hass
|
||||
|
||||
hass = ha.HomeAssistant()
|
||||
|
@ -42,6 +43,8 @@ def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name
|
|||
{http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD,
|
||||
http.CONF_SERVER_PORT: SERVER_PORT}})
|
||||
|
||||
hass.services.register('test', 'alexa', lambda call: calls.append(call))
|
||||
|
||||
bootstrap.setup_component(hass, alexa.DOMAIN, {
|
||||
'alexa': {
|
||||
'intents': {
|
||||
|
@ -61,7 +64,20 @@ def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name
|
|||
'GetZodiacHoroscopeIntent': {
|
||||
'speech': {
|
||||
'type': 'plaintext',
|
||||
'text': 'You told us your sign is {{ ZodiacSign }}.'
|
||||
'text': 'You told us your sign is {{ ZodiacSign }}.',
|
||||
}
|
||||
},
|
||||
'CallServiceIntent': {
|
||||
'speech': {
|
||||
'type': 'plaintext',
|
||||
'text': 'Service called',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.alexa',
|
||||
'data': {
|
||||
'hello': 1
|
||||
},
|
||||
'entity_id': 'switch.test',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,6 +247,39 @@ class TestAlexa(unittest.TestCase):
|
|||
text = req.json().get('response', {}).get('outputSpeech', {}).get('text')
|
||||
self.assertEqual('You are both home, you silly', text)
|
||||
|
||||
def test_intent_request_calling_service(self):
|
||||
data = {
|
||||
'version': '1.0',
|
||||
'session': {
|
||||
'new': False,
|
||||
'sessionId': 'amzn1.echo-api.session.0000000-0000-0000-0000-00000000000',
|
||||
'application': {
|
||||
'applicationId': 'amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe'
|
||||
},
|
||||
'attributes': {},
|
||||
'user': {
|
||||
'userId': 'amzn1.account.AM3B00000000000000000000000'
|
||||
}
|
||||
},
|
||||
'request': {
|
||||
'type': 'IntentRequest',
|
||||
'requestId': ' amzn1.echo-api.request.0000000-0000-0000-0000-00000000000',
|
||||
'timestamp': '2015-05-13T12:34:56Z',
|
||||
'intent': {
|
||||
'name': 'CallServiceIntent',
|
||||
}
|
||||
}
|
||||
}
|
||||
call_count = len(calls)
|
||||
req = _req(data)
|
||||
self.assertEqual(200, req.status_code)
|
||||
self.assertEqual(call_count + 1, len(calls))
|
||||
call = calls[-1]
|
||||
self.assertEqual('test', call.domain)
|
||||
self.assertEqual('alexa', call.service)
|
||||
self.assertEqual(['switch.test'], call.data.get('entity_id'))
|
||||
self.assertEqual(1, call.data.get('hello'))
|
||||
|
||||
def test_session_ended_request(self):
|
||||
data = {
|
||||
'version': '1.0',
|
||||
|
|
|
@ -6,20 +6,22 @@ Tests core compoments.
|
|||
"""
|
||||
# pylint: disable=protected-access,too-many-public-methods
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.loader as loader
|
||||
from homeassistant.const import (
|
||||
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||
import homeassistant.components as comps
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
class TestComponentsCore(unittest.TestCase):
|
||||
""" Tests homeassistant.components module. """
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
""" Init needed objects. """
|
||||
self.hass = ha.HomeAssistant()
|
||||
self.hass = get_test_home_assistant()
|
||||
self.assertTrue(comps.setup(self.hass, {}))
|
||||
|
||||
self.hass.states.set('light.Bowl', STATE_ON)
|
||||
|
@ -58,3 +60,24 @@ class TestComponentsCore(unittest.TestCase):
|
|||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertEqual(1, len(runs))
|
||||
|
||||
@patch('homeassistant.core.ServiceRegistry.call')
|
||||
def test_turn_on_to_not_block_for_domains_without_service(self, mock_call):
|
||||
self.hass.services.register('light', SERVICE_TURN_ON, lambda x: x)
|
||||
|
||||
# We can't test if our service call results in services being called
|
||||
# because by mocking out the call service method, we mock out all
|
||||
# So we mimick how the service registry calls services
|
||||
service_call = ha.ServiceCall('homeassistant', 'turn_on', {
|
||||
'entity_id': ['light.test', 'sensor.bla', 'light.bla']
|
||||
})
|
||||
self.hass.services._services['homeassistant']['turn_on'](service_call)
|
||||
|
||||
self.assertEqual(2, mock_call.call_count)
|
||||
self.assertEqual(
|
||||
('light', 'turn_on', {'entity_id': ['light.bla', 'light.test']},
|
||||
True),
|
||||
mock_call.call_args_list[0][0])
|
||||
self.assertEqual(
|
||||
('sensor', 'turn_on', {'entity_id': ['sensor.bla']}, False),
|
||||
mock_call.call_args_list[1][0])
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
"""
|
||||
tests.helpers.test_service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Test service helpers.
|
||||
"""
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.const import SERVICE_TURN_ON
|
||||
from homeassistant.helpers import service
|
||||
|
||||
from tests.common import get_test_home_assistant, mock_service
|
||||
|
||||
|
||||
class TestServiceHelpers(unittest.TestCase):
|
||||
"""
|
||||
Tests the Home Assistant service helpers.
|
||||
"""
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
""" things to be run when tests are started. """
|
||||
self.hass = get_test_home_assistant()
|
||||
self.calls = mock_service(self.hass, 'test_domain', 'test_service')
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
""" Stop down stuff we started. """
|
||||
self.hass.stop()
|
||||
|
||||
def test_split_entity_string(self):
|
||||
service.call_from_config(self.hass, {
|
||||
'service': 'test_domain.test_service',
|
||||
'entity_id': 'hello.world, sensor.beer'
|
||||
})
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual(['hello.world', 'sensor.beer'],
|
||||
self.calls[-1].data.get('entity_id'))
|
||||
|
||||
def test_not_mutate_input(self):
|
||||
orig = {
|
||||
'service': 'test_domain.test_service',
|
||||
'entity_id': 'hello.world, sensor.beer',
|
||||
'data': {
|
||||
'hello': 1,
|
||||
},
|
||||
}
|
||||
service.call_from_config(self.hass, orig)
|
||||
self.hass.pool.block_till_done()
|
||||
self.assertEqual({
|
||||
'service': 'test_domain.test_service',
|
||||
'entity_id': 'hello.world, sensor.beer',
|
||||
'data': {
|
||||
'hello': 1,
|
||||
},
|
||||
}, orig)
|
||||
|
||||
@patch('homeassistant.helpers.service._LOGGER.error')
|
||||
def test_fail_silently_if_no_service(self, mock_log):
|
||||
service.call_from_config(self.hass, None)
|
||||
self.assertEqual(1, mock_log.call_count)
|
||||
|
||||
service.call_from_config(self.hass, {})
|
||||
self.assertEqual(2, mock_log.call_count)
|
||||
|
||||
service.call_from_config(self.hass, {
|
||||
'service': 'invalid'
|
||||
})
|
||||
self.assertEqual(3, mock_log.call_count)
|
Loading…
Reference in New Issue