mirror of
https://github.com/home-assistant/core.git
synced 2025-07-31 17:18:23 +00:00
Merge remote-tracking branch 'refs/remotes/balloob/dev' into dev
This commit is contained in:
commit
7823fb9788
@ -87,13 +87,21 @@ def setup(hass, config):
|
|||||||
lambda item: util.split_entity_id(item)[0])
|
lambda item: util.split_entity_id(item)[0])
|
||||||
|
|
||||||
for domain, ent_ids in by_domain:
|
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
|
# Create a new dict for this call
|
||||||
data = dict(service.data)
|
data = dict(service.data)
|
||||||
|
|
||||||
# ent_ids is a generator, convert it to a list.
|
# ent_ids is a generator, convert it to a list.
|
||||||
data[ATTR_ENTITY_ID] = list(ent_ids)
|
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_OFF, handle_turn_service)
|
||||||
hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, 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
|
self._state = STATE_ALARM_DISARMED
|
||||||
elif verisure.ALARM_STATUS[self._id].status == 'armedhome':
|
elif verisure.ALARM_STATUS[self._id].status == 'armedhome':
|
||||||
self._state = STATE_ALARM_ARMED_HOME
|
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
|
self._state = STATE_ALARM_ARMED_AWAY
|
||||||
elif verisure.ALARM_STATUS[self._id].status != 'pending':
|
elif verisure.ALARM_STATUS[self._id].status != 'pending':
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
|
@ -11,6 +11,7 @@ import logging
|
|||||||
|
|
||||||
from homeassistant.const import HTTP_OK, HTTP_UNPROCESSABLE_ENTITY
|
from homeassistant.const import HTTP_OK, HTTP_UNPROCESSABLE_ENTITY
|
||||||
from homeassistant.util import template
|
from homeassistant.util import template
|
||||||
|
from homeassistant.helpers.service import call_from_config
|
||||||
|
|
||||||
DOMAIN = 'alexa'
|
DOMAIN = 'alexa'
|
||||||
DEPENDENCIES = ['http']
|
DEPENDENCIES = ['http']
|
||||||
@ -23,6 +24,7 @@ API_ENDPOINT = '/api/alexa'
|
|||||||
CONF_INTENTS = 'intents'
|
CONF_INTENTS = 'intents'
|
||||||
CONF_CARD = 'card'
|
CONF_CARD = 'card'
|
||||||
CONF_SPEECH = 'speech'
|
CONF_SPEECH = 'speech'
|
||||||
|
CONF_ACTION = 'action'
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
@ -80,6 +82,7 @@ def _handle_alexa(handler, path_match, data):
|
|||||||
|
|
||||||
speech = config.get(CONF_SPEECH)
|
speech = config.get(CONF_SPEECH)
|
||||||
card = config.get(CONF_CARD)
|
card = config.get(CONF_CARD)
|
||||||
|
action = config.get(CONF_ACTION)
|
||||||
|
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
if speech is not None:
|
if speech is not None:
|
||||||
@ -89,6 +92,9 @@ def _handle_alexa(handler, path_match, data):
|
|||||||
response.add_card(CardType[card['type']], card['title'],
|
response.add_card(CardType[card['type']], card['title'],
|
||||||
card['content'])
|
card['content'])
|
||||||
|
|
||||||
|
if action is not None:
|
||||||
|
call_from_config(handler.server.hass, action, True)
|
||||||
|
|
||||||
handler.write_json(response.as_dict())
|
handler.write_json(response.as_dict())
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@ https://home-assistant.io/components/automation/
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.bootstrap import prepare_setup_platform
|
from homeassistant.bootstrap import prepare_setup_platform
|
||||||
from homeassistant.util import split_entity_id
|
from homeassistant.const import CONF_PLATFORM
|
||||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM
|
|
||||||
from homeassistant.components import logbook
|
from homeassistant.components import logbook
|
||||||
|
from homeassistant.helpers.service import call_from_config
|
||||||
|
|
||||||
DOMAIN = 'automation'
|
DOMAIN = 'automation'
|
||||||
|
|
||||||
@ -19,8 +19,6 @@ DEPENDENCIES = ['group']
|
|||||||
|
|
||||||
CONF_ALIAS = 'alias'
|
CONF_ALIAS = 'alias'
|
||||||
CONF_SERVICE = 'service'
|
CONF_SERVICE = 'service'
|
||||||
CONF_SERVICE_ENTITY_ID = 'entity_id'
|
|
||||||
CONF_SERVICE_DATA = 'data'
|
|
||||||
|
|
||||||
CONF_CONDITION = 'condition'
|
CONF_CONDITION = 'condition'
|
||||||
CONF_ACTION = 'action'
|
CONF_ACTION = 'action'
|
||||||
@ -96,22 +94,7 @@ def _get_action(hass, config, name):
|
|||||||
_LOGGER.info('Executing %s', name)
|
_LOGGER.info('Executing %s', name)
|
||||||
logbook.log_entry(hass, name, 'has been triggered', DOMAIN)
|
logbook.log_entry(hass, name, 'has been triggered', DOMAIN)
|
||||||
|
|
||||||
domain, service = split_entity_id(config[CONF_SERVICE])
|
call_from_config(hass, config)
|
||||||
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)
|
|
||||||
|
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ def setup_scanner(hass, config, see):
|
|||||||
location = ''
|
location = ''
|
||||||
if data['event'] == 'enter':
|
if data['event'] == 'enter':
|
||||||
|
|
||||||
if data['desc'] == 'home':
|
if data['desc'].lower() == 'home':
|
||||||
location = STATE_HOME
|
location = STATE_HOME
|
||||||
else:
|
else:
|
||||||
location = data['desc']
|
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/
|
https://home-assistant.io/components/light.vera/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
|
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
from homeassistant.components.switch.vera import VeraSwitch
|
from homeassistant.components.switch.vera import VeraSwitch
|
||||||
|
|
||||||
from homeassistant.components.light import ATTR_BRIGHTNESS
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
|||||||
|
|
||||||
lights = []
|
lights = []
|
||||||
for device in devices:
|
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)
|
exclude = extra_data.get('exclude', False)
|
||||||
|
|
||||||
if exclude is not True:
|
if exclude is not True:
|
||||||
@ -86,5 +85,5 @@ class VeraLight(VeraSwitch):
|
|||||||
else:
|
else:
|
||||||
self.vera_device.switch_on()
|
self.vera_device.switch_on()
|
||||||
|
|
||||||
self.last_command_send = time.time()
|
self._state = STATE_ON
|
||||||
self.is_on_status = True
|
self.update_ha_state()
|
||||||
|
@ -20,7 +20,7 @@ from homeassistant.components.media_player import (
|
|||||||
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK,
|
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK,
|
||||||
MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO)
|
MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO)
|
||||||
|
|
||||||
REQUIREMENTS = ['pychromecast==0.6.13']
|
REQUIREMENTS = ['pychromecast==0.6.14']
|
||||||
CONF_IGNORE_CEC = 'ignore_cec'
|
CONF_IGNORE_CEC = 'ignore_cec'
|
||||||
CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png'
|
CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png'
|
||||||
SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
|
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):
|
def config_from_file(filename, config=None):
|
||||||
''' Small configuration file management function'''
|
""" Small configuration file management function. """
|
||||||
if config:
|
if config:
|
||||||
# We're writing configuration
|
# We're writing configuration
|
||||||
try:
|
try:
|
||||||
@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
|||||||
|
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
def setup_plexserver(host, token, hass, add_devices_callback):
|
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.server
|
||||||
import plexapi.exceptions
|
import plexapi.exceptions
|
||||||
|
|
||||||
|
@ -149,9 +149,9 @@ class MQTT(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if client_id is None:
|
if client_id is None:
|
||||||
self._mqttc = mqtt.Client()
|
self._mqttc = mqtt.Client(protocol=mqtt.MQTTv311)
|
||||||
else:
|
else:
|
||||||
self._mqttc = mqtt.Client(client_id)
|
self._mqttc = mqtt.Client(client_id, protocol=mqtt.MQTTv311)
|
||||||
|
|
||||||
self._mqttc.user_data_set(self.userdata)
|
self._mqttc.user_data_set(self.userdata)
|
||||||
|
|
||||||
|
@ -70,5 +70,8 @@ class EliqSensor(Entity):
|
|||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
""" Gets the latest data. """
|
""" Gets the latest data. """
|
||||||
|
try:
|
||||||
response = self.api.get_data_now(channelid=self.channel_id)
|
response = self.api.get_data_now(channelid=self.channel_id)
|
||||||
self._state = int(response.power)
|
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.const import (CONF_API_KEY, TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
REQUIREMENTS = ['pyowm==2.2.1']
|
REQUIREMENTS = ['pyowm==2.3.0']
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
SENSOR_TYPES = {
|
SENSOR_TYPES = {
|
||||||
'weather': ['Condition', ''],
|
'weather': ['Condition', ''],
|
||||||
'temperature': ['Temperature', ''],
|
'temperature': ['Temperature', ''],
|
||||||
'wind_speed': ['Wind speed', 'm/s'],
|
'wind_speed': ['Wind speed', 'm/s'],
|
||||||
'humidity': ['Humidity', '%'],
|
'humidity': ['Humidity', '%'],
|
||||||
'pressure': ['Pressure', 'hPa'],
|
'pressure': ['Pressure', 'mbar'],
|
||||||
'clouds': ['Cloud coverage', '%'],
|
'clouds': ['Cloud coverage', '%'],
|
||||||
'rain': ['Rain', 'mm'],
|
'rain': ['Rain', 'mm'],
|
||||||
'snow': ['Snow', 'mm']
|
'snow': ['Snow', 'mm']
|
||||||
|
@ -15,7 +15,7 @@ from homeassistant.const import (
|
|||||||
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
|
ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME,
|
||||||
TEMP_CELCIUS, TEMP_FAHRENHEIT, EVENT_HOMEASSISTANT_STOP)
|
TEMP_CELCIUS, TEMP_FAHRENHEIT, EVENT_HOMEASSISTANT_STOP)
|
||||||
|
|
||||||
REQUIREMENTS = ['pyvera==0.2.2']
|
REQUIREMENTS = ['pyvera==0.2.3']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ def get_devices(hass, config):
|
|||||||
|
|
||||||
vera_sensors = []
|
vera_sensors = []
|
||||||
for device in devices:
|
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)
|
exclude = extra_data.get('exclude', False)
|
||||||
|
|
||||||
if exclude is not True:
|
if exclude is not True:
|
||||||
@ -85,18 +85,14 @@ class VeraSensor(Entity):
|
|||||||
self.current_value = ''
|
self.current_value = ''
|
||||||
self._temperature_units = None
|
self._temperature_units = None
|
||||||
|
|
||||||
self.controller.register(vera_device)
|
self.controller.register(vera_device, self._update_callback)
|
||||||
self.controller.on(
|
|
||||||
vera_device, self._update_callback)
|
|
||||||
|
|
||||||
def _update_callback(self, _device):
|
def _update_callback(self, _device):
|
||||||
""" Called by the vera device callback to update state. """
|
""" Called by the vera device callback to update state. """
|
||||||
_LOGGER.info(
|
|
||||||
'Subscription update for %s', self.name)
|
|
||||||
self.update_ha_state(True)
|
self.update_ha_state(True)
|
||||||
|
|
||||||
def __str__(self):
|
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
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
@ -119,18 +115,18 @@ class VeraSensor(Entity):
|
|||||||
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
|
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
|
||||||
|
|
||||||
if self.vera_device.is_armable:
|
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'
|
attr[ATTR_ARMED] = 'True' if armed == '1' else 'False'
|
||||||
|
|
||||||
if self.vera_device.is_trippable:
|
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:
|
if last_tripped is not None:
|
||||||
utc_time = dt_util.utc_from_timestamp(int(last_tripped))
|
utc_time = dt_util.utc_from_timestamp(int(last_tripped))
|
||||||
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
|
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
|
||||||
utc_time)
|
utc_time)
|
||||||
else:
|
else:
|
||||||
attr[ATTR_LAST_TRIP_TIME] = None
|
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[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False'
|
||||||
|
|
||||||
attr['Vera Device Id'] = self.vera_device.vera_device_id
|
attr['Vera Device Id'] = self.vera_device.vera_device_id
|
||||||
@ -143,7 +139,6 @@ class VeraSensor(Entity):
|
|||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.vera_device.category == "Temperature Sensor":
|
if self.vera_device.category == "Temperature Sensor":
|
||||||
self.vera_device.refresh_value('CurrentTemperature')
|
|
||||||
current_temp = self.vera_device.get_value('CurrentTemperature')
|
current_temp = self.vera_device.get_value('CurrentTemperature')
|
||||||
vera_temp_units = self.vera_device.veraController.temperature_units
|
vera_temp_units = self.vera_device.veraController.temperature_units
|
||||||
|
|
||||||
@ -161,10 +156,9 @@ class VeraSensor(Entity):
|
|||||||
|
|
||||||
self.current_value = current_temp
|
self.current_value = current_temp
|
||||||
elif self.vera_device.category == "Light Sensor":
|
elif self.vera_device.category == "Light Sensor":
|
||||||
self.vera_device.refresh_value('CurrentLevel')
|
|
||||||
self.current_value = self.vera_device.get_value('CurrentLevel')
|
self.current_value = self.vera_device.get_value('CurrentLevel')
|
||||||
elif self.vera_device.category == "Sensor":
|
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'
|
self.current_value = 'Tripped' if tripped == '1' else 'Not Tripped'
|
||||||
else:
|
else:
|
||||||
self.current_value = 'Unknown'
|
self.current_value = 'Unknown'
|
||||||
|
@ -25,7 +25,7 @@ SENSOR_TYPES = {
|
|||||||
'precipitation': ['Condition', 'mm'],
|
'precipitation': ['Condition', 'mm'],
|
||||||
'temperature': ['Temperature', '°C'],
|
'temperature': ['Temperature', '°C'],
|
||||||
'windSpeed': ['Wind speed', 'm/s'],
|
'windSpeed': ['Wind speed', 'm/s'],
|
||||||
'pressure': ['Pressure', 'hPa'],
|
'pressure': ['Pressure', 'mbar'],
|
||||||
'windDirection': ['Wind direction', '°'],
|
'windDirection': ['Wind direction', '°'],
|
||||||
'humidity': ['Humidity', '%'],
|
'humidity': ['Humidity', '%'],
|
||||||
'fog': ['Fog', '%'],
|
'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/
|
https://home-assistant.io/components/switch.vera/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import time
|
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.components.switch import SwitchDevice
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_BATTERY_LEVEL,
|
ATTR_BATTERY_LEVEL,
|
||||||
ATTR_TRIPPED,
|
ATTR_TRIPPED,
|
||||||
ATTR_ARMED,
|
ATTR_ARMED,
|
||||||
ATTR_LAST_TRIP_TIME,
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -60,7 +62,7 @@ def get_devices(hass, config):
|
|||||||
|
|
||||||
vera_switches = []
|
vera_switches = []
|
||||||
for device in devices:
|
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)
|
exclude = extra_data.get('exclude', False)
|
||||||
|
|
||||||
if exclude is not True:
|
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))
|
add_devices(get_devices(hass, config))
|
||||||
|
|
||||||
|
|
||||||
class VeraSwitch(ToggleEntity):
|
class VeraSwitch(SwitchDevice):
|
||||||
""" Represents a Vera Switch. """
|
""" Represents a Vera Switch. """
|
||||||
|
|
||||||
def __init__(self, vera_device, controller, extra_data=None):
|
def __init__(self, vera_device, controller, extra_data=None):
|
||||||
@ -86,19 +88,17 @@ class VeraSwitch(ToggleEntity):
|
|||||||
self._name = self.extra_data.get('name')
|
self._name = self.extra_data.get('name')
|
||||||
else:
|
else:
|
||||||
self._name = self.vera_device.name
|
self._name = self.vera_device.name
|
||||||
self.is_on_status = False
|
self._state = STATE_OFF
|
||||||
# for debouncing status check after command is sent
|
|
||||||
self.last_command_send = 0
|
|
||||||
|
|
||||||
self.controller.register(vera_device)
|
self.controller.register(vera_device, self._update_callback)
|
||||||
self.controller.on(
|
|
||||||
vera_device, self._update_callback)
|
|
||||||
|
|
||||||
def _update_callback(self, _device):
|
def _update_callback(self, _device):
|
||||||
""" Called by the vera device callback to update state. """
|
""" Called by the vera device callback to update state. """
|
||||||
_LOGGER.info(
|
if self.vera_device.is_switched_on():
|
||||||
'Subscription update for %s', self.name)
|
self._state = STATE_ON
|
||||||
self.update_ha_state(True)
|
else:
|
||||||
|
self._state = STATE_OFF
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -113,18 +113,18 @@ class VeraSwitch(ToggleEntity):
|
|||||||
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
|
attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%'
|
||||||
|
|
||||||
if self.vera_device.is_armable:
|
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'
|
attr[ATTR_ARMED] = 'True' if armed == '1' else 'False'
|
||||||
|
|
||||||
if self.vera_device.is_trippable:
|
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:
|
if last_tripped is not None:
|
||||||
utc_time = dt_util.utc_from_timestamp(int(last_tripped))
|
utc_time = dt_util.utc_from_timestamp(int(last_tripped))
|
||||||
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
|
attr[ATTR_LAST_TRIP_TIME] = dt_util.datetime_to_str(
|
||||||
utc_time)
|
utc_time)
|
||||||
else:
|
else:
|
||||||
attr[ATTR_LAST_TRIP_TIME] = None
|
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[ATTR_TRIPPED] = 'True' if tripped == '1' else 'False'
|
||||||
|
|
||||||
attr['Vera Device Id'] = self.vera_device.vera_device_id
|
attr['Vera Device Id'] = self.vera_device.vera_device_id
|
||||||
@ -132,14 +132,14 @@ class VeraSwitch(ToggleEntity):
|
|||||||
return attr
|
return attr
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
def turn_on(self, **kwargs):
|
||||||
self.last_command_send = time.time()
|
|
||||||
self.vera_device.switch_on()
|
self.vera_device.switch_on()
|
||||||
self.is_on_status = True
|
self._state = STATE_ON
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
def turn_off(self, **kwargs):
|
||||||
self.last_command_send = time.time()
|
|
||||||
self.vera_device.switch_off()
|
self.vera_device.switch_off()
|
||||||
self.is_on_status = False
|
self._state = STATE_OFF
|
||||||
|
self.update_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
@ -149,13 +149,4 @@ class VeraSwitch(ToggleEntity):
|
|||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
""" True if device is on. """
|
""" True if device is on. """
|
||||||
return self.is_on_status
|
return self._state == STATE_ON
|
||||||
|
|
||||||
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)
|
|
||||||
|
@ -12,7 +12,7 @@ from homeassistant.components.switch import SwitchDevice
|
|||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ON, STATE_OFF, STATE_STANDBY, EVENT_HOMEASSISTANT_STOP)
|
STATE_ON, STATE_OFF, STATE_STANDBY, EVENT_HOMEASSISTANT_STOP)
|
||||||
|
|
||||||
REQUIREMENTS = ['pywemo==0.3.7']
|
REQUIREMENTS = ['pywemo==0.3.8']
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
_WEMO_SUBSCRIPTION_REGISTRY = None
|
_WEMO_SUBSCRIPTION_REGISTRY = None
|
||||||
@ -69,15 +69,14 @@ class WemoSwitch(SwitchDevice):
|
|||||||
def _update_callback(self, _device, _params):
|
def _update_callback(self, _device, _params):
|
||||||
""" Called by the wemo device callback to update state. """
|
""" Called by the wemo device callback to update state. """
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'Subscription update for %s, sevice=%s',
|
'Subscription update for %s',
|
||||||
self.name, _device)
|
_device)
|
||||||
self.update_ha_state(True)
|
self.update_ha_state(True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
""" No polling should be needed with subscriptions """
|
""" No polling needed with subscriptions """
|
||||||
# but leave in for initial version in case of issues.
|
return False
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
|
@ -28,7 +28,7 @@ DISCOVER_SWITCHES = 'verisure.switches'
|
|||||||
DISCOVER_ALARMS = 'verisure.alarm_control_panel'
|
DISCOVER_ALARMS = 'verisure.alarm_control_panel'
|
||||||
|
|
||||||
DEPENDENCIES = ['alarm_control_panel']
|
DEPENDENCIES = ['alarm_control_panel']
|
||||||
REQUIREMENTS = ['vsure==0.4.3']
|
REQUIREMENTS = ['vsure==0.4.5']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ def extract_entity_ids(hass, service):
|
|||||||
service_ent_id = service.data[ATTR_ENTITY_ID]
|
service_ent_id = service.data[ATTR_ENTITY_ID]
|
||||||
|
|
||||||
if isinstance(service_ent_id, str):
|
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)]
|
return [ent_id for ent_id in group.expand_entity_ids(hass, service_ent_id)]
|
||||||
|
|
||||||
|
43
homeassistant/helpers/service.py
Normal file
43
homeassistant/helpers/service.py
Normal file
@ -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.light.vera
|
||||||
# homeassistant.components.sensor.vera
|
# homeassistant.components.sensor.vera
|
||||||
# homeassistant.components.switch.vera
|
# homeassistant.components.switch.vera
|
||||||
pyvera==0.2.2
|
pyvera==0.2.3
|
||||||
|
|
||||||
# homeassistant.components.wink
|
# homeassistant.components.wink
|
||||||
# homeassistant.components.light.wink
|
# homeassistant.components.light.wink
|
||||||
@ -69,7 +69,7 @@ pyvera==0.2.2
|
|||||||
python-wink==0.3.1
|
python-wink==0.3.1
|
||||||
|
|
||||||
# homeassistant.components.media_player.cast
|
# homeassistant.components.media_player.cast
|
||||||
pychromecast==0.6.13
|
pychromecast==0.6.14
|
||||||
|
|
||||||
# homeassistant.components.media_player.kodi
|
# homeassistant.components.media_player.kodi
|
||||||
jsonrpc-requests==0.1
|
jsonrpc-requests==0.1
|
||||||
@ -135,7 +135,7 @@ python-forecastio==1.3.3
|
|||||||
https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3
|
https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3
|
||||||
|
|
||||||
# homeassistant.components.sensor.openweathermap
|
# homeassistant.components.sensor.openweathermap
|
||||||
pyowm==2.2.1
|
pyowm==2.3.0
|
||||||
|
|
||||||
# homeassistant.components.sensor.rpi_gpio
|
# homeassistant.components.sensor.rpi_gpio
|
||||||
# homeassistant.components.switch.rpi_gpio
|
# homeassistant.components.switch.rpi_gpio
|
||||||
@ -173,7 +173,7 @@ hikvision==0.4
|
|||||||
orvibo==1.1.0
|
orvibo==1.1.0
|
||||||
|
|
||||||
# homeassistant.components.switch.wemo
|
# homeassistant.components.switch.wemo
|
||||||
pywemo==0.3.7
|
pywemo==0.3.8
|
||||||
|
|
||||||
# homeassistant.components.tellduslive
|
# homeassistant.components.tellduslive
|
||||||
tellive-py==0.5.2
|
tellive-py==0.5.2
|
||||||
@ -191,7 +191,7 @@ python-nest==2.6.0
|
|||||||
radiotherm==1.2
|
radiotherm==1.2
|
||||||
|
|
||||||
# homeassistant.components.verisure
|
# homeassistant.components.verisure
|
||||||
vsure==0.4.3
|
vsure==0.4.5
|
||||||
|
|
||||||
# homeassistant.components.zwave
|
# homeassistant.components.zwave
|
||||||
pydispatcher==2.0.5
|
pydispatcher==2.0.5
|
||||||
|
@ -4,12 +4,14 @@ tests.components.sensor.test_yr
|
|||||||
|
|
||||||
Tests Yr sensor.
|
Tests Yr sensor.
|
||||||
"""
|
"""
|
||||||
|
from datetime import datetime
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
import homeassistant.components.sensor as sensor
|
import homeassistant.components.sensor as sensor
|
||||||
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('betamax_session')
|
@pytest.mark.usefixtures('betamax_session')
|
||||||
@ -26,8 +28,12 @@ class TestSensorYr:
|
|||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
|
|
||||||
def test_default_setup(self, betamax_session):
|
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',
|
with patch('homeassistant.components.sensor.yr.requests.Session',
|
||||||
return_value=betamax_session):
|
return_value=betamax_session):
|
||||||
|
with patch('homeassistant.components.sensor.yr.dt_util.utcnow',
|
||||||
|
return_value=now):
|
||||||
assert sensor.setup(self.hass, {
|
assert sensor.setup(self.hass, {
|
||||||
'sensor': {
|
'sensor': {
|
||||||
'platform': 'yr',
|
'platform': 'yr',
|
||||||
|
@ -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}
|
HA_HEADERS = {const.HTTP_HEADER_HA_AUTH: API_PASSWORD}
|
||||||
|
|
||||||
hass = None
|
hass = None
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
|
||||||
@patch('homeassistant.components.http.util.get_local_ip',
|
@patch('homeassistant.components.http.util.get_local_ip',
|
||||||
return_value='127.0.0.1')
|
return_value='127.0.0.1')
|
||||||
def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name
|
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
|
global hass
|
||||||
|
|
||||||
hass = ha.HomeAssistant()
|
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.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD,
|
||||||
http.CONF_SERVER_PORT: SERVER_PORT}})
|
http.CONF_SERVER_PORT: SERVER_PORT}})
|
||||||
|
|
||||||
|
hass.services.register('test', 'alexa', lambda call: calls.append(call))
|
||||||
|
|
||||||
bootstrap.setup_component(hass, alexa.DOMAIN, {
|
bootstrap.setup_component(hass, alexa.DOMAIN, {
|
||||||
'alexa': {
|
'alexa': {
|
||||||
'intents': {
|
'intents': {
|
||||||
@ -61,7 +64,20 @@ def setUpModule(mock_get_local_ip): # pylint: disable=invalid-name
|
|||||||
'GetZodiacHoroscopeIntent': {
|
'GetZodiacHoroscopeIntent': {
|
||||||
'speech': {
|
'speech': {
|
||||||
'type': 'plaintext',
|
'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')
|
text = req.json().get('response', {}).get('outputSpeech', {}).get('text')
|
||||||
self.assertEqual('You are both home, you silly', 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):
|
def test_session_ended_request(self):
|
||||||
data = {
|
data = {
|
||||||
'version': '1.0',
|
'version': '1.0',
|
||||||
|
@ -6,20 +6,22 @@ Tests core compoments.
|
|||||||
"""
|
"""
|
||||||
# pylint: disable=protected-access,too-many-public-methods
|
# pylint: disable=protected-access,too-many-public-methods
|
||||||
import unittest
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
import homeassistant.loader as loader
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||||
import homeassistant.components as comps
|
import homeassistant.components as comps
|
||||||
|
|
||||||
|
from tests.common import get_test_home_assistant
|
||||||
|
|
||||||
|
|
||||||
class TestComponentsCore(unittest.TestCase):
|
class TestComponentsCore(unittest.TestCase):
|
||||||
""" Tests homeassistant.components module. """
|
""" Tests homeassistant.components module. """
|
||||||
|
|
||||||
def setUp(self): # pylint: disable=invalid-name
|
def setUp(self): # pylint: disable=invalid-name
|
||||||
""" Init needed objects. """
|
""" Init needed objects. """
|
||||||
self.hass = ha.HomeAssistant()
|
self.hass = get_test_home_assistant()
|
||||||
self.assertTrue(comps.setup(self.hass, {}))
|
self.assertTrue(comps.setup(self.hass, {}))
|
||||||
|
|
||||||
self.hass.states.set('light.Bowl', STATE_ON)
|
self.hass.states.set('light.Bowl', STATE_ON)
|
||||||
@ -58,3 +60,24 @@ class TestComponentsCore(unittest.TestCase):
|
|||||||
self.hass.pool.block_till_done()
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
self.assertEqual(1, len(runs))
|
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])
|
||||||
|
68
tests/helpers/test_service.py
Normal file
68
tests/helpers/test_service.py
Normal file
@ -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…
x
Reference in New Issue
Block a user