diff --git a/.coveragerc b/.coveragerc index e97d197ca94a45..b091b3765798ba 100644 --- a/.coveragerc +++ b/.coveragerc @@ -11,9 +11,6 @@ omit = homeassistant/components/abode.py homeassistant/components/*/abode.py - homeassistant/components/ads/__init__.py - homeassistant/components/*/ads.py - homeassistant/components/alarmdecoder.py homeassistant/components/*/alarmdecoder.py @@ -266,7 +263,6 @@ omit = homeassistant/components/alarm_control_panel/alarmdotcom.py homeassistant/components/alarm_control_panel/concord232.py homeassistant/components/alarm_control_panel/egardia.py - homeassistant/components/alarm_control_panel/ialarm.py homeassistant/components/alarm_control_panel/manual_mqtt.py homeassistant/components/alarm_control_panel/nx584.py homeassistant/components/alarm_control_panel/simplisafe.py @@ -288,9 +284,9 @@ omit = homeassistant/components/camera/ffmpeg.py homeassistant/components/camera/foscam.py homeassistant/components/camera/mjpeg.py + homeassistant/components/camera/rpi_camera.py homeassistant/components/camera/onvif.py homeassistant/components/camera/ring.py - homeassistant/components/camera/rpi_camera.py homeassistant/components/camera/synology.py homeassistant/components/camera/yi.py homeassistant/components/climate/ephember.py @@ -298,7 +294,6 @@ omit = homeassistant/components/climate/flexit.py homeassistant/components/climate/heatmiser.py homeassistant/components/climate/homematic.py - homeassistant/components/climate/honeywell.py homeassistant/components/climate/knx.py homeassistant/components/climate/oem.py homeassistant/components/climate/proliphix.py @@ -336,10 +331,10 @@ omit = homeassistant/components/device_tracker/sky_hub.py homeassistant/components/device_tracker/snmp.py homeassistant/components/device_tracker/swisscom.py - homeassistant/components/device_tracker/tado.py homeassistant/components/device_tracker/thomson.py - homeassistant/components/device_tracker/tile.py homeassistant/components/device_tracker/tomato.py + homeassistant/components/device_tracker/tado.py + homeassistant/components/device_tracker/tile.py homeassistant/components/device_tracker/tplink.py homeassistant/components/device_tracker/trackr.py homeassistant/components/device_tracker/ubus.py @@ -357,8 +352,8 @@ omit = homeassistant/components/keyboard.py homeassistant/components/keyboard_remote.py homeassistant/components/light/avion.py - homeassistant/components/light/blinksticklight.py homeassistant/components/light/blinkt.py + homeassistant/components/light/blinksticklight.py homeassistant/components/light/decora.py homeassistant/components/light/decora_wifi.py homeassistant/components/light/flux_led.py @@ -369,8 +364,8 @@ omit = homeassistant/components/light/limitlessled.py homeassistant/components/light/mystrom.py homeassistant/components/light/osramlightify.py - homeassistant/components/light/piglow.py homeassistant/components/light/rpi_gpio_pwm.py + homeassistant/components/light/piglow.py homeassistant/components/light/sensehat.py homeassistant/components/light/tikteck.py homeassistant/components/light/tplink.py @@ -381,9 +376,9 @@ omit = homeassistant/components/light/yeelightsunflower.py homeassistant/components/light/zengge.py homeassistant/components/lirc.py - homeassistant/components/lock/lockitron.py homeassistant/components/lock/nello.py homeassistant/components/lock/nuki.py + homeassistant/components/lock/lockitron.py homeassistant/components/lock/sesame.py homeassistant/components/media_extractor.py homeassistant/components/media_player/anthemav.py @@ -430,7 +425,6 @@ omit = homeassistant/components/media_player/volumio.py homeassistant/components/media_player/yamaha.py homeassistant/components/media_player/yamaha_musiccast.py - homeassistant/components/media_player/ziggo_mediabox_xl.py homeassistant/components/mycroft.py homeassistant/components/notify/aws_lambda.py homeassistant/components/notify/aws_sns.py @@ -478,7 +472,6 @@ omit = homeassistant/components/scene/hunterdouglas_powerview.py homeassistant/components/scene/lifx_cloud.py homeassistant/components/sensor/airvisual.py - homeassistant/components/sensor/alpha_vantage.py homeassistant/components/sensor/arest.py homeassistant/components/sensor/arwn.py homeassistant/components/sensor/bbox.py @@ -489,8 +482,8 @@ omit = homeassistant/components/sensor/bom.py homeassistant/components/sensor/broadlink.py homeassistant/components/sensor/buienradar.py - homeassistant/components/sensor/cert_expiry.py homeassistant/components/sensor/citybikes.py + homeassistant/components/sensor/cert_expiry.py homeassistant/components/sensor/comed_hourly_pricing.py homeassistant/components/sensor/cpuspeed.py homeassistant/components/sensor/crimereports.py @@ -518,7 +511,6 @@ omit = homeassistant/components/sensor/fixer.py homeassistant/components/sensor/fritzbox_callmonitor.py homeassistant/components/sensor/fritzbox_netmonitor.py - homeassistant/components/sensor/gearbest.py homeassistant/components/sensor/geizhals.py homeassistant/components/sensor/gitter.py homeassistant/components/sensor/glances.py @@ -629,8 +621,8 @@ omit = homeassistant/components/switch/rest.py homeassistant/components/switch/rpi_rf.py homeassistant/components/switch/snmp.py - homeassistant/components/switch/telnet.py homeassistant/components/switch/tplink.py + homeassistant/components/switch/telnet.py homeassistant/components/switch/transmission.py homeassistant/components/switch/xiaomi_miio.py homeassistant/components/telegram_bot/* @@ -639,9 +631,7 @@ omit = homeassistant/components/tts/baidu.py homeassistant/components/tts/microsoft.py homeassistant/components/tts/picotts.py - homeassistant/components/vacuum/mqtt.py homeassistant/components/vacuum/roomba.py - homeassistant/components/vacuum/xiaomi_miio.py homeassistant/components/weather/bom.py homeassistant/components/weather/buienradar.py homeassistant/components/weather/metoffice.py @@ -650,6 +640,7 @@ omit = homeassistant/components/weather/zamg.py homeassistant/components/zeroconf.py homeassistant/components/zwave/util.py + homeassistant/components/vacuum/mqtt.py [report] # Regexes for lines to exclude from consideration diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 214efef6e4dcec..00000000000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -# Ensure Docker script files uses LF to support Docker for Windows. -setup_docker_prereqs eol=lf -/virtualization/Docker/scripts/* eol=lf \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index ac0f794482a320..6fa130432f4ef4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -46,7 +46,6 @@ homeassistant/components/climate/eq3btsmart.py @rytilahti homeassistant/components/climate/sensibo.py @andrey-git homeassistant/components/cover/template.py @PhracturedBlue homeassistant/components/device_tracker/automatic.py @armills -homeassistant/components/device_tracker/tile.py @bachya homeassistant/components/history_graph.py @andrey-git homeassistant/components/light/tplink.py @rytilahti homeassistant/components/light/yeelight.py @rytilahti @@ -54,7 +53,6 @@ homeassistant/components/media_player/kodi.py @armills homeassistant/components/media_player/monoprice.py @etsinko homeassistant/components/media_player/yamaha_musiccast.py @jalmeroth homeassistant/components/sensor/airvisual.py @bachya -homeassistant/components/sensor/gearbest.py @HerrHofrat homeassistant/components/sensor/irish_rail_transport.py @ttroy50 homeassistant/components/sensor/miflora.py @danielhiversen homeassistant/components/sensor/sytadin.py @gautric diff --git a/homeassistant/components/ads/__init__.py b/homeassistant/components/ads/__init__.py deleted file mode 100644 index 3d9de28ded3792..00000000000000 --- a/homeassistant/components/ads/__init__.py +++ /dev/null @@ -1,217 +0,0 @@ -""" -ADS Component. - -For more details about this component, please refer to the documentation. -https://home-assistant.io/components/ads/ - -""" -import os -import threading -import struct -import logging -import ctypes -from collections import namedtuple -import voluptuous as vol -from homeassistant.const import CONF_DEVICE, CONF_PORT, CONF_IP_ADDRESS, \ - EVENT_HOMEASSISTANT_STOP -from homeassistant.config import load_yaml_config_file -import homeassistant.helpers.config_validation as cv - -REQUIREMENTS = ['pyads==2.2.6'] - -_LOGGER = logging.getLogger(__name__) - -DATA_ADS = 'data_ads' - -# Supported Types -ADSTYPE_INT = 'int' -ADSTYPE_UINT = 'uint' -ADSTYPE_BYTE = 'byte' -ADSTYPE_BOOL = 'bool' - -DOMAIN = 'ads' - -# config variable names -CONF_ADS_VAR = 'adsvar' -CONF_ADS_VAR_BRIGHTNESS = 'adsvar_brightness' -CONF_ADS_TYPE = 'adstype' -CONF_ADS_FACTOR = 'factor' -CONF_ADS_VALUE = 'value' - -SERVICE_WRITE_DATA_BY_NAME = 'write_data_by_name' - -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_DEVICE): cv.string, - vol.Required(CONF_PORT): cv.port, - vol.Optional(CONF_IP_ADDRESS): cv.string, - }) -}, extra=vol.ALLOW_EXTRA) - -SCHEMA_SERVICE_WRITE_DATA_BY_NAME = vol.Schema({ - vol.Required(CONF_ADS_VAR): cv.string, - vol.Required(CONF_ADS_TYPE): vol.In([ADSTYPE_INT, ADSTYPE_UINT, - ADSTYPE_BYTE]), - vol.Required(CONF_ADS_VALUE): cv.match_all -}) - - -def setup(hass, config): - """Set up the ADS component.""" - import pyads - conf = config[DOMAIN] - - # get ads connection parameters from config - net_id = conf.get(CONF_DEVICE) - ip_address = conf.get(CONF_IP_ADDRESS) - port = conf.get(CONF_PORT) - - # create a new ads connection - client = pyads.Connection(net_id, port, ip_address) - - # add some constants to AdsHub - AdsHub.ADS_TYPEMAP = { - ADSTYPE_BOOL: pyads.PLCTYPE_BOOL, - ADSTYPE_BYTE: pyads.PLCTYPE_BYTE, - ADSTYPE_INT: pyads.PLCTYPE_INT, - ADSTYPE_UINT: pyads.PLCTYPE_UINT, - } - - AdsHub.PLCTYPE_BOOL = pyads.PLCTYPE_BOOL - AdsHub.PLCTYPE_BYTE = pyads.PLCTYPE_BYTE - AdsHub.PLCTYPE_INT = pyads.PLCTYPE_INT - AdsHub.PLCTYPE_UINT = pyads.PLCTYPE_UINT - AdsHub.ADSError = pyads.ADSError - - # connect to ads client and try to connect - try: - ads = AdsHub(client) - except pyads.pyads.ADSError: - _LOGGER.error( - 'Could not connect to ADS host (netid=%s, port=%s)', net_id, port - ) - return False - - # add ads hub to hass data collection, listen to shutdown - hass.data[DATA_ADS] = ads - hass.bus.listen(EVENT_HOMEASSISTANT_STOP, ads.shutdown) - - def handle_write_data_by_name(call): - """Write a value to the connected ADS device.""" - ads_var = call.data.get(CONF_ADS_VAR) - ads_type = call.data.get(CONF_ADS_TYPE) - value = call.data.get(CONF_ADS_VALUE) - - try: - ads.write_by_name(ads_var, value, ads.ADS_TYPEMAP[ads_type]) - except pyads.ADSError as err: - _LOGGER.error(err) - - # load descriptions from services.yaml - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - hass.services.register( - DOMAIN, SERVICE_WRITE_DATA_BY_NAME, handle_write_data_by_name, - descriptions[SERVICE_WRITE_DATA_BY_NAME], - schema=SCHEMA_SERVICE_WRITE_DATA_BY_NAME - ) - - return True - - -# tuple to hold data needed for notification -NotificationItem = namedtuple( - 'NotificationItem', 'hnotify huser name plc_datatype callback' -) - - -class AdsHub: - """Representation of a PyADS connection.""" - - def __init__(self, ads_client): - """Initialize the ADS Hub.""" - self._client = ads_client - self._client.open() - - # all ADS devices are registered here - self._devices = [] - self._notification_items = {} - self._lock = threading.Lock() - - def shutdown(self, *args, **kwargs): - """Shutdown ADS connection.""" - _LOGGER.debug('Shutting down ADS') - for notification_item in self._notification_items.values(): - self._client.del_device_notification( - notification_item.hnotify, - notification_item.huser - ) - _LOGGER.debug( - 'Deleting device notification %d, %d', - notification_item.hnotify, notification_item.huser - ) - self._client.close() - - def register_device(self, device): - """Register a new device.""" - self._devices.append(device) - - def write_by_name(self, name, value, plc_datatype): - """Write a value to the device.""" - with self._lock: - return self._client.write_by_name(name, value, plc_datatype) - - def read_by_name(self, name, plc_datatype): - """Read a value from the device.""" - with self._lock: - return self._client.read_by_name(name, plc_datatype) - - def add_device_notification(self, name, plc_datatype, callback): - """Add a notification to the ADS devices.""" - from pyads import NotificationAttrib - attr = NotificationAttrib(ctypes.sizeof(plc_datatype)) - - with self._lock: - hnotify, huser = self._client.add_device_notification( - name, attr, self._device_notification_callback - ) - hnotify = int(hnotify) - - _LOGGER.debug( - 'Added Device Notification %d for variable %s', hnotify, name - ) - - self._notification_items[hnotify] = NotificationItem( - hnotify, huser, name, plc_datatype, callback - ) - - def _device_notification_callback(self, addr, notification, huser): - """Handle device notifications.""" - contents = notification.contents - - hnotify = int(contents.hNotification) - _LOGGER.debug('Received Notification %d', hnotify) - data = contents.data - - try: - notification_item = self._notification_items[hnotify] - except KeyError: - _LOGGER.debug('Unknown Device Notification handle: %d', hnotify) - return - - # parse data to desired datatype - if notification_item.plc_datatype == self.PLCTYPE_BOOL: - value = bool(struct.unpack(' dt_util.utcnow() + pending_time = self._pending_time_by_state[state] + return self._state_ts + pending_time > dt_util.utcnow() @property def code_format(self): @@ -239,35 +185,26 @@ def alarm_arm_custom_bypass(self, code=None): self._update_state(STATE_ALARM_ARMED_CUSTOM_BYPASS) def alarm_trigger(self, code=None): - """ - Send alarm trigger command. + """Send alarm trigger command. No code needed.""" + self._pre_trigger_state = self._state - No code needed, a trigger time of zero for the current state - disables the alarm. - """ - if not self._trigger_time_by_state[self._active_state]: - return self._update_state(STATE_ALARM_TRIGGERED) def _update_state(self, state): - if self._state == state: - return - - self._previous_state = self._state self._state = state self._state_ts = dt_util.utcnow() self.schedule_update_ha_state() - pending_time = self._pending_time(state) - if state == STATE_ALARM_TRIGGERED: + pending_time = self._pending_time_by_state[state] + + if state == STATE_ALARM_TRIGGERED and self._trigger_time: track_point_in_time( self._hass, self.async_update_ha_state, self._state_ts + pending_time) - trigger_time = self._trigger_time_by_state[self._previous_state] track_point_in_time( self._hass, self.async_update_ha_state, - self._state_ts + pending_time + trigger_time) + self._state_ts + self._trigger_time + pending_time) elif state in SUPPORTED_PENDING_STATES and pending_time: track_point_in_time( self._hass, self.async_update_ha_state, @@ -275,14 +212,7 @@ def _update_state(self, state): def _validate_code(self, code, state): """Validate given code.""" - if self._code is None: - return True - if isinstance(self._code, str): - alarm_code = self._code - else: - alarm_code = self._code.render(from_state=self._state, - to_state=state) - check = not alarm_code or code == alarm_code + check = self._code is None or code == self._code if not check: _LOGGER.warning("Invalid code given for %s", state) return check @@ -293,7 +223,6 @@ def device_state_attributes(self): state_attr = {} if self.state == STATE_ALARM_PENDING: - state_attr[ATTR_PRE_PENDING_STATE] = self._previous_state state_attr[ATTR_POST_PENDING_STATE] = self._state return state_attr diff --git a/homeassistant/components/alarm_control_panel/manual_mqtt.py b/homeassistant/components/alarm_control_panel/manual_mqtt.py index 9e388806e73495..44247616b59ff3 100644 --- a/homeassistant/components/alarm_control_panel/manual_mqtt.py +++ b/homeassistant/components/alarm_control_panel/manual_mqtt.py @@ -16,8 +16,8 @@ from homeassistant.const import ( STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, - CONF_PLATFORM, CONF_NAME, CONF_CODE, CONF_DELAY_TIME, CONF_PENDING_TIME, - CONF_TRIGGER_TIME, CONF_DISARM_AFTER_TRIGGER) + CONF_PLATFORM, CONF_NAME, CONF_CODE, CONF_PENDING_TIME, CONF_TRIGGER_TIME, + CONF_DISARM_AFTER_TRIGGER) import homeassistant.components.mqtt as mqtt from homeassistant.helpers.event import async_track_state_change @@ -26,44 +26,28 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import track_point_in_time -CONF_CODE_TEMPLATE = 'code_template' - CONF_PAYLOAD_DISARM = 'payload_disarm' CONF_PAYLOAD_ARM_HOME = 'payload_arm_home' CONF_PAYLOAD_ARM_AWAY = 'payload_arm_away' CONF_PAYLOAD_ARM_NIGHT = 'payload_arm_night' DEFAULT_ALARM_NAME = 'HA Alarm' -DEFAULT_DELAY_TIME = datetime.timedelta(seconds=0) -DEFAULT_PENDING_TIME = datetime.timedelta(seconds=60) -DEFAULT_TRIGGER_TIME = datetime.timedelta(seconds=120) +DEFAULT_PENDING_TIME = 60 +DEFAULT_TRIGGER_TIME = 120 DEFAULT_DISARM_AFTER_TRIGGER = False DEFAULT_ARM_AWAY = 'ARM_AWAY' DEFAULT_ARM_HOME = 'ARM_HOME' DEFAULT_ARM_NIGHT = 'ARM_NIGHT' DEFAULT_DISARM = 'DISARM' -SUPPORTED_STATES = [STATE_ALARM_DISARMED, STATE_ALARM_ARMED_AWAY, - STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, - STATE_ALARM_TRIGGERED] - -SUPPORTED_PRETRIGGER_STATES = [state for state in SUPPORTED_STATES - if state != STATE_ALARM_TRIGGERED] - -SUPPORTED_PENDING_STATES = [state for state in SUPPORTED_STATES - if state != STATE_ALARM_DISARMED] +SUPPORTED_PENDING_STATES = [STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, STATE_ALARM_TRIGGERED] -ATTR_PRE_PENDING_STATE = 'pre_pending_state' ATTR_POST_PENDING_STATE = 'post_pending_state' def _state_validator(config): config = copy.deepcopy(config) - for state in SUPPORTED_PRETRIGGER_STATES: - if CONF_DELAY_TIME not in config[state]: - config[state][CONF_DELAY_TIME] = config[CONF_DELAY_TIME] - if CONF_TRIGGER_TIME not in config[state]: - config[state][CONF_TRIGGER_TIME] = config[CONF_TRIGGER_TIME] for state in SUPPORTED_PENDING_STATES: if CONF_PENDING_TIME not in config[state]: config[state][CONF_PENDING_TIME] = config[CONF_PENDING_TIME] @@ -71,44 +55,27 @@ def _state_validator(config): return config -def _state_schema(state): - schema = {} - if state in SUPPORTED_PRETRIGGER_STATES: - schema[vol.Optional(CONF_DELAY_TIME)] = vol.All( - cv.time_period, cv.positive_timedelta) - schema[vol.Optional(CONF_TRIGGER_TIME)] = vol.All( - cv.time_period, cv.positive_timedelta) - if state in SUPPORTED_PENDING_STATES: - schema[vol.Optional(CONF_PENDING_TIME)] = vol.All( - cv.time_period, cv.positive_timedelta) - return vol.Schema(schema) - +STATE_SETTING_SCHEMA = vol.Schema({ + vol.Optional(CONF_PENDING_TIME): + vol.All(vol.Coerce(int), vol.Range(min=0)) +}) DEPENDENCIES = ['mqtt'] PLATFORM_SCHEMA = vol.Schema(vol.All(mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ vol.Required(CONF_PLATFORM): 'manual_mqtt', vol.Optional(CONF_NAME, default=DEFAULT_ALARM_NAME): cv.string, - vol.Exclusive(CONF_CODE, 'code validation'): cv.string, - vol.Exclusive(CONF_CODE_TEMPLATE, 'code validation'): cv.template, - vol.Optional(CONF_DELAY_TIME, default=DEFAULT_DELAY_TIME): - vol.All(cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_CODE): cv.string, vol.Optional(CONF_PENDING_TIME, default=DEFAULT_PENDING_TIME): - vol.All(cv.time_period, cv.positive_timedelta), + vol.All(vol.Coerce(int), vol.Range(min=0)), vol.Optional(CONF_TRIGGER_TIME, default=DEFAULT_TRIGGER_TIME): - vol.All(cv.time_period, cv.positive_timedelta), + vol.All(vol.Coerce(int), vol.Range(min=1)), vol.Optional(CONF_DISARM_AFTER_TRIGGER, default=DEFAULT_DISARM_AFTER_TRIGGER): cv.boolean, - vol.Optional(STATE_ALARM_ARMED_AWAY, default={}): - _state_schema(STATE_ALARM_ARMED_AWAY), - vol.Optional(STATE_ALARM_ARMED_HOME, default={}): - _state_schema(STATE_ALARM_ARMED_HOME), - vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}): - _state_schema(STATE_ALARM_ARMED_NIGHT), - vol.Optional(STATE_ALARM_DISARMED, default={}): - _state_schema(STATE_ALARM_DISARMED), - vol.Optional(STATE_ALARM_TRIGGERED, default={}): - _state_schema(STATE_ALARM_TRIGGERED), + vol.Optional(STATE_ALARM_ARMED_AWAY, default={}): STATE_SETTING_SCHEMA, + vol.Optional(STATE_ALARM_ARMED_HOME, default={}): STATE_SETTING_SCHEMA, + vol.Optional(STATE_ALARM_ARMED_NIGHT, default={}): STATE_SETTING_SCHEMA, + vol.Optional(STATE_ALARM_TRIGGERED, default={}): STATE_SETTING_SCHEMA, vol.Required(mqtt.CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Required(mqtt.CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string, @@ -126,7 +93,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass, config[CONF_NAME], config.get(CONF_CODE), - config.get(CONF_CODE_TEMPLATE), + config.get(CONF_PENDING_TIME, DEFAULT_PENDING_TIME), + config.get(CONF_TRIGGER_TIME, DEFAULT_TRIGGER_TIME), config.get(CONF_DISARM_AFTER_TRIGGER, DEFAULT_DISARM_AFTER_TRIGGER), config.get(mqtt.CONF_STATE_TOPIC), config.get(mqtt.CONF_COMMAND_TOPIC), @@ -143,15 +111,13 @@ class ManualMQTTAlarm(alarm.AlarmControlPanel): Representation of an alarm status. When armed, will be pending for 'pending_time', after that armed. - When triggered, will be pending for the triggering state's 'delay_time' - plus the triggered state's 'pending_time'. - After that will be triggered for 'trigger_time', after that we return to - the previous state or disarm if `disarm_after_trigger` is true. - A trigger_time of zero disables the alarm_trigger service. + When triggered, will be pending for 'trigger_time'. After that will be + triggered for 'trigger_time', after that we return to the previous state + or disarm if `disarm_after_trigger` is true. """ - def __init__(self, hass, name, code, code_template, - disarm_after_trigger, + def __init__(self, hass, name, code, pending_time, + trigger_time, disarm_after_trigger, state_topic, command_topic, qos, payload_disarm, payload_arm_home, payload_arm_away, payload_arm_night, config): @@ -159,24 +125,17 @@ def __init__(self, hass, name, code, code_template, self._state = STATE_ALARM_DISARMED self._hass = hass self._name = name - if code_template: - self._code = code_template - self._code.hass = hass - else: - self._code = code or None + self._code = str(code) if code else None + self._pending_time = datetime.timedelta(seconds=pending_time) + self._trigger_time = datetime.timedelta(seconds=trigger_time) self._disarm_after_trigger = disarm_after_trigger - self._previous_state = self._state + self._pre_trigger_state = self._state self._state_ts = None - self._delay_time_by_state = { - state: config[state][CONF_DELAY_TIME] - for state in SUPPORTED_PRETRIGGER_STATES} - self._trigger_time_by_state = { - state: config[state][CONF_TRIGGER_TIME] - for state in SUPPORTED_PRETRIGGER_STATES} - self._pending_time_by_state = { - state: config[state][CONF_PENDING_TIME] - for state in SUPPORTED_PENDING_STATES} + self._pending_time_by_state = {} + for state in SUPPORTED_PENDING_STATES: + self._pending_time_by_state[state] = datetime.timedelta( + seconds=config[state][CONF_PENDING_TIME]) self._state_topic = state_topic self._command_topic = command_topic @@ -199,16 +158,15 @@ def name(self): @property def state(self): """Return the state of the device.""" - if self._state == STATE_ALARM_TRIGGERED: + if self._state == STATE_ALARM_TRIGGERED and self._trigger_time: if self._within_pending_time(self._state): return STATE_ALARM_PENDING - trigger_time = self._trigger_time_by_state[self._previous_state] - if (self._state_ts + self._pending_time(self._state) + - trigger_time) < dt_util.utcnow(): + elif (self._state_ts + self._pending_time_by_state[self._state] + + self._trigger_time) < dt_util.utcnow(): if self._disarm_after_trigger: return STATE_ALARM_DISARMED else: - self._state = self._previous_state + self._state = self._pre_trigger_state return self._state if self._state in SUPPORTED_PENDING_STATES and \ @@ -217,21 +175,9 @@ def state(self): return self._state - @property - def _active_state(self): - if self.state == STATE_ALARM_PENDING: - return self._previous_state - else: - return self._state - - def _pending_time(self, state): - pending_time = self._pending_time_by_state[state] - if state == STATE_ALARM_TRIGGERED: - pending_time += self._delay_time_by_state[self._previous_state] - return pending_time - def _within_pending_time(self, state): - return self._state_ts + self._pending_time(state) > dt_util.utcnow() + pending_time = self._pending_time_by_state[state] + return self._state_ts + pending_time > dt_util.utcnow() @property def code_format(self): @@ -269,35 +215,26 @@ def alarm_arm_night(self, code=None): self._update_state(STATE_ALARM_ARMED_NIGHT) def alarm_trigger(self, code=None): - """ - Send alarm trigger command. + """Send alarm trigger command. No code needed.""" + self._pre_trigger_state = self._state - No code needed, a trigger time of zero for the current state - disables the alarm. - """ - if not self._trigger_time_by_state[self._active_state]: - return self._update_state(STATE_ALARM_TRIGGERED) def _update_state(self, state): - if self._state == state: - return - - self._previous_state = self._state self._state = state self._state_ts = dt_util.utcnow() self.schedule_update_ha_state() - pending_time = self._pending_time(state) - if state == STATE_ALARM_TRIGGERED: + pending_time = self._pending_time_by_state[state] + + if state == STATE_ALARM_TRIGGERED and self._trigger_time: track_point_in_time( self._hass, self.async_update_ha_state, self._state_ts + pending_time) - trigger_time = self._trigger_time_by_state[self._previous_state] track_point_in_time( self._hass, self.async_update_ha_state, - self._state_ts + pending_time + trigger_time) + self._state_ts + self._trigger_time + pending_time) elif state in SUPPORTED_PENDING_STATES and pending_time: track_point_in_time( self._hass, self.async_update_ha_state, @@ -305,14 +242,7 @@ def _update_state(self, state): def _validate_code(self, code, state): """Validate given code.""" - if self._code is None: - return True - if isinstance(self._code, str): - alarm_code = self._code - else: - alarm_code = self._code.render(from_state=self._state, - to_state=state) - check = not alarm_code or code == alarm_code + check = self._code is None or code == self._code if not check: _LOGGER.warning("Invalid code given for %s", state) return check @@ -323,7 +253,6 @@ def device_state_attributes(self): state_attr = {} if self.state == STATE_ALARM_PENDING: - state_attr[ATTR_PRE_PENDING_STATE] = self._previous_state state_attr[ATTR_POST_PENDING_STATE] = self._state return state_attr diff --git a/homeassistant/components/automation/numeric_state.py b/homeassistant/components/automation/numeric_state.py index b59271f25e56ca..d5cdc9ffd83ec2 100644 --- a/homeassistant/components/automation/numeric_state.py +++ b/homeassistant/components/automation/numeric_state.py @@ -37,8 +37,8 @@ def async_trigger(hass, config, action): above = config.get(CONF_ABOVE) time_delta = config.get(CONF_FOR) value_template = config.get(CONF_VALUE_TEMPLATE) - unsub_track_same = {} - entities_triggered = set() + async_remove_track_same = None + already_triggered = False if value_template is not None: value_template.hass = hass @@ -63,6 +63,8 @@ def check_numeric_state(entity, from_s, to_s): @callback def state_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" + nonlocal already_triggered, async_remove_track_same + @callback def call_action(): """Call action with right context.""" @@ -79,18 +81,16 @@ def call_action(): matching = check_numeric_state(entity, from_s, to_s) - if not matching: - entities_triggered.discard(entity) - elif entity not in entities_triggered: - entities_triggered.add(entity) - + if matching and not already_triggered: if time_delta: - unsub_track_same[entity] = async_track_same_state( + async_remove_track_same = async_track_same_state( hass, time_delta, call_action, entity_ids=entity_id, async_check_same_func=check_numeric_state) else: call_action() + already_triggered = matching + unsub = async_track_state_change( hass, entity_id, state_automation_listener) @@ -98,8 +98,7 @@ def call_action(): def async_remove(): """Remove state listeners async.""" unsub() - for async_remove in unsub_track_same.values(): - async_remove() - unsub_track_same.clear() + if async_remove_track_same: + async_remove_track_same() # pylint: disable=not-callable return async_remove diff --git a/homeassistant/components/automation/state.py b/homeassistant/components/automation/state.py index e4d096d35fd395..7ed44761be80fe 100644 --- a/homeassistant/components/automation/state.py +++ b/homeassistant/components/automation/state.py @@ -35,11 +35,13 @@ def async_trigger(hass, config, action): to_state = config.get(CONF_TO, MATCH_ALL) time_delta = config.get(CONF_FOR) match_all = (from_state == MATCH_ALL and to_state == MATCH_ALL) - unsub_track_same = {} + async_remove_track_same = None @callback def state_automation_listener(entity, from_s, to_s): """Listen for state changes and calls action.""" + nonlocal async_remove_track_same + @callback def call_action(): """Call action with right context.""" @@ -62,7 +64,7 @@ def call_action(): call_action() return - unsub_track_same[entity] = async_track_same_state( + async_remove_track_same = async_track_same_state( hass, time_delta, call_action, lambda _, _2, to_state: to_state.state == to_s.state, entity_ids=entity_id) @@ -74,8 +76,7 @@ def call_action(): def async_remove(): """Remove state listeners async.""" unsub() - for async_remove in unsub_track_same.values(): - async_remove() - unsub_track_same.clear() + if async_remove_track_same: + async_remove_track_same() # pylint: disable=not-callable return async_remove diff --git a/homeassistant/components/binary_sensor/ads.py b/homeassistant/components/binary_sensor/ads.py deleted file mode 100644 index e6b86ed97e68a2..00000000000000 --- a/homeassistant/components/binary_sensor/ads.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Support for ADS binary sensors. - -For more details about this platform, please refer to the documentation. -https://home-assistant.io/components/binary_sensor.ads/ - -""" -import asyncio -import logging -import voluptuous as vol -from homeassistant.components.binary_sensor import BinarySensorDevice, \ - PLATFORM_SCHEMA, DEVICE_CLASSES_SCHEMA -from homeassistant.components.ads import DATA_ADS, CONF_ADS_VAR -from homeassistant.const import CONF_NAME, CONF_DEVICE_CLASS -import homeassistant.helpers.config_validation as cv - - -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['ads'] -DEFAULT_NAME = 'ADS binary sensor' - - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ADS_VAR): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Binary Sensor platform for ADS.""" - ads_hub = hass.data.get(DATA_ADS) - - ads_var = config.get(CONF_ADS_VAR) - name = config.get(CONF_NAME) - device_class = config.get(CONF_DEVICE_CLASS) - - ads_sensor = AdsBinarySensor(ads_hub, name, ads_var, device_class) - add_devices([ads_sensor]) - - -class AdsBinarySensor(BinarySensorDevice): - """Representation of ADS binary sensors.""" - - def __init__(self, ads_hub, name, ads_var, device_class): - """Initialize AdsBinarySensor entity.""" - self._name = name - self._state = False - self._device_class = device_class or 'moving' - self._ads_hub = ads_hub - self.ads_var = ads_var - - @asyncio.coroutine - def async_added_to_hass(self): - """Register device notification.""" - def update(name, value): - """Handle device notifications.""" - _LOGGER.debug('Variable %s changed its value to %d', - name, value) - self._state = value - self.schedule_update_ha_state() - - self.hass.async_add_job( - self._ads_hub.add_device_notification, - self.ads_var, self._ads_hub.PLCTYPE_BOOL, update - ) - - @property - def name(self): - """Return the default name of the binary sensor.""" - return self._name - - @property - def device_class(self): - """Return the device class.""" - return self._device_class - - @property - def is_on(self): - """Return if the binary sensor is on.""" - return self._state - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False diff --git a/homeassistant/components/binary_sensor/vera.py b/homeassistant/components/binary_sensor/vera.py index e87886376bc307..e16f4e17fa0589 100644 --- a/homeassistant/components/binary_sensor/vera.py +++ b/homeassistant/components/binary_sensor/vera.py @@ -19,8 +19,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Perform the setup for Vera controller devices.""" add_devices( - VeraBinarySensor(device, hass.data[VERA_CONTROLLER]) - for device in hass.data[VERA_DEVICES]['binary_sensor']) + VeraBinarySensor(device, VERA_CONTROLLER) + for device in VERA_DEVICES['binary_sensor']) class VeraBinarySensor(VeraDevice, BinarySensorDevice): diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 6574a4d539660f..987708834cc711 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -13,8 +13,7 @@ from homeassistant.core import DOMAIN as HA_DOMAIN from homeassistant.components.climate import ( STATE_HEAT, STATE_COOL, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA, - STATE_AUTO, ATTR_OPERATION_MODE, SUPPORT_OPERATION_MODE, - SUPPORT_TARGET_TEMPERATURE) + STATE_AUTO, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE) from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, ATTR_TEMPERATURE, CONF_NAME, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF) @@ -41,7 +40,7 @@ CONF_COLD_TOLERANCE = 'cold_tolerance' CONF_HOT_TOLERANCE = 'hot_tolerance' CONF_KEEP_ALIVE = 'keep_alive' -CONF_INITIAL_OPERATION_MODE = 'initial_operation_mode' + SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -59,8 +58,6 @@ vol.Optional(CONF_TARGET_TEMP): vol.Coerce(float), vol.Optional(CONF_KEEP_ALIVE): vol.All( cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_INITIAL_OPERATION_MODE): - vol.In([STATE_AUTO, STATE_OFF]) }) @@ -78,12 +75,11 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): cold_tolerance = config.get(CONF_COLD_TOLERANCE) hot_tolerance = config.get(CONF_HOT_TOLERANCE) keep_alive = config.get(CONF_KEEP_ALIVE) - initial_operation_mode = config.get(CONF_INITIAL_OPERATION_MODE) async_add_devices([GenericThermostat( hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp, ac_mode, min_cycle_duration, cold_tolerance, - hot_tolerance, keep_alive, initial_operation_mode)]) + hot_tolerance, keep_alive)]) class GenericThermostat(ClimateDevice): @@ -91,8 +87,7 @@ class GenericThermostat(ClimateDevice): def __init__(self, hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp, ac_mode, min_cycle_duration, - cold_tolerance, hot_tolerance, keep_alive, - initial_operation_mode): + cold_tolerance, hot_tolerance, keep_alive): """Initialize the thermostat.""" self.hass = hass self._name = name @@ -102,11 +97,7 @@ def __init__(self, hass, name, heater_entity_id, sensor_entity_id, self._cold_tolerance = cold_tolerance self._hot_tolerance = hot_tolerance self._keep_alive = keep_alive - self._initial_operation_mode = initial_operation_mode - if initial_operation_mode == STATE_OFF: - self._enabled = False - else: - self._enabled = True + self._enabled = True self._active = False self._cur_temp = None @@ -131,20 +122,14 @@ def __init__(self, hass, name, heater_entity_id, sensor_entity_id, @asyncio.coroutine def async_added_to_hass(self): """Run when entity about to be added.""" - # Check If we have an old state - old_state = yield from async_get_last_state(self.hass, - self.entity_id) - if old_state is not None: - # If we have no initial temperature, restore - if self._target_temp is None: + # If we have an old state and no target temp, restore + if self._target_temp is None: + old_state = yield from async_get_last_state(self.hass, + self.entity_id) + if old_state is not None: self._target_temp = float( old_state.attributes[ATTR_TEMPERATURE]) - # If we have no initial operation mode, restore - if self._initial_operation_mode is None: - if old_state.attributes[ATTR_OPERATION_MODE] == STATE_OFF: - self._enabled = False - @property def should_poll(self): """Return the polling state.""" diff --git a/homeassistant/components/climate/tado.py b/homeassistant/components/climate/tado.py index a8054b838ef0ba..d58acac5373c25 100644 --- a/homeassistant/components/climate/tado.py +++ b/homeassistant/components/climate/tado.py @@ -59,11 +59,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): climate_devices = [] for zone in zones: - device = create_climate_device( - tado, hass, zone, zone['name'], zone['id']) - if not device: - continue - climate_devices.append(device) + climate_devices.append(create_climate_device( + tado, hass, zone, zone['name'], zone['id'])) if climate_devices: add_devices(climate_devices, True) @@ -78,11 +75,8 @@ def create_climate_device(tado, hass, zone, name, zone_id): if ac_mode: temperatures = capabilities['HEAT']['temperatures'] - elif 'temperatures' in capabilities: - temperatures = capabilities['temperatures'] else: - _LOGGER.debug("Received zone %s has no temperature; not adding", name) - return + temperatures = capabilities['temperatures'] min_temp = float(temperatures['celsius']['min']) max_temp = float(temperatures['celsius']['max']) diff --git a/homeassistant/components/climate/vera.py b/homeassistant/components/climate/vera.py index c9d22e41d81d07..4644f86cba216e 100644 --- a/homeassistant/components/climate/vera.py +++ b/homeassistant/components/climate/vera.py @@ -32,8 +32,8 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): """Set up of Vera thermostats.""" add_devices_callback( - VeraThermostat(device, hass.data[VERA_CONTROLLER]) for - device in hass.data[VERA_DEVICES]['climate']) + VeraThermostat(device, VERA_CONTROLLER) for + device in VERA_DEVICES['climate']) class VeraThermostat(VeraDevice, ClimateDevice): diff --git a/homeassistant/components/config/group.py b/homeassistant/components/config/group.py index 8b327faa95f387..16e1900c64587a 100644 --- a/homeassistant/components/config/group.py +++ b/homeassistant/components/config/group.py @@ -1,8 +1,8 @@ """Provide configuration end points for Groups.""" import asyncio -from homeassistant.const import SERVICE_RELOAD + from homeassistant.components.config import EditKeyBasedConfigView -from homeassistant.components.group import DOMAIN, GROUP_SCHEMA +from homeassistant.components.group import GROUP_SCHEMA import homeassistant.helpers.config_validation as cv @@ -12,13 +12,7 @@ @asyncio.coroutine def async_setup(hass): """Set up the Group config API.""" - @asyncio.coroutine - def hook(hass): - """post_write_hook for Config View that reloads groups.""" - yield from hass.services.async_call(DOMAIN, SERVICE_RELOAD) - hass.http.register_view(EditKeyBasedConfigView( - 'group', 'config', CONFIG_PATH, cv.slug, GROUP_SCHEMA, - post_write_hook=hook + 'group', 'config', CONFIG_PATH, cv.slug, GROUP_SCHEMA )) return True diff --git a/homeassistant/components/cover/vera.py b/homeassistant/components/cover/vera.py index 6cf269b75b35f4..05be125ec6f95d 100644 --- a/homeassistant/components/cover/vera.py +++ b/homeassistant/components/cover/vera.py @@ -18,8 +18,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Vera covers.""" add_devices( - VeraCover(device, hass.data[VERA_CONTROLLER]) for - device in hass.data[VERA_DEVICES]['cover']) + VeraCover(device, VERA_CONTROLLER) for + device in VERA_DEVICES['cover']) class VeraCover(VeraDevice, CoverDevice): diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 28505900f14552..0b18cc72f6e242 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -53,7 +53,6 @@ CONF_TRACK_NEW = 'track_new_devices' DEFAULT_TRACK_NEW = True -CONF_NEW_DEVICE_DEFAULTS = 'new_device_defaults' CONF_CONSIDER_HOME = 'consider_home' DEFAULT_CONSIDER_HOME = timedelta(seconds=180) @@ -82,18 +81,12 @@ SOURCE_TYPE_GPS = 'gps' SOURCE_TYPE_ROUTER = 'router' -NEW_DEVICE_DEFAULTS_SCHEMA = vol.Any(None, vol.Schema({ - vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean, - vol.Optional(CONF_AWAY_HIDE, default=DEFAULT_AWAY_HIDE): cv.boolean, -})) PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ vol.Optional(CONF_SCAN_INTERVAL): cv.time_period, vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean, vol.Optional(CONF_CONSIDER_HOME, default=DEFAULT_CONSIDER_HOME): vol.All( - cv.time_period, cv.positive_timedelta), - vol.Optional(CONF_NEW_DEVICE_DEFAULTS, - default={}): NEW_DEVICE_DEFAULTS_SCHEMA + cv.time_period, cv.positive_timedelta) }) @@ -132,11 +125,9 @@ def async_setup(hass: HomeAssistantType, config: ConfigType): conf = conf[0] if conf else {} consider_home = conf.get(CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME) track_new = conf.get(CONF_TRACK_NEW, DEFAULT_TRACK_NEW) - defaults = conf.get(CONF_NEW_DEVICE_DEFAULTS, {}) devices = yield from async_load_config(yaml_path, hass, consider_home) - tracker = DeviceTracker( - hass, consider_home, track_new, defaults, devices) + tracker = DeviceTracker(hass, consider_home, track_new, devices) @asyncio.coroutine def async_setup_platform(p_type, p_config, disc_info=None): @@ -220,15 +211,13 @@ class DeviceTracker(object): """Representation of a device tracker.""" def __init__(self, hass: HomeAssistantType, consider_home: timedelta, - track_new: bool, defaults: dict, - devices: Sequence) -> None: + track_new: bool, devices: Sequence) -> None: """Initialize a device tracker.""" self.hass = hass self.devices = {dev.dev_id: dev for dev in devices} self.mac_to_dev = {dev.mac: dev for dev in devices if dev.mac} self.consider_home = consider_home - self.track_new = defaults.get(CONF_TRACK_NEW, track_new) - self.defaults = defaults + self.track_new = track_new self.group = None self._is_updating = asyncio.Lock(loop=hass.loop) @@ -285,8 +274,7 @@ def async_see(self, mac: str=None, dev_id: str=None, host_name: str=None, device = Device( self.hass, self.consider_home, self.track_new, dev_id, mac, (host_name or dev_id).replace('_', ' '), - picture=picture, icon=icon, - hide_if_away=self.defaults.get(CONF_AWAY_HIDE, DEFAULT_AWAY_HIDE)) + picture=picture, icon=icon) self.devices[dev_id] = device if mac is not None: self.mac_to_dev[mac] = device diff --git a/homeassistant/components/device_tracker/linksys_ap.py b/homeassistant/components/device_tracker/linksys_ap.py index 20dc9052e116a3..196235f32f4f62 100644 --- a/homeassistant/components/device_tracker/linksys_ap.py +++ b/homeassistant/components/device_tracker/linksys_ap.py @@ -11,8 +11,7 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv -from homeassistant.components.device_tracker import ( - DOMAIN, PLATFORM_SCHEMA, DeviceScanner) +from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL) @@ -39,7 +38,7 @@ def get_scanner(hass, config): return None -class LinksysAPDeviceScanner(DeviceScanner): +class LinksysAPDeviceScanner(object): """This class queries a Linksys Access Point.""" def __init__(self, config): diff --git a/homeassistant/components/device_tracker/meraki.py b/homeassistant/components/device_tracker/meraki.py deleted file mode 100644 index 319c19d7b73d86..00000000000000 --- a/homeassistant/components/device_tracker/meraki.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -Support for the Meraki CMX location service. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.meraki/ - -""" -import asyncio -import logging -import json - -import voluptuous as vol -import homeassistant.helpers.config_validation as cv -from homeassistant.const import (HTTP_BAD_REQUEST, HTTP_UNPROCESSABLE_ENTITY) -from homeassistant.core import callback -from homeassistant.components.http import HomeAssistantView -from homeassistant.components.device_tracker import ( - PLATFORM_SCHEMA, SOURCE_TYPE_ROUTER) - -CONF_VALIDATOR = 'validator' -CONF_SECRET = 'secret' -DEPENDENCIES = ['http'] -URL = '/api/meraki' -VERSION = '2.0' - - -_LOGGER = logging.getLogger(__name__) - - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_VALIDATOR): cv.string, - vol.Required(CONF_SECRET): cv.string -}) - - -@asyncio.coroutine -def async_setup_scanner(hass, config, async_see, discovery_info=None): - """Set up an endpoint for the Meraki tracker.""" - hass.http.register_view( - MerakiView(config, async_see)) - - return True - - -class MerakiView(HomeAssistantView): - """View to handle Meraki requests.""" - - url = URL - name = 'api:meraki' - - def __init__(self, config, async_see): - """Initialize Meraki URL endpoints.""" - self.async_see = async_see - self.validator = config[CONF_VALIDATOR] - self.secret = config[CONF_SECRET] - - @asyncio.coroutine - def get(self, request): - """Meraki message received as GET.""" - return self.validator - - @asyncio.coroutine - def post(self, request): - """Meraki CMX message received.""" - try: - data = yield from request.json() - except ValueError: - return self.json_message('Invalid JSON', HTTP_BAD_REQUEST) - _LOGGER.debug("Meraki Data from Post: %s", json.dumps(data)) - if not data.get('secret', False): - _LOGGER.error("secret invalid") - return self.json_message('No secret', HTTP_UNPROCESSABLE_ENTITY) - if data['secret'] != self.secret: - _LOGGER.error("Invalid Secret received from Meraki") - return self.json_message('Invalid secret', - HTTP_UNPROCESSABLE_ENTITY) - elif data['version'] != VERSION: - _LOGGER.error("Invalid API version: %s", data['version']) - return self.json_message('Invalid version', - HTTP_UNPROCESSABLE_ENTITY) - else: - _LOGGER.debug('Valid Secret') - if data['type'] not in ('DevicesSeen', 'BluetoothDevicesSeen'): - _LOGGER.error("Unknown Device %s", data['type']) - return self.json_message('Invalid device type', - HTTP_UNPROCESSABLE_ENTITY) - _LOGGER.debug("Processing %s", data['type']) - if len(data["data"]["observations"]) == 0: - _LOGGER.debug("No observations found") - return - self._handle(request.app['hass'], data) - - @callback - def _handle(self, hass, data): - for i in data["data"]["observations"]: - data["data"]["secret"] = "hidden" - mac = i["clientMac"] - _LOGGER.debug("clientMac: %s", mac) - attrs = {} - if i.get('os', False): - attrs['os'] = i['os'] - if i.get('manufacturer', False): - attrs['manufacturer'] = i['manufacturer'] - if i.get('ipv4', False): - attrs['ipv4'] = i['ipv4'] - if i.get('ipv6', False): - attrs['ipv6'] = i['ipv6'] - if i.get('seenTime', False): - attrs['seenTime'] = i['seenTime'] - if i.get('ssid', False): - attrs['ssid'] = i['ssid'] - hass.async_add_job(self.async_see( - mac=mac, - source_type=SOURCE_TYPE_ROUTER, - attributes=attrs - )) diff --git a/homeassistant/components/dominos.py b/homeassistant/components/dominos.py index 0d6645f37c11a0..867bdfafc6b731 100644 --- a/homeassistant/components/dominos.py +++ b/homeassistant/components/dominos.py @@ -58,8 +58,7 @@ vol.Required(ATTR_PHONE): cv.string, vol.Required(ATTR_ADDRESS): cv.string, vol.Optional(ATTR_SHOW_MENU): cv.boolean, - vol.Optional(ATTR_ORDERS, default=[]): vol.All( - cv.ensure_list, [_ORDERS_SCHEMA]), + vol.Optional(ATTR_ORDERS): vol.All(cv.ensure_list, [_ORDERS_SCHEMA]), }), }, extra=vol.ALLOW_EXTRA) @@ -82,8 +81,7 @@ def setup(hass, config): order = DominosOrder(order_info, dominos) entities.append(order) - if entities: - component.add_entities(entities) + component.add_entities(entities) # Return boolean to indicate that initialization was successfully. return True @@ -95,8 +93,7 @@ class Dominos(): def __init__(self, hass, config): """Set up main service.""" conf = config[DOMAIN] - from pizzapi import Address, Customer - from pizzapi.address import StoreException + from pizzapi import Address, Customer, Store self.hass = hass self.customer = Customer( conf.get(ATTR_FIRST_NAME), @@ -108,10 +105,7 @@ def __init__(self, hass, config): *self.customer.address.split(','), country=conf.get(ATTR_COUNTRY)) self.country = conf.get(ATTR_COUNTRY) - try: - self.closest_store = self.address.closest_store() - except StoreException: - self.closest_store = None + self.closest_store = Store() def handle_order(self, call): """Handle ordering pizza.""" @@ -129,32 +123,29 @@ def update_closest_store(self): from pizzapi.address import StoreException try: self.closest_store = self.address.closest_store() - return True except StoreException: - self.closest_store = None - return False + self.closest_store = False def get_menu(self): """Return the products from the closest stores menu.""" - self.update_closest_store() - if self.closest_store is None: + if self.closest_store is False: _LOGGER.warning('Cannot get menu. Store may be closed') - return [] - else: - menu = self.closest_store.get_menu() - product_entries = [] + return + + menu = self.closest_store.get_menu() + product_entries = [] - for product in menu.products: - item = {} - if isinstance(product.menu_data['Variants'], list): - variants = ', '.join(product.menu_data['Variants']) - else: - variants = product.menu_data['Variants'] - item['name'] = product.name - item['variants'] = variants - product_entries.append(item) + for product in menu.products: + item = {} + if isinstance(product.menu_data['Variants'], list): + variants = ', '.join(product.menu_data['Variants']) + else: + variants = product.menu_data['Variants'] + item['name'] = product.name + item['variants'] = variants + product_entries.append(item) - return product_entries + return product_entries class DominosProductListView(http.HomeAssistantView): @@ -201,7 +192,7 @@ def orderable(self): @property def state(self): """Return the state either closed, orderable or unorderable.""" - if self.dominos.closest_store is None: + if self.dominos.closest_store is False: return 'closed' else: return 'orderable' if self._orderable else 'unorderable' @@ -226,11 +217,6 @@ def update(self): def order(self): """Create the order object.""" from pizzapi import Order - from pizzapi.address import StoreException - - if self.dominos.closest_store is None: - raise StoreException - order = Order( self.dominos.closest_store, self.dominos.customer, diff --git a/homeassistant/components/ecobee.py b/homeassistant/components/ecobee.py index b4bb977ee705dd..d69770e3a5e76f 100644 --- a/homeassistant/components/ecobee.py +++ b/homeassistant/components/ecobee.py @@ -16,7 +16,7 @@ from homeassistant.util import Throttle from homeassistant.util.json import save_json -REQUIREMENTS = ['python-ecobee-api==0.0.14'] +REQUIREMENTS = ['python-ecobee-api==0.0.11'] _CONFIGURING = {} _LOGGER = logging.getLogger(__name__) @@ -82,7 +82,6 @@ def setup_ecobee(hass, network, config): hass, 'climate', DOMAIN, {'hold_temp': hold_temp}, config) discovery.load_platform(hass, 'sensor', DOMAIN, {}, config) discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config) - discovery.load_platform(hass, 'weather', DOMAIN, {}, config) class EcobeeData(object): diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 3d669ddc4d167f..74090c7810723c 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -23,7 +23,7 @@ from homeassistant.core import callback from homeassistant.loader import bind_hass -REQUIREMENTS = ['home-assistant-frontend==20171206.0', 'user-agents==1.1.0'] +REQUIREMENTS = ['home-assistant-frontend==20171127.0', 'user-agents==1.1.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] @@ -303,7 +303,7 @@ def async_setup(hass, config): "/home-assistant-polymer", repo_path, False) hass.http.register_static_path( "/static/translations", - os.path.join(repo_path, "build-translations/output"), False) + os.path.join(repo_path, "build-translations"), False) sw_path_es5 = os.path.join(repo_path, "build-es5/service_worker.js") sw_path_latest = os.path.join(repo_path, "build/service_worker.js") static_path = os.path.join(repo_path, 'hass_frontend') @@ -476,8 +476,7 @@ def get_template(self, latest): def get(self, request, extra=None): """Serve the index view.""" hass = request.app['hass'] - latest = self.repo_path is not None or \ - _is_latest(self.js_option, request) + latest = _is_latest(self.js_option, request) if request.path == '/': panel = 'states' @@ -583,9 +582,9 @@ def _is_latest(js_option, request): family_min_version = { 'Chrome': 50, # Probably can reduce this - 'Firefox': 43, # Array.protopype.includes added in 43 + 'Firefox': 41, # Destructuring added in 41 'Opera': 40, # Probably can reduce this - 'Edge': 14, # Array.protopype.includes added in 14 + 'Edge': 14, # Maybe can reduce this 'Safari': 10, # many features not supported by 9 } version = family_min_version.get(useragent.browser.family) diff --git a/homeassistant/components/ios.py b/homeassistant/components/ios.py index ebabcdb0e7955e..cfa1693f571dbc 100644 --- a/homeassistant/components/ios.py +++ b/homeassistant/components/ios.py @@ -264,7 +264,7 @@ def post(self, request): # return self.json_message(humanize_error(request.json, ex), # HTTP_BAD_REQUEST) - data[ATTR_LAST_SEEN_AT] = datetime.datetime.now().isoformat() + data[ATTR_LAST_SEEN_AT] = datetime.datetime.now() name = data.get(ATTR_DEVICE_ID) diff --git a/homeassistant/components/knx.py b/homeassistant/components/knx.py index 3966b490f528f8..d426e79ace9fef 100644 --- a/homeassistant/components/knx.py +++ b/homeassistant/components/knx.py @@ -27,6 +27,7 @@ CONF_KNX_FIRE_EVENT = "fire_event" CONF_KNX_FIRE_EVENT_FILTER = "fire_event_filter" CONF_KNX_STATE_UPDATER = "state_updater" +CONF_KNX_TIME_ADDRESS = "time_address" SERVICE_KNX_SEND = "send" SERVICE_KNX_ATTR_ADDRESS = "address" @@ -60,6 +61,7 @@ vol.All( cv.ensure_list, [cv.string]), + vol.Optional(CONF_KNX_TIME_ADDRESS): cv.string, vol.Optional(CONF_KNX_STATE_UPDATER, default=True): cv.boolean, }) }, extra=vol.ALLOW_EXTRA) @@ -97,6 +99,9 @@ def async_setup(hass, config): ATTR_DISCOVER_DEVICES: found_devices }, config)) + if CONF_KNX_TIME_ADDRESS in config[DOMAIN]: + _add_time_device(hass, config) + hass.services.async_register( DOMAIN, SERVICE_KNX_SEND, hass.data[DATA_KNX].service_send_to_knx_bus, @@ -105,6 +110,17 @@ def async_setup(hass, config): return True +def _add_time_device(hass, config): + """Create time broadcasting device and add it to xknx device queue.""" + import xknx + group_address_time = config[DOMAIN][CONF_KNX_TIME_ADDRESS] + time = xknx.devices.Time( + hass.data[DATA_KNX].xknx, + 'Time', + group_address=group_address_time) + hass.data[DATA_KNX].xknx.devices.add(time) + + def _get_devices(hass, discovery_type): return list( map(lambda device: device.name, diff --git a/homeassistant/components/light/ads.py b/homeassistant/components/light/ads.py deleted file mode 100644 index 41709a4692b6db..00000000000000 --- a/homeassistant/components/light/ads.py +++ /dev/null @@ -1,117 +0,0 @@ -""" -Support for ADS light sources. - -For more details about this platform, please refer to the documentation. -https://home-assistant.io/components/light.ads/ - -""" -import asyncio -import logging -import voluptuous as vol -from homeassistant.components.light import Light, ATTR_BRIGHTNESS, \ - SUPPORT_BRIGHTNESS, PLATFORM_SCHEMA -from homeassistant.const import CONF_NAME -from homeassistant.components.ads import DATA_ADS, CONF_ADS_VAR, \ - CONF_ADS_VAR_BRIGHTNESS -import homeassistant.helpers.config_validation as cv - -_LOGGER = logging.getLogger(__name__) -DEPENDENCIES = ['ads'] -DEFAULT_NAME = 'ADS Light' -CONF_ADSVAR_BRIGHTNESS = 'adsvar_brightness' -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ADS_VAR): cv.string, - vol.Optional(CONF_ADS_VAR_BRIGHTNESS): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the light platform for ADS.""" - ads_hub = hass.data.get(DATA_ADS) - - ads_var_enable = config.get(CONF_ADS_VAR) - ads_var_brightness = config.get(CONF_ADS_VAR_BRIGHTNESS) - name = config.get(CONF_NAME) - - add_devices([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, - name)], True) - - -class AdsLight(Light): - """Representation of ADS light.""" - - def __init__(self, ads_hub, ads_var_enable, ads_var_brightness, name): - """Initialize AdsLight entity.""" - self._ads_hub = ads_hub - self._on_state = False - self._brightness = None - self._name = name - self.ads_var_enable = ads_var_enable - self.ads_var_brightness = ads_var_brightness - - @asyncio.coroutine - def async_added_to_hass(self): - """Register device notification.""" - def update_on_state(name, value): - """Handle device notifications for state.""" - _LOGGER.debug('Variable %s changed its value to %d', name, value) - self._on_state = value - self.schedule_update_ha_state() - - def update_brightness(name, value): - """Handle device notification for brightness.""" - _LOGGER.debug('Variable %s changed its value to %d', name, value) - self._brightness = value - self.schedule_update_ha_state() - - self.hass.async_add_job( - self._ads_hub.add_device_notification, - self.ads_var_enable, self._ads_hub.PLCTYPE_BOOL, update_on_state - ) - self.hass.async_add_job( - self._ads_hub.add_device_notification, - self.ads_var_brightness, self._ads_hub.PLCTYPE_INT, - update_brightness - ) - - @property - def name(self): - """Return the name of the device if any.""" - return self._name - - @property - def brightness(self): - """Return the brightness of the light (0..255).""" - return self._brightness - - @property - def is_on(self): - """Return if light is on.""" - return self._on_state - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False - - @property - def supported_features(self): - """Flag supported features.""" - if self.ads_var_brightness is not None: - return SUPPORT_BRIGHTNESS - - def turn_on(self, **kwargs): - """Turn the light on or set a specific dimmer value.""" - brightness = kwargs.get(ATTR_BRIGHTNESS) - self._ads_hub.write_by_name(self.ads_var_enable, True, - self._ads_hub.PLCTYPE_BOOL) - - if self.ads_var_brightness is not None and brightness is not None: - self._ads_hub.write_by_name(self.ads_var_brightness, brightness, - self._ads_hub.PLCTYPE_UINT) - - def turn_off(self, **kwargs): - """Turn the light off.""" - self._ads_hub.write_by_name(self.ads_var_enable, False, - self._ads_hub.PLCTYPE_BOOL) diff --git a/homeassistant/components/light/tradfri.py b/homeassistant/components/light/tradfri.py index dc8e7f4c996f0d..3bba6da8dd35b3 100644 --- a/homeassistant/components/light/tradfri.py +++ b/homeassistant/components/light/tradfri.py @@ -99,7 +99,7 @@ def brightness(self): @asyncio.coroutine def async_turn_off(self, **kwargs): """Instruct the group lights to turn off.""" - yield from self._api(self._group.set_state(0)) + self.hass.async_add_job(self._api(self._group.set_state(0))) @asyncio.coroutine def async_turn_on(self, **kwargs): @@ -112,10 +112,10 @@ def async_turn_on(self, **kwargs): if kwargs[ATTR_BRIGHTNESS] == 255: kwargs[ATTR_BRIGHTNESS] = 254 - yield from self._api( - self._group.set_dimmer(kwargs[ATTR_BRIGHTNESS], **keys)) + self.hass.async_add_job(self._api( + self._group.set_dimmer(kwargs[ATTR_BRIGHTNESS], **keys))) else: - yield from self._api(self._group.set_state(1)) + self.hass.async_add_job(self._api(self._group.set_state(1))) @callback def _async_start_observe(self, exc=None): @@ -140,11 +140,11 @@ def _refresh(self, group): self._group = group self._name = group.name - @callback def _observe_update(self, tradfri_device): """Receive new state data for this light.""" self._refresh(tradfri_device) - self.async_schedule_update_ha_state() + + self.hass.async_add_job(self.async_update_ha_state()) class TradfriLight(Light): @@ -238,7 +238,8 @@ def rgb_color(self): @asyncio.coroutine def async_turn_off(self, **kwargs): """Instruct the light to turn off.""" - yield from self._api(self._light_control.set_state(False)) + self.hass.async_add_job(self._api( + self._light_control.set_state(False))) @asyncio.coroutine def async_turn_on(self, **kwargs): @@ -249,17 +250,17 @@ def async_turn_on(self, **kwargs): for ATTR_RGB_COLOR, this also supports Philips Hue bulbs. """ if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None: - yield from self._api( + self.hass.async_add_job(self._api( self._light.light_control.set_rgb_color( - *kwargs[ATTR_RGB_COLOR])) + *kwargs[ATTR_RGB_COLOR]))) elif ATTR_COLOR_TEMP in kwargs and \ self._light_data.hex_color is not None and \ self._temp_supported: kelvin = color_util.color_temperature_mired_to_kelvin( kwargs[ATTR_COLOR_TEMP]) - yield from self._api( - self._light_control.set_kelvin_color(kelvin)) + self.hass.async_add_job(self._api( + self._light_control.set_kelvin_color(kelvin))) keys = {} if ATTR_TRANSITION in kwargs: @@ -269,12 +270,12 @@ def async_turn_on(self, **kwargs): if kwargs[ATTR_BRIGHTNESS] == 255: kwargs[ATTR_BRIGHTNESS] = 254 - yield from self._api( + self.hass.async_add_job(self._api( self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS], - **keys)) + **keys))) else: - yield from self._api( - self._light_control.set_state(True)) + self.hass.async_add_job(self._api( + self._light_control.set_state(True))) @callback def _async_start_observe(self, exc=None): @@ -317,11 +318,10 @@ def _refresh(self, light): self._temp_supported = self._light.device_info.manufacturer \ in ALLOWED_TEMPERATURES - @callback def _observe_update(self, tradfri_device): """Receive new state data for this light.""" self._refresh(tradfri_device) self._rgb_color = color_util.rgb_hex_to_rgb_list( self._light_data.hex_color_inferred ) - self.async_schedule_update_ha_state() + self.hass.async_add_job(self.async_update_ha_state()) diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py index 102ca814882917..b3be93d82e289c 100644 --- a/homeassistant/components/light/vera.py +++ b/homeassistant/components/light/vera.py @@ -21,8 +21,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Vera lights.""" add_devices( - VeraLight(device, hass.data[VERA_CONTROLLER]) for - device in hass.data[VERA_DEVICES]['light']) + VeraLight(device, VERA_CONTROLLER) for device in VERA_DEVICES['light']) class VeraLight(VeraDevice, Light): diff --git a/homeassistant/components/lock/vera.py b/homeassistant/components/lock/vera.py index b3aae5e159fafc..04962566821b5f 100644 --- a/homeassistant/components/lock/vera.py +++ b/homeassistant/components/lock/vera.py @@ -19,8 +19,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Find and return Vera locks.""" add_devices( - VeraLock(device, hass.data[VERA_CONTROLLER]) for - device in hass.data[VERA_DEVICES]['lock']) + VeraLock(device, VERA_CONTROLLER) for + device in VERA_DEVICES['lock']) class VeraLock(VeraDevice, LockDevice): diff --git a/homeassistant/components/media_extractor.py b/homeassistant/components/media_extractor.py index 9d5e88282aec50..d1f7f89863c187 100644 --- a/homeassistant/components/media_extractor.py +++ b/homeassistant/components/media_extractor.py @@ -16,7 +16,7 @@ from homeassistant.config import load_yaml_config_file from homeassistant.helpers import config_validation as cv -REQUIREMENTS = ['youtube_dl==2017.11.26'] +REQUIREMENTS = ['youtube_dl==2017.11.15'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 6ae44495e3e22b..ca3da7ae165fe7 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -20,9 +20,7 @@ import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -# Do not upgrade to 1.0.2, it breaks a bunch of stuff -# https://github.com/home-assistant/home-assistant/issues/10926 -REQUIREMENTS = ['pychromecast==0.8.2'] +REQUIREMENTS = ['pychromecast==1.0.2'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/media_player/denonavr.py b/homeassistant/components/media_player/denonavr.py index 0a03af0e1bf033..7fffc09696ce58 100644 --- a/homeassistant/components/media_player/denonavr.py +++ b/homeassistant/components/media_player/denonavr.py @@ -20,7 +20,7 @@ CONF_NAME, STATE_ON, CONF_ZONE, CONF_TIMEOUT) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['denonavr==0.5.5'] +REQUIREMENTS = ['denonavr==0.5.4'] _LOGGER = logging.getLogger(__name__) @@ -102,11 +102,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if config.get(CONF_HOST) is None and discovery_info is None: d_receivers = denonavr.discover() # More than one receiver could be discovered by that method - for d_receiver in d_receivers: - host = d_receiver["host"] - name = d_receiver["friendlyName"] - new_hosts.append( - NewHost(host=host, name=name)) + if d_receivers is not None: + for d_receiver in d_receivers: + host = d_receiver["host"] + name = d_receiver["friendlyName"] + new_hosts.append( + NewHost(host=host, name=name)) for entry in new_hosts: # Check if host not in cache, append it and save for later diff --git a/homeassistant/components/media_player/samsungtv.py b/homeassistant/components/media_player/samsungtv.py index d42bd9ea012588..52235cef24eddc 100644 --- a/homeassistant/components/media_player/samsungtv.py +++ b/homeassistant/components/media_player/samsungtv.py @@ -6,7 +6,6 @@ """ import logging import socket -from datetime import timedelta import voluptuous as vol @@ -18,7 +17,6 @@ CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, CONF_PORT, CONF_MAC) import homeassistant.helpers.config_validation as cv -from homeassistant.util import dt as dt_util REQUIREMENTS = ['samsungctl==0.6.0', 'wakeonlan==0.2.2'] @@ -102,9 +100,6 @@ def __init__(self, host, port, name, timeout, mac): self._playing = True self._state = STATE_UNKNOWN self._remote = None - # Mark the end of a shutdown command (need to wait 15 seconds before - # sending the next command to avoid turning the TV back ON). - self._end_of_power_off = None # Generate a configuration for the Samsung library self._config = { 'name': 'HomeAssistant', @@ -123,7 +118,7 @@ def __init__(self, host, port, name, timeout, mac): def update(self): """Retrieve the latest data.""" # Send an empty key to see if we are still connected - self.send_key('KEY') + return self.send_key('KEY') def get_remote(self): """Create or return a remote control instance.""" @@ -135,10 +130,6 @@ def get_remote(self): def send_key(self, key): """Send a key to the tv and handles exceptions.""" - if self._power_off_in_progress() \ - and not (key == 'KEY_POWER' or key == 'KEY_POWEROFF'): - _LOGGER.info("TV is powering off, not sending command: %s", key) - return try: self.get_remote().control(key) self._state = STATE_ON @@ -148,16 +139,13 @@ def send_key(self, key): # BrokenPipe can occur when the commands is sent to fast self._state = STATE_ON self._remote = None - return + return False except (self._exceptions_class.ConnectionClosed, OSError): self._state = STATE_OFF self._remote = None - if self._power_off_in_progress(): - self._state = STATE_OFF + return False - def _power_off_in_progress(self): - return self._end_of_power_off is not None and \ - self._end_of_power_off > dt_util.utcnow() + return True @property def name(self): @@ -183,8 +171,6 @@ def supported_features(self): def turn_off(self): """Turn off media player.""" - self._end_of_power_off = dt_util.utcnow() + timedelta(seconds=15) - if self._config['method'] == 'websocket': self.send_key('KEY_POWER') else: diff --git a/homeassistant/components/media_player/webostv.py b/homeassistant/components/media_player/webostv.py index 0abdb90e67a6b7..3215ad82a7cbf1 100644 --- a/homeassistant/components/media_player/webostv.py +++ b/homeassistant/components/media_player/webostv.py @@ -322,15 +322,12 @@ def media_play_pause(self): def select_source(self, source): """Select input source.""" - source = self._source_list.get(source) - if source is None: - _LOGGER.warning("Source %s not found for %s", source, self.name) - return - self._current_source_id = self._source_list[source]['id'] - if source.get('title'): + if self._source_list.get(source).get('title'): + self._current_source_id = self._source_list[source]['id'] self._current_source = self._source_list[source]['title'] self._client.launch_app(self._source_list[source]['id']) - elif source.get('label'): + elif self._source_list.get(source).get('label'): + self._current_source_id = self._source_list[source]['id'] self._current_source = self._source_list[source]['label'] self._client.set_input(self._source_list[source]['id']) diff --git a/homeassistant/components/media_player/ziggo_mediabox_xl.py b/homeassistant/components/media_player/ziggo_mediabox_xl.py deleted file mode 100644 index 1886cd751ea87f..00000000000000 --- a/homeassistant/components/media_player/ziggo_mediabox_xl.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -Support for interface with a Ziggo Mediabox XL. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/media_player.ziggo_mediabox_xl/ -""" -import logging -import socket - -import voluptuous as vol - -from homeassistant.components.media_player import ( - PLATFORM_SCHEMA, MediaPlayerDevice, - SUPPORT_TURN_ON, SUPPORT_TURN_OFF, - SUPPORT_NEXT_TRACK, SUPPORT_PREVIOUS_TRACK, SUPPORT_SELECT_SOURCE, - SUPPORT_PLAY, SUPPORT_PAUSE) -from homeassistant.const import ( - CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_PAUSED, STATE_PLAYING) -import homeassistant.helpers.config_validation as cv - -REQUIREMENTS = ['ziggo-mediabox-xl==1.0.0'] - -_LOGGER = logging.getLogger(__name__) - -DATA_KNOWN_DEVICES = 'ziggo_mediabox_xl_known_devices' - -SUPPORT_ZIGGO = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | \ - SUPPORT_NEXT_TRACK | SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | \ - SUPPORT_SELECT_SOURCE | SUPPORT_PLAY - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HOST): cv.string, - vol.Optional(CONF_NAME): cv.string, -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Ziggo Mediabox XL platform.""" - from ziggo_mediabox_xl import ZiggoMediaboxXL - - hass.data[DATA_KNOWN_DEVICES] = known_devices = set() - - # Is this a manual configuration? - if config.get(CONF_HOST) is not None: - host = config.get(CONF_HOST) - name = config.get(CONF_NAME) - elif discovery_info is not None: - host = discovery_info.get('host') - name = discovery_info.get('name') - else: - _LOGGER.error("Cannot determine device") - return - - # Only add a device once, so discovered devices do not override manual - # config. - hosts = [] - ip_addr = socket.gethostbyname(host) - if ip_addr not in known_devices: - try: - mediabox = ZiggoMediaboxXL(ip_addr) - if mediabox.test_connection(): - hosts.append(ZiggoMediaboxXLDevice(mediabox, host, name)) - known_devices.add(ip_addr) - else: - _LOGGER.error("Can't connect to %s", host) - except socket.error as error: - _LOGGER.error("Can't connect to %s: %s", host, error) - else: - _LOGGER.info("Ignoring duplicate Ziggo Mediabox XL %s", host) - add_devices(hosts, True) - - -class ZiggoMediaboxXLDevice(MediaPlayerDevice): - """Representation of a Ziggo Mediabox XL Device.""" - - def __init__(self, mediabox, host, name): - """Initialize the device.""" - # Generate a configuration for the Samsung library - self._mediabox = mediabox - self._host = host - self._name = name - self._state = None - - def update(self): - """Retrieve the state of the device.""" - try: - if self._mediabox.turned_on(): - if self._state != STATE_PAUSED: - self._state = STATE_PLAYING - else: - self._state = STATE_OFF - except socket.error: - _LOGGER.error("Couldn't fetch state from %s", self._host) - - def send_keys(self, keys): - """Send keys to the device and handle exceptions.""" - try: - self._mediabox.send_keys(keys) - except socket.error: - _LOGGER.error("Couldn't send keys to %s", self._host) - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def state(self): - """Return the state of the device.""" - return self._state - - @property - def source_list(self): - """List of available sources (channels).""" - return [self._mediabox.channels()[c] - for c in sorted(self._mediabox.channels().keys())] - - @property - def supported_features(self): - """Flag media player features that are supported.""" - return SUPPORT_ZIGGO - - def turn_on(self): - """Turn the media player on.""" - self.send_keys(['POWER']) - self._state = STATE_ON - - def turn_off(self): - """Turn off media player.""" - self.send_keys(['POWER']) - self._state = STATE_OFF - - def media_play(self): - """Send play command.""" - self.send_keys(['PLAY']) - self._state = STATE_PLAYING - - def media_pause(self): - """Send pause command.""" - self.send_keys(['PAUSE']) - self._state = STATE_PAUSED - - def media_play_pause(self): - """Simulate play pause media player.""" - self.send_keys(['PAUSE']) - if self._state == STATE_PAUSED: - self._state = STATE_PLAYING - else: - self._state = STATE_PAUSED - - def media_next_track(self): - """Channel up.""" - self.send_keys(['CHAN_UP']) - self._state = STATE_PLAYING - - def media_previous_track(self): - """Channel down.""" - self.send_keys(['CHAN_DOWN']) - self._state = STATE_PLAYING - - def select_source(self, source): - """Select the channel.""" - if str(source).isdigit(): - digits = str(source) - else: - digits = next(( - key for key, value in self._mediabox.channels().items() - if value == source), None) - if digits is None: - return - - self.send_keys(['NUM_{}'.format(digit) - for digit in str(digits)]) - self._state = STATE_PLAYING diff --git a/homeassistant/components/neato.py b/homeassistant/components/neato.py index bd680b5361e9e5..e10878833e4394 100644 --- a/homeassistant/components/neato.py +++ b/homeassistant/components/neato.py @@ -17,8 +17,8 @@ _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['https://github.com/jabesq/pybotvac/archive/v0.0.4.zip' - '#pybotvac==0.0.4'] +REQUIREMENTS = ['https://github.com/jabesq/pybotvac/archive/v0.0.3.zip' + '#pybotvac==0.0.3'] DOMAIN = 'neato' NEATO_ROBOTS = 'neato_robots' diff --git a/homeassistant/components/notify/nfandroidtv.py b/homeassistant/components/notify/nfandroidtv.py index 1fa8f1dab78b63..6c4f7e49ddea6d 100644 --- a/homeassistant/components/notify/nfandroidtv.py +++ b/homeassistant/components/notify/nfandroidtv.py @@ -4,9 +4,8 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/notify.nfandroidtv/ """ +import os import logging -import io -import base64 import requests import voluptuous as vol @@ -32,9 +31,6 @@ DEFAULT_COLOR = 'grey' DEFAULT_INTERRUPT = False DEFAULT_TIMEOUT = 5 -DEFAULT_ICON = ( - 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGP6zwAAAgcBApo' - 'cMXEAAAAASUVORK5CYII=') ATTR_DURATION = 'duration' ATTR_POSITION = 'position' @@ -114,13 +110,16 @@ def __init__(self, remoteip, duration, position, transparency, color, self._default_color = color self._default_interrupt = interrupt self._timeout = timeout - self._icon_file = io.BytesIO(base64.b64decode(DEFAULT_ICON)) + self._icon_file = os.path.join( + os.path.dirname(__file__), '..', 'frontend', 'www_static', 'icons', + 'favicon-192x192.png') def send_message(self, message="", **kwargs): """Send a message to a Android TV device.""" _LOGGER.debug("Sending notification to: %s", self._target) - payload = dict(filename=('icon.png', self._icon_file, + payload = dict(filename=('icon.png', + open(self._icon_file, 'rb'), 'application/octet-stream', {'Expires': '0'}), type='0', title=kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT), @@ -130,7 +129,7 @@ def send_message(self, message="", **kwargs): transparency='%i' % TRANSPARENCIES.get( self._default_transparency), offset='0', app=ATTR_TITLE_DEFAULT, force='true', - interrupt='%i' % self._default_interrupt,) + interrupt='%i' % self._default_interrupt) data = kwargs.get(ATTR_DATA) if data: diff --git a/homeassistant/components/prometheus.py b/homeassistant/components/prometheus.py index 0ecfa50ee63607..0396cafd4ffaa4 100644 --- a/homeassistant/components/prometheus.py +++ b/homeassistant/components/prometheus.py @@ -14,13 +14,12 @@ from homeassistant.components import recorder from homeassistant.const import ( CONF_DOMAINS, CONF_ENTITIES, CONF_EXCLUDE, CONF_INCLUDE, TEMP_CELSIUS, - EVENT_STATE_CHANGED, TEMP_FAHRENHEIT, CONTENT_TYPE_TEXT_PLAIN, - ATTR_TEMPERATURE, ATTR_UNIT_OF_MEASUREMENT) + EVENT_STATE_CHANGED, TEMP_FAHRENHEIT, CONTENT_TYPE_TEXT_PLAIN) from homeassistant import core as hacore from homeassistant.helpers import state as state_helper from homeassistant.util.temperature import fahrenheit_to_celsius -REQUIREMENTS = ['prometheus_client==0.0.21'] +REQUIREMENTS = ['prometheus_client==0.0.19'] _LOGGER = logging.getLogger(__name__) @@ -160,26 +159,6 @@ def _handle_lock(self, state): value = state_helper.state_as_number(state) metric.labels(**self._labels(state)).set(value) - def _handle_climate(self, state): - temp = state.attributes.get(ATTR_TEMPERATURE) - if temp: - unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) - if unit == TEMP_FAHRENHEIT: - temp = fahrenheit_to_celsius(temp) - metric = self._metric( - 'temperature_c', self.prometheus_client.Gauge, - 'Temperature in degrees Celsius') - metric.labels(**self._labels(state)).set(temp) - - metric = self._metric( - 'climate_state', self.prometheus_client.Gauge, - 'State of the thermostat (0/1)') - try: - value = state_helper.state_as_number(state) - metric.labels(**self._labels(state)).set(value) - except ValueError: - pass - def _handle_sensor(self, state): _sensor_types = { TEMP_CELSIUS: ( @@ -210,17 +189,9 @@ def _handle_sensor(self, state): 'electricity_usage_w', self.prometheus_client.Gauge, 'Currently reported electricity draw in Watts', ), - 'min': ( - 'sensor_min', self.prometheus_client.Gauge, - 'Time in minutes reported by a sensor' - ), - 'Events': ( - 'sensor_event_count', self.prometheus_client.Gauge, - 'Number of events for a sensor' - ), } - unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + unit = state.attributes.get('unit_of_measurement') metric = _sensor_types.get(unit) if metric is not None: @@ -241,25 +212,12 @@ def _handle_switch(self, state): self.prometheus_client.Gauge, 'State of the switch (0/1)', ) - - try: - value = state_helper.state_as_number(state) - metric.labels(**self._labels(state)).set(value) - except ValueError: - pass + value = state_helper.state_as_number(state) + metric.labels(**self._labels(state)).set(value) def _handle_zwave(self, state): self._battery(state) - def _handle_automation(self, state): - metric = self._metric( - 'automation_triggered_count', - self.prometheus_client.Counter, - 'Count of times an automation has been triggered', - ) - - metric.labels(**self._labels(state)).inc() - class PrometheusView(HomeAssistantView): """Handle Prometheus requests.""" diff --git a/homeassistant/components/scene/vera.py b/homeassistant/components/scene/vera.py deleted file mode 100644 index 3dbb68d214fc63..00000000000000 --- a/homeassistant/components/scene/vera.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Support for Vera scenes. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/scene.vera/ -""" -import logging - -from homeassistant.util import slugify -from homeassistant.components.scene import Scene -from homeassistant.components.vera import ( - VERA_CONTROLLER, VERA_SCENES, VERA_ID_FORMAT) - -DEPENDENCIES = ['vera'] - -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Vera scenes.""" - add_devices( - [VeraScene(scene, hass.data[VERA_CONTROLLER]) - for scene in hass.data[VERA_SCENES]], True) - - -class VeraScene(Scene): - """Representation of a Vera scene entity.""" - - def __init__(self, vera_scene, controller): - """Initialize the scene.""" - self.vera_scene = vera_scene - self.controller = controller - - self._name = self.vera_scene.name - # Append device id to prevent name clashes in HA. - self.vera_id = VERA_ID_FORMAT.format( - slugify(vera_scene.name), vera_scene.scene_id) - - def update(self): - """Update the scene status.""" - self.vera_scene.refresh() - - def activate(self, **kwargs): - """Activate the scene.""" - self.vera_scene.activate() - - @property - def name(self): - """Return the name of the scene.""" - return self._name - - @property - def device_state_attributes(self): - """Return the state attributes of the scene.""" - return {'vera_scene_id': self.vera_scene.vera_scene_id} - - @property - def should_poll(self): - """Return that polling is not necessary.""" - return False diff --git a/homeassistant/components/sensor/ads.py b/homeassistant/components/sensor/ads.py deleted file mode 100644 index 725cbb555f11a8..00000000000000 --- a/homeassistant/components/sensor/ads.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Support for ADS sensors. - -For more details about this platform, please refer to the documentation. -https://home-assistant.io/components/sensor.ads/ - -""" -import asyncio -import logging -import voluptuous as vol -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import CONF_NAME, CONF_UNIT_OF_MEASUREMENT -from homeassistant.helpers.entity import Entity -import homeassistant.helpers.config_validation as cv -from homeassistant.components import ads -from homeassistant.components.ads import CONF_ADS_VAR, CONF_ADS_TYPE, \ - CONF_ADS_FACTOR - - -_LOGGER = logging.getLogger(__name__) - -DEFAULT_NAME = 'ADS sensor' -DEPENDENCIES = ['ads'] - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ADS_VAR): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_UNIT_OF_MEASUREMENT, default=''): cv.string, - vol.Optional(CONF_ADS_TYPE, default=ads.ADSTYPE_INT): vol.In( - [ads.ADSTYPE_INT, ads.ADSTYPE_UINT, ads.ADSTYPE_BYTE] - ), - vol.Optional(CONF_ADS_FACTOR): cv.positive_int, -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up an ADS sensor device.""" - ads_hub = hass.data.get(ads.DATA_ADS) - - ads_var = config.get(CONF_ADS_VAR) - ads_type = config.get(CONF_ADS_TYPE) - name = config.get(CONF_NAME) - unit_of_measurement = config.get(CONF_UNIT_OF_MEASUREMENT) - factor = config.get(CONF_ADS_FACTOR) - - entity = AdsSensor(ads_hub, ads_var, ads_type, name, - unit_of_measurement, factor) - - add_devices([entity]) - - -class AdsSensor(Entity): - """Representation of an ADS sensor entity.""" - - def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement, - factor): - """Initialize AdsSensor entity.""" - self._ads_hub = ads_hub - self._name = name - self._value = None - self._unit_of_measurement = unit_of_measurement - self.ads_var = ads_var - self.ads_type = ads_type - self.factor = factor - - @asyncio.coroutine - def async_added_to_hass(self): - """Register device notification.""" - def update(name, value): - """Handle device notifications.""" - _LOGGER.debug('Variable %s changed its value to %d', name, value) - - # if factor is set use it otherwise not - if self.factor is None: - self._value = value - else: - self._value = value / self.factor - self.schedule_update_ha_state() - - self.hass.async_add_job( - self._ads_hub.add_device_notification, - self.ads_var, self._ads_hub.ADS_TYPEMAP[self.ads_type], update - ) - - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def state(self): - """Return the state of the device.""" - return self._value - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return self._unit_of_measurement - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False diff --git a/homeassistant/components/sensor/alpha_vantage.py b/homeassistant/components/sensor/alpha_vantage.py deleted file mode 100644 index 88ead3301b6fd8..00000000000000 --- a/homeassistant/components/sensor/alpha_vantage.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -Stock market information from Alpha Vantage. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.alpha_vantage/ -""" -from datetime import timedelta -import logging - -import voluptuous as vol - -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY -import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import Entity - -REQUIREMENTS = ['alpha_vantage==1.3.6'] - -_LOGGER = logging.getLogger(__name__) - -ATTR_CLOSE = 'close' -ATTR_HIGH = 'high' -ATTR_LOW = 'low' -ATTR_VOLUME = 'volume' - -CONF_ATTRIBUTION = "Stock market information provided by Alpha Vantage." -CONF_SYMBOLS = 'symbols' - -DEFAULT_SYMBOL = 'GOOGL' - -ICON = 'mdi:currency-usd' - -SCAN_INTERVAL = timedelta(minutes=5) - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_API_KEY): cv.string, - vol.Optional(CONF_SYMBOLS, default=[DEFAULT_SYMBOL]): - vol.All(cv.ensure_list, [cv.string]), -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Alpha Vantage sensor.""" - from alpha_vantage.timeseries import TimeSeries - - api_key = config.get(CONF_API_KEY) - symbols = config.get(CONF_SYMBOLS) - - timeseries = TimeSeries(key=api_key) - - dev = [] - for symbol in symbols: - try: - timeseries.get_intraday(symbol) - except ValueError: - _LOGGER.error( - "API Key is not valid or symbol '%s' not known", symbol) - return - dev.append(AlphaVantageSensor(timeseries, symbol)) - - add_devices(dev, True) - - -class AlphaVantageSensor(Entity): - """Representation of a Alpha Vantage sensor.""" - - def __init__(self, timeseries, symbol): - """Initialize the sensor.""" - self._name = symbol - self._timeseries = timeseries - self._symbol = symbol - self.values = None - self._unit_of_measurement = None - - @property - def name(self): - """Return the name of the sensor.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement of this entity, if any.""" - return self._symbol - - @property - def state(self): - """Return the state of the sensor.""" - return self.values['1. open'] - - @property - def device_state_attributes(self): - """Return the state attributes.""" - if self.values is not None: - return { - ATTR_ATTRIBUTION: CONF_ATTRIBUTION, - ATTR_CLOSE: self.values['4. close'], - ATTR_HIGH: self.values['2. high'], - ATTR_LOW: self.values['3. low'], - ATTR_VOLUME: self.values['5. volume'], - } - - @property - def icon(self): - """Return the icon to use in the frontend, if any.""" - return ICON - - def update(self): - """Get the latest data and updates the states.""" - all_values, _ = self._timeseries.get_intraday(self._symbol) - self.values = next(iter(all_values.values())) diff --git a/homeassistant/components/sensor/deutsche_bahn.py b/homeassistant/components/sensor/deutsche_bahn.py index e07730b53e87fc..04c9ba45c78509 100644 --- a/homeassistant/components/sensor/deutsche_bahn.py +++ b/homeassistant/components/sensor/deutsche_bahn.py @@ -4,17 +4,17 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.deutsche_bahn/ """ -from datetime import timedelta import logging +from datetime import timedelta import voluptuous as vol -from homeassistant.components.sensor import PLATFORM_SCHEMA import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.entity import Entity import homeassistant.util.dt as dt_util +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['schiene==0.19'] +REQUIREMENTS = ['schiene==0.18'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/eliqonline.py b/homeassistant/components/sensor/eliqonline.py index 3e736ed719f25c..dc879fe0d3e26a 100644 --- a/homeassistant/components/sensor/eliqonline.py +++ b/homeassistant/components/sensor/eliqonline.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_ACCESS_TOKEN): cv.string, - vol.Required(CONF_CHANNEL_ID): cv.positive_int, + vol.Optional(CONF_CHANNEL_ID): cv.positive_int, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) diff --git a/homeassistant/components/sensor/fastdotcom.py b/homeassistant/components/sensor/fastdotcom.py index 02dd32c20af390..61f2e000d1d753 100644 --- a/homeassistant/components/sensor/fastdotcom.py +++ b/homeassistant/components/sensor/fastdotcom.py @@ -6,17 +6,16 @@ """ import asyncio import logging - import voluptuous as vol -from homeassistant.components.sensor import DOMAIN, PLATFORM_SCHEMA +import homeassistant.util.dt as dt_util import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import (DOMAIN, PLATFORM_SCHEMA) from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import track_time_change from homeassistant.helpers.restore_state import async_get_last_state -import homeassistant.util.dt as dt_util -REQUIREMENTS = ['fastdotcom==0.0.3'] +REQUIREMENTS = ['fastdotcom==0.0.1'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/gearbest.py b/homeassistant/components/sensor/gearbest.py deleted file mode 100755 index 2bc7e5b3b3a685..00000000000000 --- a/homeassistant/components/sensor/gearbest.py +++ /dev/null @@ -1,127 +0,0 @@ -""" -Parse prices of a item from gearbest. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.gearbest/ -""" -import logging -from datetime import timedelta - -import voluptuous as vol - -from homeassistant.components.sensor import PLATFORM_SCHEMA -import homeassistant.helpers.config_validation as cv -from homeassistant.util import Throttle -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.event import track_time_interval -from homeassistant.const import (CONF_NAME, CONF_ID, CONF_URL, CONF_CURRENCY) - -REQUIREMENTS = ['gearbest_parser==1.0.5'] -_LOGGER = logging.getLogger(__name__) - -CONF_ITEMS = 'items' - -ICON = 'mdi:coin' -MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=2*60*60) # 2h -MIN_TIME_BETWEEN_CURRENCY_UPDATES = timedelta(seconds=12*60*60) # 12h - - -_ITEM_SCHEMA = vol.All( - vol.Schema({ - vol.Exclusive(CONF_URL, 'XOR'): cv.string, - vol.Exclusive(CONF_ID, 'XOR'): cv.string, - vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_CURRENCY): cv.string - }), cv.has_at_least_one_key(CONF_URL, CONF_ID) -) - -_ITEMS_SCHEMA = vol.Schema([_ITEM_SCHEMA]) - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ITEMS): _ITEMS_SCHEMA, - vol.Required(CONF_CURRENCY): cv.string, -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Gearbest sensor.""" - from gearbest_parser import CurrencyConverter - currency = config.get(CONF_CURRENCY) - - sensors = [] - items = config.get(CONF_ITEMS) - - converter = CurrencyConverter() - converter.update() - - for item in items: - try: - sensors.append(GearbestSensor(converter, item, currency)) - except ValueError as exc: - _LOGGER.error(exc) - - def currency_update(event_time): - """Update currency list.""" - converter.update() - - track_time_interval(hass, - currency_update, - MIN_TIME_BETWEEN_CURRENCY_UPDATES) - - add_devices(sensors, True) - - -class GearbestSensor(Entity): - """Implementation of the sensor.""" - - def __init__(self, converter, item, currency): - """Initialize the sensor.""" - from gearbest_parser import GearbestParser - - self._name = item.get(CONF_NAME) - self._parser = GearbestParser() - self._parser.set_currency_converter(converter) - self._item = self._parser.load(item.get(CONF_ID), - item.get(CONF_URL), - item.get(CONF_CURRENCY, currency)) - if self._item is None: - raise ValueError("id and url could not be resolved") - - @property - def name(self): - """Return the name of the item.""" - return self._name if self._name is not None else self._item.name - - @property - def icon(self): - """Return the icon for the frontend.""" - return ICON - - @property - def state(self): - """Return the price of the selected product.""" - return self._item.price - - @property - def unit_of_measurement(self): - """Return the currency.""" - return self._item.currency - - @property - def entity_picture(self): - """Return the image.""" - return self._item.image - - @property - def device_state_attributes(self): - """Return the state attributes.""" - attrs = {'name': self._item.name, - 'description': self._item.description, - 'currency': self._item.currency, - 'url': self._item.url} - return attrs - - @Throttle(MIN_TIME_BETWEEN_UPDATES) - def update(self): - """Get the latest price from gearbest and updates the state.""" - self._item.update() diff --git a/homeassistant/components/sensor/rest.py b/homeassistant/components/sensor/rest.py index 86362e8f2d9f91..2ae1c3674eae63 100644 --- a/homeassistant/components/sensor/rest.py +++ b/homeassistant/components/sensor/rest.py @@ -5,7 +5,6 @@ https://home-assistant.io/components/sensor.rest/ """ import logging -import json import voluptuous as vol import requests @@ -26,7 +25,6 @@ DEFAULT_NAME = 'REST Sensor' DEFAULT_VERIFY_SSL = True -CONF_JSON_ATTRS = 'json_attributes' METHODS = ['POST', 'GET'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -34,7 +32,6 @@ vol.Optional(CONF_AUTHENTICATION): vol.In([HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]), vol.Optional(CONF_HEADERS): {cv.string: cv.string}, - vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv, vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(METHODS), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PASSWORD): cv.string, @@ -58,8 +55,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): headers = config.get(CONF_HEADERS) unit = config.get(CONF_UNIT_OF_MEASUREMENT) value_template = config.get(CONF_VALUE_TEMPLATE) - json_attrs = config.get(CONF_JSON_ATTRS) - if value_template is not None: value_template.hass = hass @@ -73,15 +68,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): rest = RestData(method, resource, auth, headers, payload, verify_ssl) rest.update() - add_devices([RestSensor( - hass, rest, name, unit, value_template, json_attrs)], True) + add_devices([RestSensor(hass, rest, name, unit, value_template)], True) class RestSensor(Entity): """Implementation of a REST sensor.""" - def __init__(self, hass, rest, name, - unit_of_measurement, value_template, json_attrs): + def __init__(self, hass, rest, name, unit_of_measurement, value_template): """Initialize the REST sensor.""" self._hass = hass self.rest = rest @@ -89,8 +82,6 @@ def __init__(self, hass, rest, name, self._state = STATE_UNKNOWN self._unit_of_measurement = unit_of_measurement self._value_template = value_template - self._json_attrs = json_attrs - self._attributes = None @property def name(self): @@ -117,20 +108,6 @@ def update(self): self.rest.update() value = self.rest.data - if self._json_attrs: - self._attributes = {} - try: - json_dict = json.loads(value) - if isinstance(json_dict, dict): - attrs = {k: json_dict[k] for k in self._json_attrs - if k in json_dict} - self._attributes = attrs - else: - _LOGGER.warning("JSON result was not a dictionary") - except ValueError: - _LOGGER.warning("REST result could not be parsed as JSON") - _LOGGER.debug("Erroneous JSON: %s", value) - if value is None: value = STATE_UNKNOWN elif self._value_template is not None: @@ -139,11 +116,6 @@ def update(self): self._state = value - @property - def device_state_attributes(self): - """Return the state attributes.""" - return self._attributes - class RestData(object): """Class for handling the data retrieval.""" diff --git a/homeassistant/components/sensor/tellstick.py b/homeassistant/components/sensor/tellstick.py index 8355add47e92a5..c9f922207e5e19 100644 --- a/homeassistant/components/sensor/tellstick.py +++ b/homeassistant/components/sensor/tellstick.py @@ -14,7 +14,7 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -DEPENDENCIES = ['tellstick'] +REQUIREMENTS = ['tellcore-py==1.1.2'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/tesla.py b/homeassistant/components/sensor/tesla.py index 3f36a1128d6ded..824fec41580270 100644 --- a/homeassistant/components/sensor/tesla.py +++ b/homeassistant/components/sensor/tesla.py @@ -39,7 +39,7 @@ class TeslaSensor(TeslaDevice, Entity): def __init__(self, tesla_device, controller, sensor_type=None): """Initialisation of the sensor.""" self.current_value = None - self._unit = None + self._temperature_units = None self.last_changed_time = None self.type = sensor_type super().__init__(tesla_device, controller) @@ -59,7 +59,7 @@ def state(self): @property def unit_of_measurement(self): """Return the unit_of_measurement of the device.""" - return self._unit + return self._temperature_units def update(self): """Update the state from the sensor.""" @@ -74,9 +74,8 @@ def update(self): tesla_temp_units = self.tesla_device.measurement if tesla_temp_units == 'F': - self._unit = TEMP_FAHRENHEIT + self._temperature_units = TEMP_FAHRENHEIT else: - self._unit = TEMP_CELSIUS + self._temperature_units = TEMP_CELSIUS else: self.current_value = self.tesla_device.battery_level() - self._unit = "%" diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index c81c208e33ec3e..f901bd27dcad67 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -25,8 +25,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Vera controller devices.""" add_devices( - VeraSensor(device, hass.data[VERA_CONTROLLER]) - for device in hass.data[VERA_DEVICES]['sensor']) + VeraSensor(device, VERA_CONTROLLER) + for device in VERA_DEVICES['sensor']) class VeraSensor(VeraDevice, Entity): diff --git a/homeassistant/components/sensor/whois.py b/homeassistant/components/sensor/whois.py index 771c4bc9d73b3c..9f50a4c13db6c7 100644 --- a/homeassistant/components/sensor/whois.py +++ b/homeassistant/components/sensor/whois.py @@ -47,13 +47,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if 'expiration_date' in get_whois(domain, normalized=True): add_devices([WhoisSensor(name, domain)], True) else: - _LOGGER.error( + _LOGGER.warning( "WHOIS lookup for %s didn't contain expiration_date", domain) return except WhoisException as ex: - _LOGGER.error( - "Exception %s occurred during WHOIS lookup for %s", ex, domain) + _LOGGER.error("Exception %s occurred during WHOIS lookup for %s", + ex, + domain) return @@ -70,7 +71,10 @@ def __init__(self, name, domain): self._domain = domain self._state = None - self._attributes = None + self._data = None + self._updated_date = None + self._expiration_date = None + self._name_servers = [] @property def name(self): @@ -95,52 +99,38 @@ def state(self): @property def device_state_attributes(self): """Get the more info attributes.""" - return self._attributes + if self._data: + updated_formatted = self._updated_date.isoformat() + expires_formatted = self._expiration_date.isoformat() - def _empty_state_and_attributes(self): - """Empty the state and attributes on an error.""" - self._state = None - self._attributes = None + return { + ATTR_NAME_SERVERS: ' '.join(self._name_servers), + ATTR_REGISTRAR: self._data['registrar'][0], + ATTR_UPDATED: updated_formatted, + ATTR_EXPIRES: expires_formatted, + } def update(self): - """Get the current WHOIS data for the domain.""" + """Get the current WHOIS data for hostname.""" from pythonwhois.shared import WhoisException try: response = self.whois(self._domain, normalized=True) except WhoisException as ex: _LOGGER.error("Exception %s occurred during WHOIS lookup", ex) - self._empty_state_and_attributes() return if response: - if 'expiration_date' not in response: - _LOGGER.error( - "Failed to find expiration_date in whois lookup response. " - "Did find: %s", ', '.join(response.keys())) - self._empty_state_and_attributes() - return - - if not response['expiration_date']: - _LOGGER.error("Whois response contains empty expiration_date") - self._empty_state_and_attributes() - return - - attrs = {} - - expiration_date = response['expiration_date'][0] - attrs[ATTR_EXPIRES] = expiration_date.isoformat() - - if 'nameservers' in response: - attrs[ATTR_NAME_SERVERS] = ' '.join(response['nameservers']) + self._data = response - if 'updated_date' in response: - attrs[ATTR_UPDATED] = response['updated_date'][0].isoformat() + if self._data['nameservers']: + self._name_servers = self._data['nameservers'] - if 'registrar' in response: - attrs[ATTR_REGISTRAR] = response['registrar'][0] + if 'expiration_date' in self._data: + self._expiration_date = self._data['expiration_date'][0] + if 'updated_date' in self._data: + self._updated_date = self._data['updated_date'][0] - time_delta = (expiration_date - expiration_date.now()) + time_delta = (self._expiration_date - self._expiration_date.now()) - self._attributes = attrs self._state = time_delta.days diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index c532c0dfd208d1..c4e460fdb663f2 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -437,7 +437,7 @@ input_text: set_value: description: Set the value of an input text entity. fields: - entity_id: + entity_id: description: Entity id of the input text to set the new value. example: 'input_text.text1' value: @@ -448,7 +448,7 @@ input_number: set_value: description: Set the value of an input number entity. fields: - entity_id: + entity_id: description: Entity id of the input number to set the new value. example: 'input_number.threshold' value: @@ -457,13 +457,13 @@ input_number: increment: description: Increment the value of an input number entity by its stepping. fields: - entity_id: + entity_id: description: Entity id of the input number the should be incremented. example: 'input_number.threshold' decrement: description: Decrement the value of an input number entity by its stepping. fields: - entity_id: + entity_id: description: Entity id of the input number the should be decremented. example: 'input_number.threshold' diff --git a/homeassistant/components/switch/ads.py b/homeassistant/components/switch/ads.py deleted file mode 100644 index f4abf2391e2a64..00000000000000 --- a/homeassistant/components/switch/ads.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -Support for ADS switch platform. - -For more details about this platform, please refer to the documentation. -https://home-assistant.io/components/switch.ads/ - -""" -import asyncio -import logging -import voluptuous as vol -from homeassistant.components.switch import PLATFORM_SCHEMA -from homeassistant.const import CONF_NAME -from homeassistant.components.ads import DATA_ADS, CONF_ADS_VAR -from homeassistant.helpers.entity import ToggleEntity -import homeassistant.helpers.config_validation as cv - - -_LOGGER = logging.getLogger(__name__) -DEPENDENCIES = ['ads'] -DEFAULT_NAME = 'ADS Switch' -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ADS_VAR): cv.string, - vol.Optional(CONF_NAME): cv.string, -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up switch platform for ADS.""" - ads_hub = hass.data.get(DATA_ADS) - - name = config.get(CONF_NAME) - ads_var = config.get(CONF_ADS_VAR) - - add_devices([AdsSwitch(ads_hub, name, ads_var)], True) - - -class AdsSwitch(ToggleEntity): - """Representation of an Ads switch device.""" - - def __init__(self, ads_hub, name, ads_var): - """Initialize the AdsSwitch entity.""" - self._ads_hub = ads_hub - self._on_state = False - self._name = name - self.ads_var = ads_var - - @asyncio.coroutine - def async_added_to_hass(self): - """Register device notification.""" - def update(name, value): - """Handle device notification.""" - _LOGGER.debug('Variable %s changed its value to %d', - name, value) - self._on_state = value - self.schedule_update_ha_state() - - self.hass.async_add_job( - self._ads_hub.add_device_notification, - self.ads_var, self._ads_hub.PLCTYPE_BOOL, update - ) - - @property - def is_on(self): - """Return if the switch is turned on.""" - return self._on_state - - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def should_poll(self): - """Return False because entity pushes its state to HA.""" - return False - - def turn_on(self, **kwargs): - """Turn the switch on.""" - self._ads_hub.write_by_name(self.ads_var, True, - self._ads_hub.PLCTYPE_BOOL) - - def turn_off(self, **kwargs): - """Turn the switch off.""" - self._ads_hub.write_by_name(self.ads_var, False, - self._ads_hub.PLCTYPE_BOOL) diff --git a/homeassistant/components/switch/tplink.py b/homeassistant/components/switch/tplink.py index 0772cc9277c510..8fa6493862c652 100644 --- a/homeassistant/components/switch/tplink.py +++ b/homeassistant/components/switch/tplink.py @@ -5,6 +5,7 @@ https://home-assistant.io/components/switch.tplink/ """ import logging + import time import voluptuous as vol @@ -22,12 +23,9 @@ ATTR_DAILY_CONSUMPTION = 'daily_consumption' ATTR_CURRENT = 'current' -CONF_LEDS = 'enable_leds' - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_NAME): cv.string, - vol.Optional(CONF_LEDS, default=True): cv.boolean, }) @@ -37,21 +35,18 @@ def setup_platform(hass, config, add_devices, discovery_info=None): from pyHS100 import SmartPlug host = config.get(CONF_HOST) name = config.get(CONF_NAME) - leds_on = config.get(CONF_LEDS) - add_devices([SmartPlugSwitch(SmartPlug(host), name, leds_on)], True) + add_devices([SmartPlugSwitch(SmartPlug(host), name)], True) class SmartPlugSwitch(SwitchDevice): """Representation of a TPLink Smart Plug switch.""" - def __init__(self, smartplug, name, leds_on): + def __init__(self, smartplug, name): """Initialize the switch.""" self.smartplug = smartplug self._name = name - self._leds_on = leds_on self._state = None - self._available = True # Set up emeter cache self._emeter_params = {} @@ -60,11 +55,6 @@ def name(self): """Return the name of the Smart Plug, if any.""" return self._name - @property - def available(self) -> bool: - """Return if switch is available.""" - return self._available - @property def is_on(self): """Return true if switch is on.""" @@ -87,15 +77,12 @@ def update(self): """Update the TP-Link switch's state.""" from pyHS100 import SmartDeviceException try: - self._available = True self._state = self.smartplug.state == \ self.smartplug.SWITCH_STATE_ON if self._name is None: self._name = self.smartplug.alias - self.smartplug.led = self._leds_on - if self.smartplug.has_emeter: emeter_readings = self.smartplug.get_emeter_realtime() @@ -113,9 +100,8 @@ def update(self): self._emeter_params[ATTR_DAILY_CONSUMPTION] \ = "%.2f kW" % emeter_statics[int(time.strftime("%e"))] except KeyError: - # Device returned no daily history + # device returned no daily history pass except (SmartDeviceException, OSError) as ex: - _LOGGER.warning("Could not read state for %s: %s", self.name, ex) - self._available = False + _LOGGER.warning('Could not read state for %s: %s', self.name, ex) diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index d7c284e4ccf515..1e92612b9a9efa 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -19,8 +19,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Vera switches.""" add_devices( - VeraSwitch(device, hass.data[VERA_CONTROLLER]) for - device in hass.data[VERA_DEVICES]['switch']) + VeraSwitch(device, VERA_CONTROLLER) for + device in VERA_DEVICES['switch']) class VeraSwitch(VeraDevice, SwitchDevice): diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index 28bf65bc4c5059..ba7c1afd286b35 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -24,7 +24,7 @@ DOMAIN = 'tellduslive' -REQUIREMENTS = ['tellduslive==0.10.4'] +REQUIREMENTS = ['tellduslive==0.10.3'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/tellstick.py b/homeassistant/components/tellstick.py index bcef0d3fb859ac..91a7c0c69e5157 100644 --- a/homeassistant/components/tellstick.py +++ b/homeassistant/components/tellstick.py @@ -17,7 +17,7 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['tellcore-py==1.1.2', 'tellcore-net==0.3'] +REQUIREMENTS = ['tellcore-py==1.1.2', 'tellcore-net==0.1'] _LOGGER = logging.getLogger(__name__) @@ -42,8 +42,7 @@ CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Inclusive(CONF_HOST, 'tellcore-net'): cv.string, - vol.Inclusive(CONF_PORT, 'tellcore-net'): - vol.All(cv.ensure_list, [cv.port], vol.Length(min=2, max=2)), + vol.Inclusive(CONF_PORT, 'tellcore-net'): cv.port, vol.Optional(CONF_SIGNAL_REPETITIONS, default=DEFAULT_SIGNAL_REPETITIONS): vol.Coerce(int), }), @@ -74,12 +73,11 @@ def setup(hass, config): conf = config.get(DOMAIN, {}) net_host = conf.get(CONF_HOST) - net_ports = conf.get(CONF_PORT) + net_port = conf.get(CONF_PORT) # Initialize remote tellcore client - if net_host: - net_client = TellCoreClient( - host=net_host, port_client=net_ports[0], port_events=net_ports[1]) + if net_host and net_port: + net_client = TellCoreClient(net_host, net_port) net_client.start() def stop_tellcore_net(event): diff --git a/homeassistant/components/tts/microsoft.py b/homeassistant/components/tts/microsoft.py index 3043e9f418bbcb..4f4c5eb959ddc6 100644 --- a/homeassistant/components/tts/microsoft.py +++ b/homeassistant/components/tts/microsoft.py @@ -15,18 +15,14 @@ CONF_GENDER = 'gender' CONF_OUTPUT = 'output' -CONF_RATE = 'rate' -CONF_VOLUME = 'volume' -CONF_PITCH = 'pitch' -CONF_CONTOUR = 'contour' -REQUIREMENTS = ["pycsspeechtts==1.0.2"] +REQUIREMENTS = ["pycsspeechtts==1.0.1"] _LOGGER = logging.getLogger(__name__) SUPPORTED_LANGUAGES = [ 'ar-eg', 'ar-sa', 'ca-es', 'cs-cz', 'da-dk', 'de-at', 'de-ch', 'de-de', - 'el-gr', 'en-au', 'en-ca', 'en-gb', 'en-ie', 'en-in', 'en-us', 'es-es', + 'el-gr', 'en-au', 'en-ca', 'en-ga', 'en-ie', 'en-in', 'en-us', 'es-es', 'en-mx', 'fi-fi', 'fr-ca', 'fr-ch', 'fr-fr', 'he-il', 'hi-in', 'hu-hu', 'id-id', 'it-it', 'ja-jp', 'ko-kr', 'nb-no', 'nl-nl', 'pl-pl', 'pt-br', 'pt-pt', 'ro-ro', 'ru-ru', 'sk-sk', 'sv-se', 'th-th', 'tr-tr', 'zh-cn', @@ -41,48 +37,31 @@ DEFAULT_GENDER = 'Female' DEFAULT_TYPE = 'ZiraRUS' DEFAULT_OUTPUT = 'audio-16khz-128kbitrate-mono-mp3' -DEFAULT_RATE = 0 -DEFAULT_VOLUME = 0 -DEFAULT_PITCH = "default" -DEFAULT_CONTOUR = "" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORTED_LANGUAGES), vol.Optional(CONF_GENDER, default=DEFAULT_GENDER): vol.In(GENDERS), vol.Optional(CONF_TYPE, default=DEFAULT_TYPE): cv.string, - vol.Optional(CONF_RATE, default=DEFAULT_RATE): - vol.All(vol.Coerce(int), vol.Range(-100, 100)), - vol.Optional(CONF_VOLUME, default=DEFAULT_VOLUME): - vol.All(vol.Coerce(int), vol.Range(-100, 100)), - vol.Optional(CONF_PITCH, default=DEFAULT_PITCH): cv.string, - vol.Optional(CONF_CONTOUR, default=DEFAULT_CONTOUR): cv.string, }) def get_engine(hass, config): """Set up Microsoft speech component.""" return MicrosoftProvider(config[CONF_API_KEY], config[CONF_LANG], - config[CONF_GENDER], config[CONF_TYPE], - config[CONF_RATE], config[CONF_VOLUME], - config[CONF_PITCH], config[CONF_CONTOUR]) + config[CONF_GENDER], config[CONF_TYPE]) class MicrosoftProvider(Provider): """The Microsoft speech API provider.""" - def __init__(self, apikey, lang, gender, ttype, rate, volume, - pitch, contour): + def __init__(self, apikey, lang, gender, ttype): """Init Microsoft TTS service.""" self._apikey = apikey self._lang = lang self._gender = gender self._type = ttype self._output = DEFAULT_OUTPUT - self._rate = "{}%".format(rate) - self._volume = "{}%".format(volume) - self._pitch = pitch - self._contour = contour self.name = 'Microsoft' @property @@ -102,11 +81,8 @@ def get_tts_audio(self, message, language, options=None): from pycsspeechtts import pycsspeechtts try: trans = pycsspeechtts.TTSTranslator(self._apikey) - data = trans.speak(language=language, gender=self._gender, - voiceType=self._type, output=self._output, - rate=self._rate, volume=self._volume, - pitch=self._pitch, contour=self._contour, - text=message) + data = trans.speak(language, self._gender, self._type, + self._output, message) except HTTPException as ex: _LOGGER.error("Error occurred for Microsoft TTS: %s", ex) return(None, None) diff --git a/homeassistant/components/updater.py b/homeassistant/components/updater.py index c67beee62dd772..cb9e5681dca295 100644 --- a/homeassistant/components/updater.py +++ b/homeassistant/components/updater.py @@ -4,28 +4,28 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/updater/ """ -# pylint: disable=no-name-in-module, import-error import asyncio -from datetime import timedelta -from distutils.version import StrictVersion import json import logging import os import platform import uuid +from datetime import timedelta +# pylint: disable=no-name-in-module, import-error +from distutils.version import StrictVersion import aiohttp import async_timeout import voluptuous as vol -from homeassistant.const import ATTR_FRIENDLY_NAME -from homeassistant.const import __version__ as current_version -from homeassistant.helpers import event from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util +from homeassistant.const import ( + ATTR_FRIENDLY_NAME, __version__ as current_version) +from homeassistant.helpers import event -REQUIREMENTS = ['distro==1.1.0'] +REQUIREMENTS = ['distro==1.0.4'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/vacuum/xiaomi_miio.py b/homeassistant/components/vacuum/xiaomi_miio.py index a2265706d87161..131f5d5a77fd40 100644 --- a/homeassistant/components/vacuum/xiaomi_miio.py +++ b/homeassistant/components/vacuum/xiaomi_miio.py @@ -48,8 +48,6 @@ ATTR_CLEANING_TIME = 'cleaning_time' ATTR_DO_NOT_DISTURB = 'do_not_disturb' -ATTR_DO_NOT_DISTURB_START = 'do_not_disturb_start' -ATTR_DO_NOT_DISTURB_END = 'do_not_disturb_end' ATTR_MAIN_BRUSH_LEFT = 'main_brush_left' ATTR_SIDE_BRUSH_LEFT = 'side_brush_left' ATTR_FILTER_LEFT = 'filter_left' @@ -89,7 +87,7 @@ @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the Xiaomi vacuum cleaner robot platform.""" - from miio import Vacuum + from mirobo import Vacuum if PLATFORM not in hass.data: hass.data[PLATFORM] = {} @@ -157,7 +155,6 @@ def __init__(self, name, vacuum): self.consumable_state = None self.clean_history = None - self.dnd_state = None @property def name(self): @@ -203,9 +200,7 @@ def device_state_attributes(self): if self.vacuum_state is not None: attrs.update({ ATTR_DO_NOT_DISTURB: - STATE_ON if self.dnd_state.enabled else STATE_OFF, - ATTR_DO_NOT_DISTURB_START: str(self.dnd_state.start), - ATTR_DO_NOT_DISTURB_END: str(self.dnd_state.end), + STATE_ON if self.vacuum_state.dnd else STATE_OFF, # Not working --> 'Cleaning mode': # STATE_ON if self.vacuum_state.in_cleaning else STATE_OFF, ATTR_CLEANING_TIME: int( @@ -228,6 +223,7 @@ def device_state_attributes(self): / 3600)}) if self.vacuum_state.got_error: attrs[ATTR_ERROR] = self.vacuum_state.error + return attrs @property @@ -248,11 +244,11 @@ def supported_features(self): @asyncio.coroutine def _try_command(self, mask_error, func, *args, **kwargs): """Call a vacuum command handling error messages.""" - from miio import DeviceException + from mirobo import DeviceException, VacuumException try: yield from self.hass.async_add_job(partial(func, *args, **kwargs)) return True - except DeviceException as exc: + except (DeviceException, VacuumException) as exc: _LOGGER.error(mask_error, exc) return False @@ -369,15 +365,12 @@ def async_remote_control_move_step(self, def update(self): """Fetch state from the device.""" - from miio import DeviceException + from mirobo import DeviceException try: state = self._vacuum.status() self.vacuum_state = state - self.consumable_state = self._vacuum.consumable_status() self.clean_history = self._vacuum.clean_history() - self.dnd_state = self._vacuum.dnd_status() - self._is_on = state.is_on self._available = True except OSError as exc: diff --git a/homeassistant/components/vera.py b/homeassistant/components/vera.py index b15c4ddabfdd5a..7418ca812a1ee4 100644 --- a/homeassistant/components/vera.py +++ b/homeassistant/components/vera.py @@ -19,13 +19,13 @@ EVENT_HOMEASSISTANT_STOP, CONF_LIGHTS, CONF_EXCLUDE) from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['pyvera==0.2.39'] +REQUIREMENTS = ['pyvera==0.2.38'] _LOGGER = logging.getLogger(__name__) DOMAIN = 'vera' -VERA_CONTROLLER = 'vera_controller' +VERA_CONTROLLER = None CONF_CONTROLLER = 'vera_controller_url' @@ -34,8 +34,7 @@ ATTR_CURRENT_POWER_W = "current_power_w" ATTR_CURRENT_ENERGY_KWH = "current_energy_kwh" -VERA_DEVICES = 'vera_devices' -VERA_SCENES = 'vera_scenes' +VERA_DEVICES = defaultdict(list) VERA_ID_LIST_SCHEMA = vol.Schema([int]) @@ -48,20 +47,20 @@ }, extra=vol.ALLOW_EXTRA) VERA_COMPONENTS = [ - 'binary_sensor', 'sensor', 'light', 'switch', - 'lock', 'climate', 'cover', 'scene' + 'binary_sensor', 'sensor', 'light', 'switch', 'lock', 'climate', 'cover' ] # pylint: disable=unused-argument, too-many-function-args def setup(hass, base_config): """Set up for Vera devices.""" + global VERA_CONTROLLER import pyvera as veraApi def stop_subscription(event): """Shutdown Vera subscriptions and subscription thread on exit.""" _LOGGER.info("Shutting down subscriptions") - hass.data[VERA_CONTROLLER].stop() + VERA_CONTROLLER.stop() config = base_config.get(DOMAIN) @@ -71,14 +70,11 @@ def stop_subscription(event): exclude_ids = config.get(CONF_EXCLUDE) # Initialize the Vera controller. - controller, _ = veraApi.init_controller(base_url) - hass.data[VERA_CONTROLLER] = controller + VERA_CONTROLLER, _ = veraApi.init_controller(base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription) try: - all_devices = controller.get_devices() - - all_scenes = controller.get_scenes() + all_devices = VERA_CONTROLLER.get_devices() except RequestException: # There was a network related error connecting to the Vera controller. _LOGGER.exception("Error communicating with Vera API") @@ -88,19 +84,12 @@ def stop_subscription(event): devices = [device for device in all_devices if device.device_id not in exclude_ids] - vera_devices = defaultdict(list) for device in devices: device_type = map_vera_device(device, light_ids) if device_type is None: continue - vera_devices[device_type].append(device) - hass.data[VERA_DEVICES] = vera_devices - - vera_scenes = [] - for scene in all_scenes: - vera_scenes.append(scene) - hass.data[VERA_SCENES] = vera_scenes + VERA_DEVICES[device_type].append(device) for component in VERA_COMPONENTS: discovery.load_platform(hass, component, DOMAIN, {}, base_config) diff --git a/homeassistant/components/weather/ecobee.py b/homeassistant/components/weather/ecobee.py deleted file mode 100644 index 379f5c1211ba62..00000000000000 --- a/homeassistant/components/weather/ecobee.py +++ /dev/null @@ -1,167 +0,0 @@ -""" -Support for displaying weather info from Ecobee API. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/weather.ecobee/ -""" -from homeassistant.components import ecobee -from homeassistant.components.weather import ( - WeatherEntity, ATTR_FORECAST_TEMP, ATTR_FORECAST_TIME) -from homeassistant.const import (TEMP_FAHRENHEIT) - - -DEPENDENCIES = ['ecobee'] - -ATTR_FORECAST_CONDITION = 'condition' -ATTR_FORECAST_TEMP_LOW = 'templow' -ATTR_FORECAST_TEMP_HIGH = 'temphigh' -ATTR_FORECAST_PRESSURE = 'pressure' -ATTR_FORECAST_VISIBILITY = 'visibility' -ATTR_FORECAST_WIND_SPEED = 'windspeed' -ATTR_FORECAST_HUMIDITY = 'humidity' - -MISSING_DATA = -5002 - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Ecobee weather component.""" - if discovery_info is None: - return - dev = list() - data = ecobee.NETWORK - for index in range(len(data.ecobee.thermostats)): - thermostat = data.ecobee.get_thermostat(index) - if 'weather' in thermostat: - dev.append(EcobeeWeather(thermostat['name'], index)) - - add_devices(dev, True) - - -class EcobeeWeather(WeatherEntity): - """Representation of Ecobee weather data.""" - - def __init__(self, name, index): - """Initialize the sensor.""" - self._name = name - self._index = index - self.weather = None - - def get_forecast(self, index, param): - """Retrieve forecast parameter.""" - try: - forecast = self.weather['forecasts'][index] - return forecast[param] - except (ValueError, IndexError, KeyError): - raise ValueError - - @property - def name(self): - """Return the name of the sensor.""" - return self._name - - @property - def condition(self): - """Return the current condition.""" - try: - return self.get_forecast(0, 'condition') - except ValueError: - return None - - @property - def temperature(self): - """Return the temperature.""" - try: - return float(self.get_forecast(0, 'temperature')) / 10 - except ValueError: - return None - - @property - def temperature_unit(self): - """Return the unit of measurement.""" - return TEMP_FAHRENHEIT - - @property - def pressure(self): - """Return the pressure.""" - try: - return int(self.get_forecast(0, 'pressure')) - except ValueError: - return None - - @property - def humidity(self): - """Return the humidity.""" - try: - return int(self.get_forecast(0, 'relativeHumidity')) - except ValueError: - return None - - @property - def visibility(self): - """Return the visibility.""" - try: - return int(self.get_forecast(0, 'visibility')) - except ValueError: - return None - - @property - def wind_speed(self): - """Return the wind speed.""" - try: - return int(self.get_forecast(0, 'windSpeed')) - except ValueError: - return None - - @property - def wind_bearing(self): - """Return the wind direction.""" - try: - return int(self.get_forecast(0, 'windBearing')) - except ValueError: - return None - - @property - def attribution(self): - """Return the attribution.""" - if self.weather: - station = self.weather.get('weatherStation', "UNKNOWN") - time = self.weather.get('timestamp', "UNKNOWN") - return "Ecobee weather provided by {} at {}".format(station, time) - return None - - @property - def forecast(self): - """Return the forecast array.""" - try: - forecasts = [] - for day in self.weather['forecasts']: - forecast = { - ATTR_FORECAST_TIME: day['dateTime'], - ATTR_FORECAST_CONDITION: day['condition'], - ATTR_FORECAST_TEMP: float(day['tempHigh']) / 10, - } - if day['tempHigh'] == MISSING_DATA: - break - if day['tempLow'] != MISSING_DATA: - forecast[ATTR_FORECAST_TEMP_LOW] = \ - float(day['tempLow']) / 10 - if day['pressure'] != MISSING_DATA: - forecast[ATTR_FORECAST_PRESSURE] = int(day['pressure']) - if day['windSpeed'] != MISSING_DATA: - forecast[ATTR_FORECAST_WIND_SPEED] = int(day['windSpeed']) - if day['visibility'] != MISSING_DATA: - forecast[ATTR_FORECAST_WIND_SPEED] = int(day['visibility']) - if day['relativeHumidity'] != MISSING_DATA: - forecast[ATTR_FORECAST_HUMIDITY] = \ - int(day['relativeHumidity']) - forecasts.append(forecast) - return forecasts - except (ValueError, IndexError, KeyError): - return None - - def update(self): - """Get the latest state of the sensor.""" - data = ecobee.NETWORK - data.update() - thermostat = data.ecobee.get_thermostat(self._index) - self.weather = thermostat.get('weather', None) diff --git a/homeassistant/components/wink/__init__.py b/homeassistant/components/wink/__init__.py index 18e14b2e91286c..426893ec306794 100644 --- a/homeassistant/components/wink/__init__.py +++ b/homeassistant/components/wink/__init__.py @@ -28,7 +28,7 @@ from homeassistant.config import load_yaml_config_file from homeassistant.util.json import load_json, save_json -REQUIREMENTS = ['python-wink==1.7.1', 'pubnubsub-handler==1.0.2'] +REQUIREMENTS = ['python-wink==1.7.0', 'pubnubsub-handler==1.0.2'] _LOGGER = logging.getLogger(__name__) @@ -460,11 +460,10 @@ def service_handle(service): sirens_to_set.append(siren) for siren in sirens_to_set: - _man = siren.wink.device_manufacturer() if (service.service != SERVICE_SET_AUTO_SHUTOFF and service.service != SERVICE_ENABLE_SIREN and - (_man != 'dome' and _man != 'wink')): - _LOGGER.error("Service only valid for Dome or Wink sirens.") + siren.wink.device_manufacturer() != 'dome'): + _LOGGER.error("Service only valid for Dome sirens.") return if service.service == SERVICE_ENABLE_SIREN: @@ -495,11 +494,10 @@ def service_handle(service): component = EntityComponent(_LOGGER, DOMAIN, hass) sirens = [] - has_dome_or_wink_siren = False + has_dome_siren = False for siren in pywink.get_sirens(): - _man = siren.device_manufacturer() - if _man == "dome" or _man == "wink": - has_dome_or_wink_siren = True + if siren.device_manufacturer() == "dome": + has_dome_siren = True _id = siren.object_id() + siren.name() if _id not in hass.data[DOMAIN]['unique_ids']: sirens.append(WinkSirenDevice(siren, hass)) @@ -516,7 +514,7 @@ def service_handle(service): descriptions.get(SERVICE_ENABLE_SIREN), schema=ENABLED_SIREN_SCHEMA) - if has_dome_or_wink_siren: + if has_dome_siren: hass.services.register(DOMAIN, SERVICE_SET_SIREN_TONE, service_handle, diff --git a/homeassistant/components/xiaomi_aqara.py b/homeassistant/components/xiaomi_aqara.py index 678ead981c11ba..f875edef310290 100644 --- a/homeassistant/components/xiaomi_aqara.py +++ b/homeassistant/components/xiaomi_aqara.py @@ -219,9 +219,7 @@ def device_state_attributes(self): def push_data(self, data): """Push from Hub.""" _LOGGER.debug("PUSH >> %s: %s", self, data) - is_data = self.parse_data(data) - is_voltage = self.parse_voltage(data) - if is_data or is_voltage: + if self.parse_data(data) or self.parse_voltage(data): self.schedule_update_ha_state() def parse_voltage(self, data): diff --git a/homeassistant/components/zwave/node_entity.py b/homeassistant/components/zwave/node_entity.py index de8ca0c1ab9f3e..04446cff9a143f 100644 --- a/homeassistant/components/zwave/node_entity.py +++ b/homeassistant/components/zwave/node_entity.py @@ -137,9 +137,6 @@ def node_changed(self): if self.node.can_wake_up(): for value in self.node.get_values(COMMAND_CLASS_WAKE_UP).values(): - if value.index != 0: - continue - self.wakeup_interval = value.data break else: diff --git a/homeassistant/const.py b/homeassistant/const.py index 85047f0482e6e4..f46058b186c159 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 -MINOR_VERSION = 60 +MINOR_VERSION = 59 PATCH_VERSION = '0.dev0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) @@ -52,7 +52,6 @@ CONF_CUSTOMIZE = 'customize' CONF_CUSTOMIZE_DOMAIN = 'customize_domain' CONF_CUSTOMIZE_GLOB = 'customize_glob' -CONF_DELAY_TIME = 'delay_time' CONF_DEVICE = 'device' CONF_DEVICE_CLASS = 'device_class' CONF_DEVICES = 'devices' diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index 254a48c3d0a8e8..8b98bfadb68e80 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -21,8 +21,7 @@ ATTR_HUMIDITY, ATTR_OPERATION_MODE, ATTR_SWING_MODE, SERVICE_SET_AUX_HEAT, SERVICE_SET_AWAY_MODE, SERVICE_SET_HOLD_MODE, SERVICE_SET_FAN_MODE, SERVICE_SET_HUMIDITY, SERVICE_SET_OPERATION_MODE, - SERVICE_SET_SWING_MODE, SERVICE_SET_TEMPERATURE, STATE_HEAT, STATE_COOL, - STATE_IDLE) + SERVICE_SET_SWING_MODE, SERVICE_SET_TEMPERATURE) from homeassistant.components.climate.ecobee import ( ATTR_FAN_MIN_ON_TIME, SERVICE_SET_FAN_MIN_ON_TIME, ATTR_RESUME_ALL, SERVICE_RESUME_PROGRAM) @@ -211,11 +210,10 @@ def state_as_number(state): Raises ValueError if this is not possible. """ if state.state in (STATE_ON, STATE_LOCKED, STATE_ABOVE_HORIZON, - STATE_OPEN, STATE_HOME, STATE_HEAT, STATE_COOL): + STATE_OPEN, STATE_HOME): return 1 elif state.state in (STATE_OFF, STATE_UNLOCKED, STATE_UNKNOWN, - STATE_BELOW_HORIZON, STATE_CLOSED, STATE_NOT_HOME, - STATE_IDLE): + STATE_BELOW_HORIZON, STATE_CLOSED, STATE_NOT_HOME): return 0 return float(state.state) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 2e7acb212e2295..056ed2f3fa61e2 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -5,8 +5,8 @@ pip>=8.0.3 jinja2>=2.9.6 voluptuous==0.10.5 typing>=3,<4 -aiohttp==2.3.5 -yarl==0.15.0 +aiohttp==2.3.2 +yarl==0.14.0 async_timeout==2.0.0 chardet==3.0.4 astral==1.4 diff --git a/requirements_all.txt b/requirements_all.txt index ff16230f248cef..37936875e85c14 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -6,8 +6,8 @@ pip>=8.0.3 jinja2>=2.9.6 voluptuous==0.10.5 typing>=3,<4 -aiohttp==2.3.5 -yarl==0.15.0 +aiohttp==2.3.2 +yarl==0.14.0 async_timeout==2.0.0 chardet==3.0.4 astral==1.4 @@ -83,9 +83,6 @@ aiopvapi==1.5.4 # homeassistant.components.alarmdecoder alarmdecoder==0.12.3 -# homeassistant.components.sensor.alpha_vantage -alpha_vantage==1.3.6 - # homeassistant.components.amcrest amcrest==1.2.1 @@ -200,7 +197,7 @@ defusedxml==0.5.0 deluge-client==1.0.5 # homeassistant.components.media_player.denonavr -denonavr==0.5.5 +denonavr==0.5.4 # homeassistant.components.media_player.directv directpy==0.2 @@ -209,7 +206,7 @@ directpy==0.2 discord.py==0.16.12 # homeassistant.components.updater -distro==1.1.0 +distro==1.0.4 # homeassistant.components.switch.digitalloggers dlipower==0.7.165 @@ -250,7 +247,7 @@ evohomeclient==0.2.5 # face_recognition==1.0.0 # homeassistant.components.sensor.fastdotcom -fastdotcom==0.0.3 +fastdotcom==0.0.1 # homeassistant.components.sensor.fedex fedexdeliverymanager==1.0.4 @@ -291,9 +288,6 @@ gTTS-token==1.1.1 # homeassistant.components.device_tracker.bluetooth_le_tracker # gattlib==0.20150805 -# homeassistant.components.sensor.gearbest -gearbest_parser==1.0.5 - # homeassistant.components.sensor.gitter gitterpy==0.1.6 @@ -337,7 +331,7 @@ hipnotify==1.0.8 holidays==0.8.1 # homeassistant.components.frontend -home-assistant-frontend==20171206.0 +home-assistant-frontend==20171127.0 # homeassistant.components.camera.onvif http://github.com/tgaugry/suds-passworddigest-py3/archive/86fc50e39b4d2b8997481967d6a7fe1c57118999.zip#suds-passworddigest-py3==0.1.2a @@ -358,7 +352,7 @@ https://github.com/happyleavesaoc/spotipy/archive/544614f4b1d508201d363e84e871f8 https://github.com/jabesq/netatmo-api-python/archive/v0.9.2.1.zip#lnetatmo==0.9.2.1 # homeassistant.components.neato -https://github.com/jabesq/pybotvac/archive/v0.0.4.zip#pybotvac==0.0.4 +https://github.com/jabesq/pybotvac/archive/v0.0.3.zip#pybotvac==0.0.3 # homeassistant.components.sensor.sabnzbd https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 @@ -563,7 +557,7 @@ pocketcasts==0.1 proliphix==0.4.1 # homeassistant.components.prometheus -prometheus_client==0.0.21 +prometheus_client==0.0.19 # homeassistant.components.sensor.systemmonitor psutil==5.4.1 @@ -603,9 +597,6 @@ pyTibber==0.2.1 # homeassistant.components.switch.dlink pyW215==0.6.0 -# homeassistant.components.ads -pyads==2.2.6 - # homeassistant.components.sensor.airvisual pyairvisual==1.0.0 @@ -632,7 +623,7 @@ pybbox==0.0.5-alpha # pybluez==0.22 # homeassistant.components.media_player.cast -pychromecast==0.8.2 +pychromecast==1.0.2 # homeassistant.components.media_player.cmus pycmus==0.1.0 @@ -641,7 +632,7 @@ pycmus==0.1.0 pycomfoconnect==0.3 # homeassistant.components.tts.microsoft -pycsspeechtts==1.0.2 +pycsspeechtts==1.0.1 # homeassistant.components.sensor.cups # pycups==1.9.73 @@ -691,9 +682,6 @@ pyhomematic==0.1.35 # homeassistant.components.sensor.hydroquebec pyhydroquebec==1.3.1 -# homeassistant.components.alarm_control_panel.ialarm -pyialarm==0.2 - # homeassistant.components.device_tracker.icloud pyicloud==0.9.1 @@ -821,7 +809,7 @@ python-clementine-remote==1.0.1 python-digitalocean==1.12 # homeassistant.components.ecobee -python-ecobee-api==0.0.14 +python-ecobee-api==0.0.11 # homeassistant.components.climate.eq3btsmart # python-eq3bt==0.1.6 @@ -895,7 +883,7 @@ python-velbus==2.0.11 python-vlc==1.1.2 # homeassistant.components.wink -python-wink==1.7.1 +python-wink==1.7.0 # homeassistant.components.sensor.swiss_public_transport python_opendata_transport==0.0.3 @@ -925,7 +913,7 @@ pyunifi==2.13 # pyuserinput==0.1.11 # homeassistant.components.vera -pyvera==0.2.39 +pyvera==0.2.38 # homeassistant.components.media_player.vizio pyvizio==0.0.2 @@ -994,7 +982,7 @@ samsungctl==0.6.0 satel_integra==0.1.0 # homeassistant.components.sensor.deutsche_bahn -schiene==0.19 +schiene==0.18 # homeassistant.components.scsgate scsgate==0.1.0 @@ -1069,13 +1057,14 @@ tank_utility==1.4.0 tapsaff==0.1.3 # homeassistant.components.tellstick -tellcore-net==0.3 +tellcore-net==0.1 # homeassistant.components.tellstick +# homeassistant.components.sensor.tellstick tellcore-py==1.1.2 # homeassistant.components.tellduslive -tellduslive==0.10.4 +tellduslive==0.10.3 # homeassistant.components.sensor.temper temperusb==1.5.3 @@ -1178,13 +1167,10 @@ yeelight==0.3.3 yeelightsunflower==0.0.8 # homeassistant.components.media_extractor -youtube_dl==2017.11.26 +youtube_dl==2017.11.15 # homeassistant.components.light.zengge zengge==0.2 # homeassistant.components.zeroconf zeroconf==0.19.1 - -# homeassistant.components.media_player.ziggo_mediabox_xl -ziggo-mediabox-xl==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 72325d6305ba12..ff12d18d6c6a01 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -74,7 +74,7 @@ hbmqtt==0.9.1 holidays==0.8.1 # homeassistant.components.frontend -home-assistant-frontend==20171206.0 +home-assistant-frontend==20171127.0 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb @@ -113,7 +113,7 @@ pilight==0.1.1 pmsensor==0.4 # homeassistant.components.prometheus -prometheus_client==0.0.21 +prometheus_client==0.0.19 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/setup.py b/setup.py index d79f11732ad7e0..f7a3e4ab8f39f5 100755 --- a/setup.py +++ b/setup.py @@ -53,8 +53,8 @@ 'jinja2>=2.9.6', 'voluptuous==0.10.5', 'typing>=3,<4', - 'aiohttp==2.3.5', # If updated, check if yarl also needs an update! - 'yarl==0.15.0', + 'aiohttp==2.3.2', # If updated, check if yarl also needs an update! + 'yarl==0.14.0', 'async_timeout==2.0.0', 'chardet==3.0.4', 'astral==1.4', diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py index c47ed941b65773..d65568b08447e1 100644 --- a/tests/components/alarm_control_panel/test_manual.py +++ b/tests/components/alarm_control_panel/test_manual.py @@ -140,32 +140,6 @@ def test_arm_away_no_pending(self): self.assertEqual(STATE_ALARM_ARMED_AWAY, self.hass.states.get(entity_id).state) - def test_arm_home_with_template_code(self): - """Attempt to arm with a template-based code.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code_template': '{{ "abc" }}', - 'pending_time': 0, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.hass.start() - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_home(self.hass, 'abc') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_HOME, state.state) - def test_arm_away_with_pending(self): """Test arm home method.""" self.assertTrue(setup_component( @@ -283,13 +257,6 @@ def test_arm_night_with_pending(self): state = self.hass.states.get(entity_id) assert state.state == STATE_ALARM_ARMED_NIGHT - # Do not go to the pending state when updating to the same state - alarm_control_panel.alarm_arm_night(self.hass, CODE, entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_NIGHT, - self.hass.states.get(entity_id).state) - def test_arm_night_with_invalid_code(self): """Attempt to night home without a valid code.""" self.assertTrue(setup_component( @@ -344,93 +311,6 @@ def test_trigger_no_pending(self): self.assertEqual(STATE_ALARM_TRIGGERED, self.hass.states.get(entity_id).state) - def test_trigger_with_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code': CODE, - 'delay_time': 1, - 'pending_time': 0, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_TRIGGERED, state.state) - - def test_trigger_zero_trigger_time(self): - """Test disabled trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'pending_time': 0, - 'trigger_time': 0, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_trigger_zero_trigger_time_with_pending(self): - """Test disabled trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'pending_time': 2, - 'trigger_time': 0, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - def test_trigger_with_pending(self): """Test arm home method.""" self.assertTrue(setup_component( @@ -475,203 +355,6 @@ def test_trigger_with_pending(self): state = self.hass.states.get(entity_id) assert state.state == STATE_ALARM_DISARMED - def test_trigger_with_unused_specific_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code': CODE, - 'delay_time': 5, - 'pending_time': 0, - 'armed_home': { - 'delay_time': 10 - }, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - - def test_trigger_with_specific_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code': CODE, - 'delay_time': 10, - 'pending_time': 0, - 'armed_away': { - 'delay_time': 1 - }, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - - def test_trigger_with_pending_and_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code': CODE, - 'delay_time': 1, - 'pending_time': 0, - 'triggered': { - 'pending_time': 1 - }, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future += timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - - def test_trigger_with_pending_and_specific_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code': CODE, - 'delay_time': 10, - 'pending_time': 0, - 'armed_away': { - 'delay_time': 1 - }, - 'triggered': { - 'pending_time': 1 - }, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future += timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - def test_armed_home_with_specific_pending(self): """Test arm home method.""" self.assertTrue(setup_component( @@ -835,101 +518,6 @@ def test_trigger_with_disarm_after_trigger(self): self.assertEqual(STATE_ALARM_DISARMED, self.hass.states.get(entity_id).state) - def test_trigger_with_zero_specific_trigger_time(self): - """Test trigger method.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'trigger_time': 5, - 'disarmed': { - 'trigger_time': 0 - }, - 'pending_time': 0, - 'disarm_after_trigger': True - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_trigger_with_unused_zero_specific_trigger_time(self): - """Test disarm after trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'trigger_time': 5, - 'armed_home': { - 'trigger_time': 0 - }, - 'pending_time': 0, - 'disarm_after_trigger': True - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_TRIGGERED, - self.hass.states.get(entity_id).state) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_trigger_with_specific_trigger_time(self): - """Test disarm after trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'disarmed': { - 'trigger_time': 5 - }, - 'pending_time': 0, - 'disarm_after_trigger': True - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_TRIGGERED, - self.hass.states.get(entity_id).state) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - def test_trigger_with_no_disarm_after_trigger(self): """Test disarm after trigger.""" self.assertTrue(setup_component( @@ -1096,45 +684,6 @@ def test_disarm_during_trigger_with_invalid_code(self): self.assertEqual(STATE_ALARM_TRIGGERED, self.hass.states.get(entity_id).state) - def test_disarm_with_template_code(self): - """Attempt to disarm with a valid or invalid template-based code.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code_template': - '{{ "" if from_state == "disarmed" else "abc" }}', - 'pending_time': 0, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.hass.start() - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_home(self.hass, 'def') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_HOME, state.state) - - alarm_control_panel.alarm_disarm(self.hass, 'def') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_HOME, state.state) - - alarm_control_panel.alarm_disarm(self.hass, 'abc') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_DISARMED, state.state) - def test_arm_custom_bypass_no_pending(self): """Test arm custom bypass method.""" self.assertTrue(setup_component( @@ -1246,75 +795,3 @@ def test_armed_custom_bypass_with_specific_pending(self): self.assertEqual(STATE_ALARM_ARMED_CUSTOM_BYPASS, self.hass.states.get(entity_id).state) - - def test_arm_away_after_disabled_disarmed(self): - """Test pending state with and without zero trigger time.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual', - 'name': 'test', - 'code': CODE, - 'pending_time': 0, - 'delay_time': 1, - 'armed_away': { - 'pending_time': 1, - }, - 'disarmed': { - 'trigger_time': 0 - }, - 'disarm_after_trigger': False - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_DISARMED, - state.attributes['pre_pending_state']) - self.assertEqual(STATE_ALARM_ARMED_AWAY, - state.attributes['post_pending_state']) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_DISARMED, - state.attributes['pre_pending_state']) - self.assertEqual(STATE_ALARM_ARMED_AWAY, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_AWAY, state.state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_ARMED_AWAY, - state.attributes['pre_pending_state']) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future += timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_TRIGGERED, state.state) diff --git a/tests/components/alarm_control_panel/test_manual_mqtt.py b/tests/components/alarm_control_panel/test_manual_mqtt.py index 83254d9104f9a3..e56b6865e6e7bb 100644 --- a/tests/components/alarm_control_panel/test_manual_mqtt.py +++ b/tests/components/alarm_control_panel/test_manual_mqtt.py @@ -162,34 +162,6 @@ def test_arm_away_no_pending(self): self.assertEqual(STATE_ALARM_ARMED_AWAY, self.hass.states.get(entity_id).state) - def test_arm_home_with_template_code(self): - """Attempt to arm with a template-based code.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code_template': '{{ "abc" }}', - 'pending_time': 0, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state', - }})) - - entity_id = 'alarm_control_panel.test' - - self.hass.start() - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_home(self.hass, 'abc') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_HOME, state.state) - def test_arm_away_with_pending(self): """Test arm home method.""" self.assertTrue(setup_component( @@ -315,13 +287,6 @@ def test_arm_night_with_pending(self): self.assertEqual(STATE_ALARM_ARMED_NIGHT, self.hass.states.get(entity_id).state) - # Do not go to the pending state when updating to the same state - alarm_control_panel.alarm_arm_night(self.hass, CODE, entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_NIGHT, - self.hass.states.get(entity_id).state) - def test_arm_night_with_invalid_code(self): """Attempt to arm night without a valid code.""" self.assertTrue(setup_component( @@ -380,99 +345,6 @@ def test_trigger_no_pending(self): self.assertEqual(STATE_ALARM_TRIGGERED, self.hass.states.get(entity_id).state) - def test_trigger_with_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code': CODE, - 'delay_time': 1, - 'pending_time': 0, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_TRIGGERED, state.state) - - def test_trigger_zero_trigger_time(self): - """Test disabled trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'pending_time': 0, - 'trigger_time': 0, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_trigger_zero_trigger_time_with_pending(self): - """Test disabled trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'pending_time': 2, - 'trigger_time': 0, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - def test_trigger_with_pending(self): """Test arm home method.""" self.assertTrue(setup_component( @@ -553,107 +425,6 @@ def test_trigger_with_disarm_after_trigger(self): self.assertEqual(STATE_ALARM_DISARMED, self.hass.states.get(entity_id).state) - def test_trigger_with_zero_specific_trigger_time(self): - """Test trigger method.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'trigger_time': 5, - 'disarmed': { - 'trigger_time': 0 - }, - 'pending_time': 0, - 'disarm_after_trigger': True, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_trigger_with_unused_zero_specific_trigger_time(self): - """Test disarm after trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'trigger_time': 5, - 'armed_home': { - 'trigger_time': 0 - }, - 'pending_time': 0, - 'disarm_after_trigger': True, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_TRIGGERED, - self.hass.states.get(entity_id).state) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_trigger_with_specific_trigger_time(self): - """Test disarm after trigger.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'disarmed': { - 'trigger_time': 5 - }, - 'pending_time': 0, - 'disarm_after_trigger': True, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_TRIGGERED, - self.hass.states.get(entity_id).state) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - def test_back_to_back_trigger_with_no_disarm_after_trigger(self): """Test no disarm after back to back trigger.""" self.assertTrue(setup_component( @@ -788,211 +559,6 @@ def test_disarm_during_trigger_with_invalid_code(self): self.assertEqual(STATE_ALARM_TRIGGERED, self.hass.states.get(entity_id).state) - def test_trigger_with_unused_specific_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code': CODE, - 'delay_time': 5, - 'pending_time': 0, - 'armed_home': { - 'delay_time': 10 - }, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - - def test_trigger_with_specific_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code': CODE, - 'delay_time': 10, - 'pending_time': 0, - 'armed_away': { - 'delay_time': 1 - }, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - - def test_trigger_with_pending_and_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code': CODE, - 'delay_time': 1, - 'pending_time': 0, - 'triggered': { - 'pending_time': 1 - }, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future += timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - - def test_trigger_with_pending_and_specific_delay(self): - """Test trigger method and switch from pending to triggered.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code': CODE, - 'delay_time': 10, - 'pending_time': 0, - 'armed_away': { - 'delay_time': 1 - }, - 'triggered': { - 'pending_time': 1 - }, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state' - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_ARMED_AWAY, - self.hass.states.get(entity_id).state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future = dt_util.utcnow() + timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_PENDING - assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED - - future += timedelta(seconds=1) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - assert state.state == STATE_ALARM_TRIGGERED - def test_armed_home_with_specific_pending(self): """Test arm home method.""" self.assertTrue(setup_component( @@ -1108,145 +674,45 @@ def test_trigger_with_specific_pending(self): entity_id = 'alarm_control_panel.test' - alarm_control_panel.alarm_trigger(self.hass) + alarm_control_panel.alarm_arm_home(self.hass) self.hass.block_till_done() self.assertEqual(STATE_ALARM_PENDING, self.hass.states.get(entity_id).state) - future = dt_util.utcnow() + timedelta(seconds=2) + future = dt_util.utcnow() + timedelta(seconds=10) with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' 'dt_util.utcnow'), return_value=future): fire_time_changed(self.hass, future) self.hass.block_till_done() - self.assertEqual(STATE_ALARM_TRIGGERED, - self.hass.states.get(entity_id).state) - - future = dt_util.utcnow() + timedelta(seconds=5) - with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' - 'dt_util.utcnow'), return_value=future): - fire_time_changed(self.hass, future) - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, - self.hass.states.get(entity_id).state) - - def test_arm_away_after_disabled_disarmed(self): - """Test pending state with and without zero trigger time.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code': CODE, - 'pending_time': 0, - 'delay_time': 1, - 'armed_away': { - 'pending_time': 1, - }, - 'disarmed': { - 'trigger_time': 0 - }, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state', - }})) - - entity_id = 'alarm_control_panel.test' - - self.assertEqual(STATE_ALARM_DISARMED, + self.assertEqual(STATE_ALARM_ARMED_HOME, self.hass.states.get(entity_id).state) - alarm_control_panel.alarm_arm_away(self.hass, CODE) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_DISARMED, - state.attributes['pre_pending_state']) - self.assertEqual(STATE_ALARM_ARMED_AWAY, - state.attributes['post_pending_state']) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) + alarm_control_panel.alarm_trigger(self.hass) self.hass.block_till_done() - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_DISARMED, - state.attributes['pre_pending_state']) - self.assertEqual(STATE_ALARM_ARMED_AWAY, - state.attributes['post_pending_state']) + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) - future = dt_util.utcnow() + timedelta(seconds=1) + future = dt_util.utcnow() + timedelta(seconds=2) with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' 'dt_util.utcnow'), return_value=future): fire_time_changed(self.hass, future) self.hass.block_till_done() - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_AWAY, state.state) - - alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_PENDING, state.state) - self.assertEqual(STATE_ALARM_ARMED_AWAY, - state.attributes['pre_pending_state']) - self.assertEqual(STATE_ALARM_TRIGGERED, - state.attributes['post_pending_state']) + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) - future += timedelta(seconds=1) + future = dt_util.utcnow() + timedelta(seconds=5) with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' 'dt_util.utcnow'), return_value=future): fire_time_changed(self.hass, future) self.hass.block_till_done() - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_TRIGGERED, state.state) - - def test_disarm_with_template_code(self): - """Attempt to disarm with a valid or invalid template-based code.""" - self.assertTrue(setup_component( - self.hass, alarm_control_panel.DOMAIN, - {'alarm_control_panel': { - 'platform': 'manual_mqtt', - 'name': 'test', - 'code_template': - '{{ "" if from_state == "disarmed" else "abc" }}', - 'pending_time': 0, - 'disarm_after_trigger': False, - 'command_topic': 'alarm/command', - 'state_topic': 'alarm/state', - }})) - - entity_id = 'alarm_control_panel.test' - - self.hass.start() - self.hass.block_till_done() - - self.assertEqual(STATE_ALARM_DISARMED, + self.assertEqual(STATE_ALARM_ARMED_HOME, self.hass.states.get(entity_id).state) - alarm_control_panel.alarm_arm_home(self.hass, 'def') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_HOME, state.state) - - alarm_control_panel.alarm_disarm(self.hass, 'def') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_ARMED_HOME, state.state) - - alarm_control_panel.alarm_disarm(self.hass, 'abc') - self.hass.block_till_done() - - state = self.hass.states.get(entity_id) - self.assertEqual(STATE_ALARM_DISARMED, state.state) - def test_arm_home_via_command_topic(self): """Test arming home via command topic.""" assert setup_component(self.hass, alarm_control_panel.DOMAIN, { diff --git a/tests/components/automation/test_numeric_state.py b/tests/components/automation/test_numeric_state.py index 58cfd2cbd704f5..35841baa9304a7 100644 --- a/tests/components/automation/test_numeric_state.py +++ b/tests/components/automation/test_numeric_state.py @@ -84,36 +84,6 @@ def test_if_fires_on_entity_change_over_to_below(self): self.hass.block_till_done() self.assertEqual(1, len(self.calls)) - def test_if_fires_on_entities_change_over_to_below(self): - """"Test the firing with changed entities.""" - self.hass.states.set('test.entity_1', 11) - self.hass.states.set('test.entity_2', 11) - self.hass.block_till_done() - - assert setup_component(self.hass, automation.DOMAIN, { - automation.DOMAIN: { - 'trigger': { - 'platform': 'numeric_state', - 'entity_id': [ - 'test.entity_1', - 'test.entity_2', - ], - 'below': 10, - }, - 'action': { - 'service': 'test.automation' - } - } - }) - - # 9 is below 10 - self.hass.states.set('test.entity_1', 9) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - self.hass.states.set('test.entity_2', 9) - self.hass.block_till_done() - self.assertEqual(2, len(self.calls)) - def test_if_not_fires_on_entity_change_below_to_below(self): """"Test the firing with changed entity.""" self.hass.states.set('test.entity', 11) @@ -142,11 +112,6 @@ def test_if_not_fires_on_entity_change_below_to_below(self): self.hass.block_till_done() self.assertEqual(1, len(self.calls)) - # still below so should not fire again - self.hass.states.set('test.entity', 3) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - def test_if_not_below_fires_on_entity_change_to_equal(self): """"Test the firing with changed entity.""" self.hass.states.set('test.entity', 11) @@ -736,48 +701,6 @@ def test_if_not_fires_on_entity_change_with_for(self): self.hass.block_till_done() self.assertEqual(0, len(self.calls)) - def test_if_not_fires_on_entities_change_with_for_afte_stop(self): - """Test for not firing on entities change with for after stop.""" - assert setup_component(self.hass, automation.DOMAIN, { - automation.DOMAIN: { - 'trigger': { - 'platform': 'numeric_state', - 'entity_id': [ - 'test.entity_1', - 'test.entity_2', - ], - 'above': 8, - 'below': 12, - 'for': { - 'seconds': 5 - }, - }, - 'action': { - 'service': 'test.automation' - } - } - }) - - self.hass.states.set('test.entity_1', 9) - self.hass.states.set('test.entity_2', 9) - self.hass.block_till_done() - fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=10)) - self.hass.block_till_done() - self.assertEqual(2, len(self.calls)) - - self.hass.states.set('test.entity_1', 15) - self.hass.states.set('test.entity_2', 15) - self.hass.block_till_done() - self.hass.states.set('test.entity_1', 9) - self.hass.states.set('test.entity_2', 9) - self.hass.block_till_done() - automation.turn_off(self.hass) - self.hass.block_till_done() - - fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=10)) - self.hass.block_till_done() - self.assertEqual(2, len(self.calls)) - def test_if_fires_on_entity_change_with_for_attribute_change(self): """Test for firing on entity change with for and attribute change.""" assert setup_component(self.hass, automation.DOMAIN, { diff --git a/tests/components/automation/test_state.py b/tests/components/automation/test_state.py index b1ee0841e2de2f..1f245d1cf5c9d2 100644 --- a/tests/components/automation/test_state.py +++ b/tests/components/automation/test_state.py @@ -334,47 +334,6 @@ def test_if_not_fires_on_entity_change_with_for(self): self.hass.block_till_done() self.assertEqual(0, len(self.calls)) - def test_if_not_fires_on_entities_change_with_for_after_stop(self): - """Test for not firing on entity change with for after stop trigger.""" - assert setup_component(self.hass, automation.DOMAIN, { - automation.DOMAIN: { - 'trigger': { - 'platform': 'state', - 'entity_id': [ - 'test.entity_1', - 'test.entity_2', - ], - 'to': 'world', - 'for': { - 'seconds': 5 - }, - }, - 'action': { - 'service': 'test.automation' - } - } - }) - - self.hass.states.set('test.entity_1', 'world') - self.hass.states.set('test.entity_2', 'world') - self.hass.block_till_done() - fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=10)) - self.hass.block_till_done() - self.assertEqual(2, len(self.calls)) - - self.hass.states.set('test.entity_1', 'world_no') - self.hass.states.set('test.entity_2', 'world_no') - self.hass.block_till_done() - self.hass.states.set('test.entity_1', 'world') - self.hass.states.set('test.entity_2', 'world') - self.hass.block_till_done() - automation.turn_off(self.hass) - self.hass.block_till_done() - - fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=10)) - self.hass.block_till_done() - self.assertEqual(2, len(self.calls)) - def test_if_fires_on_entity_change_with_for_attribute_change(self): """Test for firing on entity change with for and attribute change.""" assert setup_component(self.hass, automation.DOMAIN, { diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 63bbce2e7c6b08..5982a6c16d80ea 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -205,10 +205,6 @@ def test_set_target_temp(self): self.hass.block_till_done() state = self.hass.states.get(ENTITY) self.assertEqual(30.0, state.attributes.get('temperature')) - climate.set_temperature(self.hass, None) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY) - self.assertEqual(30.0, state.attributes.get('temperature')) def test_sensor_bad_unit(self): """Test sensor that have bad unit.""" @@ -892,22 +888,19 @@ def test_custom_setup_params(hass): 'min_temp': MIN_TEMP, 'max_temp': MAX_TEMP, 'target_temp': TARGET_TEMP, - 'initial_operation_mode': STATE_OFF, }}) assert result state = hass.states.get(ENTITY) assert state.attributes.get('min_temp') == MIN_TEMP assert state.attributes.get('max_temp') == MAX_TEMP assert state.attributes.get('temperature') == TARGET_TEMP - assert state.attributes.get(climate.ATTR_OPERATION_MODE) == STATE_OFF @asyncio.coroutine def test_restore_state(hass): """Ensure states are restored on startup.""" mock_restore_cache(hass, ( - State('climate.test_thermostat', '0', {ATTR_TEMPERATURE: "20", - climate.ATTR_OPERATION_MODE: "off"}), + State('climate.test_thermostat', '0', {ATTR_TEMPERATURE: "20"}), )) hass.state = CoreState.starting @@ -922,29 +915,3 @@ def test_restore_state(hass): state = hass.states.get('climate.test_thermostat') assert(state.attributes[ATTR_TEMPERATURE] == 20) - assert(state.attributes[climate.ATTR_OPERATION_MODE] == "off") - - -@asyncio.coroutine -def test_no_restore_state(hass): - """Ensure states are not restored on startup if not needed.""" - mock_restore_cache(hass, ( - State('climate.test_thermostat', '0', {ATTR_TEMPERATURE: "20", - climate.ATTR_OPERATION_MODE: "off"}), - )) - - hass.state = CoreState.starting - - yield from async_setup_component( - hass, climate.DOMAIN, {'climate': { - 'platform': 'generic_thermostat', - 'name': 'test_thermostat', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR, - 'target_temp': 22, - 'initial_operation_mode': 'auto', - }}) - - state = hass.states.get('climate.test_thermostat') - assert(state.attributes[ATTR_TEMPERATURE] == 22) - assert(state.attributes[climate.ATTR_OPERATION_MODE] != "off") diff --git a/tests/components/config/test_group.py b/tests/components/config/test_group.py index ad28b6eb9b8417..6cc6d67811ef1b 100644 --- a/tests/components/config/test_group.py +++ b/tests/components/config/test_group.py @@ -1,7 +1,7 @@ -"""Test Group config panel.""" +"""Test Z-Wave config panel.""" import asyncio import json -from unittest.mock import patch, MagicMock +from unittest.mock import patch from homeassistant.bootstrap import async_setup_component from homeassistant.components import config @@ -66,11 +66,8 @@ def mock_write(path, data): """Mock writing data.""" written.append(data) - mock_call = MagicMock() - with patch('homeassistant.components.config._read', mock_read), \ - patch('homeassistant.components.config._write', mock_write), \ - patch.object(hass.services, 'async_call', mock_call): + patch('homeassistant.components.config._write', mock_write): resp = yield from client.post( '/api/config/group/config/hello_beer', data=json.dumps({ 'name': 'Beer', @@ -85,7 +82,6 @@ def mock_write(path, data): orig_data['hello_beer']['entities'] = ['light.top', 'light.bottom'] assert written[0] == orig_data - mock_call.assert_called_once_with('group', 'reload') @asyncio.coroutine diff --git a/tests/components/device_tracker/test_asuswrt.py b/tests/components/device_tracker/test_asuswrt.py index a6827d165cd6e2..b507bfea7c9176 100644 --- a/tests/components/device_tracker/test_asuswrt.py +++ b/tests/components/device_tracker/test_asuswrt.py @@ -9,8 +9,7 @@ from homeassistant.setup import setup_component from homeassistant.components import device_tracker from homeassistant.components.device_tracker import ( - CONF_CONSIDER_HOME, CONF_TRACK_NEW, CONF_NEW_DEVICE_DEFAULTS, - CONF_AWAY_HIDE) + CONF_CONSIDER_HOME, CONF_TRACK_NEW) from homeassistant.components.device_tracker.asuswrt import ( CONF_PROTOCOL, CONF_MODE, CONF_PUB_KEY, DOMAIN, CONF_PORT, PLATFORM_SCHEMA) @@ -79,11 +78,7 @@ def test_get_scanner_with_password_no_pubkey(self, asuswrt_mock): \ CONF_USERNAME: 'fake_user', CONF_PASSWORD: 'fake_pass', CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180), - CONF_NEW_DEVICE_DEFAULTS: { - CONF_TRACK_NEW: True, - CONF_AWAY_HIDE: False - } + CONF_CONSIDER_HOME: timedelta(seconds=180) } } @@ -109,11 +104,7 @@ def test_get_scanner_with_pubkey_no_password(self, asuswrt_mock): \ CONF_USERNAME: 'fake_user', CONF_PUB_KEY: FAKEFILE, CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180), - CONF_NEW_DEVICE_DEFAULTS: { - CONF_TRACK_NEW: True, - CONF_AWAY_HIDE: False - } + CONF_CONSIDER_HOME: timedelta(seconds=180) } } diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 34c7ecf465db92..704b2590f1240d 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -123,7 +123,7 @@ def test_track_with_duplicate_mac_dev_id(self, mock_warning): 'My device', None, None, False), device_tracker.Device(self.hass, True, True, 'your_device', 'AB:01', 'Your device', None, None, False)] - device_tracker.DeviceTracker(self.hass, False, True, {}, devices) + device_tracker.DeviceTracker(self.hass, False, True, devices) _LOGGER.debug(mock_warning.call_args_list) assert mock_warning.call_count == 1, \ "The only warning call should be duplicates (check DEBUG)" @@ -137,7 +137,7 @@ def test_track_with_duplicate_mac_dev_id(self, mock_warning): 'AB:01', 'My device', None, None, False), device_tracker.Device(self.hass, True, True, 'my_device', None, 'Your device', None, None, False)] - device_tracker.DeviceTracker(self.hass, False, True, {}, devices) + device_tracker.DeviceTracker(self.hass, False, True, devices) _LOGGER.debug(mock_warning.call_args_list) assert mock_warning.call_count == 1, \ @@ -299,7 +299,7 @@ def test_mac_vendor_lookup_on_see(self): vendor_string = 'Raspberry Pi Foundation' tracker = device_tracker.DeviceTracker( - self.hass, timedelta(seconds=60), 0, {}, []) + self.hass, timedelta(seconds=60), 0, []) with mock_aiohttp_client() as aioclient_mock: aioclient_mock.get('http://api.macvendors.com/b8:27:eb', @@ -622,7 +622,7 @@ def test_see_passive_zone_state(self): def test_see_failures(self, mock_warning): """Test that the device tracker see failures.""" tracker = device_tracker.DeviceTracker( - self.hass, timedelta(seconds=60), 0, {}, []) + self.hass, timedelta(seconds=60), 0, []) # MAC is not a string (but added) tracker.see(mac=567, host_name="Number MAC") @@ -654,7 +654,7 @@ def test_config_failure(self): def test_picture_and_icon_on_see_discovery(self): """Test that picture and icon are set in initial see.""" tracker = device_tracker.DeviceTracker( - self.hass, timedelta(seconds=60), False, {}, []) + self.hass, timedelta(seconds=60), False, []) tracker.see(dev_id=11, picture='pic_url', icon='mdi:icon') self.hass.block_till_done() config = device_tracker.load_config(self.yaml_devices, self.hass, @@ -663,18 +663,6 @@ def test_picture_and_icon_on_see_discovery(self): assert config[0].icon == 'mdi:icon' assert config[0].entity_picture == 'pic_url' - def test_default_hide_if_away_is_used(self): - """Test that default track_new is used.""" - tracker = device_tracker.DeviceTracker( - self.hass, timedelta(seconds=60), False, - {device_tracker.CONF_AWAY_HIDE: True}, []) - tracker.see(dev_id=12) - self.hass.block_till_done() - config = device_tracker.load_config(self.yaml_devices, self.hass, - timedelta(seconds=0)) - assert len(config) == 1 - self.assertTrue(config[0].hidden) - @asyncio.coroutine def test_async_added_to_hass(hass): diff --git a/tests/components/device_tracker/test_meraki.py b/tests/components/device_tracker/test_meraki.py deleted file mode 100644 index a739df804fd7aa..00000000000000 --- a/tests/components/device_tracker/test_meraki.py +++ /dev/null @@ -1,139 +0,0 @@ -"""The tests the for Meraki device tracker.""" -import asyncio -import json -from unittest.mock import patch -import pytest -from homeassistant.components.device_tracker.meraki import ( - CONF_VALIDATOR, CONF_SECRET) -from homeassistant.setup import async_setup_component -import homeassistant.components.device_tracker as device_tracker -from homeassistant.const import CONF_PLATFORM -from homeassistant.components.device_tracker.meraki import URL - - -@pytest.fixture -def meraki_client(loop, hass, test_client): - """Meraki mock client.""" - assert loop.run_until_complete(async_setup_component( - hass, device_tracker.DOMAIN, { - device_tracker.DOMAIN: { - CONF_PLATFORM: 'meraki', - CONF_VALIDATOR: 'validator', - CONF_SECRET: 'secret' - - } - })) - - with patch('homeassistant.components.device_tracker.update_config'): - yield loop.run_until_complete(test_client(hass.http.app)) - - -@asyncio.coroutine -def test_invalid_or_missing_data(meraki_client): - """Test validator with invalid or missing data.""" - req = yield from meraki_client.get(URL) - text = yield from req.text() - assert req.status == 200 - assert text == 'validator' - - req = yield from meraki_client.post(URL, data=b"invalid") - text = yield from req.json() - assert req.status == 400 - assert text['message'] == 'Invalid JSON' - - req = yield from meraki_client.post(URL, data=b"{}") - text = yield from req.json() - assert req.status == 422 - assert text['message'] == 'No secret' - - data = { - "version": "1.0", - "secret": "secret" - } - req = yield from meraki_client.post(URL, data=json.dumps(data)) - text = yield from req.json() - assert req.status == 422 - assert text['message'] == 'Invalid version' - - data = { - "version": "2.0", - "secret": "invalid" - } - req = yield from meraki_client.post(URL, data=json.dumps(data)) - text = yield from req.json() - assert req.status == 422 - assert text['message'] == 'Invalid secret' - - data = { - "version": "2.0", - "secret": "secret", - "type": "InvalidType" - } - req = yield from meraki_client.post(URL, data=json.dumps(data)) - text = yield from req.json() - assert req.status == 422 - assert text['message'] == 'Invalid device type' - - data = { - "version": "2.0", - "secret": "secret", - "type": "BluetoothDevicesSeen", - "data": { - "observations": [] - } - } - req = yield from meraki_client.post(URL, data=json.dumps(data)) - assert req.status == 200 - - -@asyncio.coroutine -def test_data_will_be_saved(hass, meraki_client): - """Test with valid data.""" - data = { - "version": "2.0", - "secret": "secret", - "type": "DevicesSeen", - "data": { - "observations": [ - { - "location": { - "lat": "51.5355157", - "lng": "21.0699035", - "unc": "46.3610585", - }, - "seenTime": "2016-09-12T16:23:13Z", - "ssid": 'ssid', - "os": 'HA', - "ipv6": '2607:f0d0:1002:51::4/64', - "clientMac": "00:26:ab:b8:a9:a4", - "seenEpoch": "147369739", - "rssi": "20", - "manufacturer": "Seiko Epson" - }, - { - "location": { - "lat": "51.5355357", - "lng": "21.0699635", - "unc": "46.3610585", - }, - "seenTime": "2016-09-12T16:21:13Z", - "ssid": 'ssid', - "os": 'HA', - "ipv4": '192.168.0.1', - "clientMac": "00:26:ab:b8:a9:a5", - "seenEpoch": "147369750", - "rssi": "20", - "manufacturer": "Seiko Epson" - } - ] - } - } - req = yield from meraki_client.post(URL, data=json.dumps(data)) - assert req.status == 200 - state_name = hass.states.get('{}.{}'.format('device_tracker', - '0026abb8a9a4')).state - assert 'home' == state_name - - state_name = hass.states.get('{}.{}'.format('device_tracker', - '0026abb8a9a5')).state - assert 'home' == state_name diff --git a/tests/components/device_tracker/test_unifi_direct.py b/tests/components/device_tracker/test_unifi_direct.py index b378118141a1d7..0e22758d07ecb8 100644 --- a/tests/components/device_tracker/test_unifi_direct.py +++ b/tests/components/device_tracker/test_unifi_direct.py @@ -11,8 +11,7 @@ from homeassistant.setup import setup_component from homeassistant.components import device_tracker from homeassistant.components.device_tracker import ( - CONF_CONSIDER_HOME, CONF_TRACK_NEW, CONF_AWAY_HIDE, - CONF_NEW_DEVICE_DEFAULTS) + CONF_CONSIDER_HOME, CONF_TRACK_NEW) from homeassistant.components.device_tracker.unifi_direct import ( DOMAIN, CONF_PORT, PLATFORM_SCHEMA, _response_to_json, get_scanner) from homeassistant.const import (CONF_PLATFORM, CONF_PASSWORD, CONF_USERNAME, @@ -55,11 +54,7 @@ def test_get_scanner(self, unifi_mock): \ CONF_USERNAME: 'fake_user', CONF_PASSWORD: 'fake_pass', CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180), - CONF_NEW_DEVICE_DEFAULTS: { - CONF_TRACK_NEW: True, - CONF_AWAY_HIDE: False - } + CONF_CONSIDER_HOME: timedelta(seconds=180) } } diff --git a/tests/components/sensor/test_rest.py b/tests/components/sensor/test_rest.py index 1bda8ab82f39d6..a083dbfb1a2819 100644 --- a/tests/components/sensor/test_rest.py +++ b/tests/components/sensor/test_rest.py @@ -133,9 +133,9 @@ def setUp(self): self.value_template = template('{{ value_json.key }}') self.value_template.hass = self.hass - self.sensor = rest.RestSensor(self.hass, self.rest, self.name, - self.unit_of_measurement, - self.value_template, []) + self.sensor = rest.RestSensor( + self.hass, self.rest, self.name, self.unit_of_measurement, + self.value_template) def tearDown(self): """Stop everything that was started.""" @@ -181,62 +181,12 @@ def test_update_with_no_template(self): self.rest.update = Mock('rest.RestData.update', side_effect=self.update_side_effect( 'plain_state')) - self.sensor = rest.RestSensor(self.hass, self.rest, self.name, - self.unit_of_measurement, None, []) + self.sensor = rest.RestSensor( + self.hass, self.rest, self.name, self.unit_of_measurement, None) self.sensor.update() self.assertEqual('plain_state', self.sensor.state) self.assertTrue(self.sensor.available) - def test_update_with_json_attrs(self): - """Test attributes get extracted from a JSON result.""" - self.rest.update = Mock('rest.RestData.update', - side_effect=self.update_side_effect( - '{ "key": "some_json_value" }')) - self.sensor = rest.RestSensor(self.hass, self.rest, self.name, - self.unit_of_measurement, None, ['key']) - self.sensor.update() - self.assertEqual('some_json_value', - self.sensor.device_state_attributes['key']) - - @patch('homeassistant.components.sensor.rest._LOGGER') - def test_update_with_json_attrs_not_dict(self, mock_logger): - """Test attributes get extracted from a JSON result.""" - self.rest.update = Mock('rest.RestData.update', - side_effect=self.update_side_effect( - '["list", "of", "things"]')) - self.sensor = rest.RestSensor(self.hass, self.rest, self.name, - self.unit_of_measurement, None, ['key']) - self.sensor.update() - self.assertEqual({}, self.sensor.device_state_attributes) - self.assertTrue(mock_logger.warning.called) - - @patch('homeassistant.components.sensor.rest._LOGGER') - def test_update_with_json_attrs_bad_JSON(self, mock_logger): - """Test attributes get extracted from a JSON result.""" - self.rest.update = Mock('rest.RestData.update', - side_effect=self.update_side_effect( - 'This is text rather than JSON data.')) - self.sensor = rest.RestSensor(self.hass, self.rest, self.name, - self.unit_of_measurement, None, ['key']) - self.sensor.update() - self.assertEqual({}, self.sensor.device_state_attributes) - self.assertTrue(mock_logger.warning.called) - self.assertTrue(mock_logger.debug.called) - - def test_update_with_json_attrs_and_template(self): - """Test attributes get extracted from a JSON result.""" - self.rest.update = Mock('rest.RestData.update', - side_effect=self.update_side_effect( - '{ "key": "json_state_updated_value" }')) - self.sensor = rest.RestSensor(self.hass, self.rest, self.name, - self.unit_of_measurement, - self.value_template, ['key']) - self.sensor.update() - - self.assertEqual('json_state_updated_value', self.sensor.state) - self.assertEqual('json_state_updated_value', - self.sensor.device_state_attributes['key']) - class TestRestData(unittest.TestCase): """Tests for RestData.""" diff --git a/tests/components/test_prometheus.py b/tests/components/test_prometheus.py index 052292b015d33c..dd8cbfe55e0967 100644 --- a/tests/components/test_prometheus.py +++ b/tests/components/test_prometheus.py @@ -30,6 +30,4 @@ def test_view(prometheus_client): # pylint: disable=redefined-outer-name assert len(body) > 3 # At least two comment lines and a metric for line in body: if line: - assert line.startswith('# ') \ - or line.startswith('process_') \ - or line.startswith('python_info') + assert line.startswith('# ') or line.startswith('process_') diff --git a/tests/components/vacuum/test_xiaomi_miio.py b/tests/components/vacuum/test_xiaomi_miio.py index a4bf9f60dac8ea..bdb85abb057309 100644 --- a/tests/components/vacuum/test_xiaomi_miio.py +++ b/tests/components/vacuum/test_xiaomi_miio.py @@ -1,6 +1,6 @@ """The tests for the Xiaomi vacuum platform.""" import asyncio -from datetime import timedelta, time +from datetime import timedelta from unittest import mock import pytest @@ -12,8 +12,7 @@ SERVICE_SEND_COMMAND, SERVICE_SET_FAN_SPEED, SERVICE_START_PAUSE, SERVICE_STOP, SERVICE_TOGGLE, SERVICE_TURN_OFF, SERVICE_TURN_ON) from homeassistant.components.vacuum.xiaomi_miio import ( - ATTR_CLEANED_AREA, ATTR_CLEANING_TIME, ATTR_DO_NOT_DISTURB, - ATTR_DO_NOT_DISTURB_START, ATTR_DO_NOT_DISTURB_END, ATTR_ERROR, + ATTR_CLEANED_AREA, ATTR_CLEANING_TIME, ATTR_DO_NOT_DISTURB, ATTR_ERROR, ATTR_MAIN_BRUSH_LEFT, ATTR_SIDE_BRUSH_LEFT, ATTR_FILTER_LEFT, ATTR_CLEANING_COUNT, ATTR_CLEANED_TOTAL_AREA, ATTR_CLEANING_TOTAL_TIME, CONF_HOST, CONF_NAME, CONF_TOKEN, PLATFORM, @@ -24,12 +23,6 @@ STATE_ON) from homeassistant.setup import async_setup_component -# calls made when device status is requested -status_calls = [mock.call.Vacuum().status(), - mock.call.Vacuum().consumable_status(), - mock.call.Vacuum().clean_history(), - mock.call.Vacuum().dnd_status()] - @pytest.fixture def mock_mirobo_is_off(): @@ -40,6 +33,7 @@ def mock_mirobo_is_off(): mock_vacuum.Vacuum().status().fanspeed = 38 mock_vacuum.Vacuum().status().got_error = True mock_vacuum.Vacuum().status().error = 'Error message' + mock_vacuum.Vacuum().status().dnd = True mock_vacuum.Vacuum().status().battery = 82 mock_vacuum.Vacuum().status().clean_area = 123.43218 mock_vacuum.Vacuum().status().clean_time = timedelta( @@ -55,12 +49,9 @@ def mock_mirobo_is_off(): mock_vacuum.Vacuum().clean_history().total_duration = timedelta( hours=11, minutes=35, seconds=34) mock_vacuum.Vacuum().status().state = 'Test Xiaomi Charging' - mock_vacuum.Vacuum().dnd_status().enabled = True - mock_vacuum.Vacuum().dnd_status().start = time(hour=22, minute=0) - mock_vacuum.Vacuum().dnd_status().end = time(hour=6, minute=0) with mock.patch.dict('sys.modules', { - 'miio': mock_vacuum, + 'mirobo': mock_vacuum, }): yield mock_vacuum @@ -73,6 +64,7 @@ def mock_mirobo_is_on(): mock_vacuum.Vacuum().status().is_on = True mock_vacuum.Vacuum().status().fanspeed = 99 mock_vacuum.Vacuum().status().got_error = False + mock_vacuum.Vacuum().status().dnd = False mock_vacuum.Vacuum().status().battery = 32 mock_vacuum.Vacuum().status().clean_area = 133.43218 mock_vacuum.Vacuum().status().clean_time = timedelta( @@ -88,10 +80,9 @@ def mock_mirobo_is_on(): mock_vacuum.Vacuum().clean_history().total_duration = timedelta( hours=11, minutes=15, seconds=34) mock_vacuum.Vacuum().status().state = 'Test Xiaomi Cleaning' - mock_vacuum.Vacuum().dnd_status().enabled = False with mock.patch.dict('sys.modules', { - 'miio': mock_vacuum, + 'mirobo': mock_vacuum, }): yield mock_vacuum @@ -102,7 +93,7 @@ def mock_mirobo_errors(): mock_vacuum = mock.MagicMock() mock_vacuum.Vacuum().status.side_effect = OSError() with mock.patch.dict('sys.modules', { - 'miio': mock_vacuum, + 'mirobo': mock_vacuum, }): yield mock_vacuum @@ -125,7 +116,6 @@ def test_xiaomi_exceptions(hass, caplog, mock_mirobo_errors): @asyncio.coroutine -@pytest.mark.skip(reason="Fails") def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_off): """Test vacuum supported features.""" entity_name = 'test_vacuum_cleaner_1' @@ -146,8 +136,6 @@ def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_off): assert state.state == STATE_OFF assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 2047 assert state.attributes.get(ATTR_DO_NOT_DISTURB) == STATE_ON - assert state.attributes.get(ATTR_DO_NOT_DISTURB_START) == '22:00:00' - assert state.attributes.get(ATTR_DO_NOT_DISTURB_END) == '06:00:00' assert state.attributes.get(ATTR_ERROR) == 'Error message' assert (state.attributes.get(ATTR_BATTERY_ICON) == 'mdi:battery-charging-80') @@ -166,75 +154,96 @@ def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_off): # Call services yield from hass.services.async_call( DOMAIN, SERVICE_TURN_ON, blocking=True) - - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum.start()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().start()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_TURN_OFF, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().home()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().home()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_TOGGLE, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().start()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().start()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_STOP, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().stop()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().stop()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_START_PAUSE, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().pause()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().start()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_RETURN_TO_BASE, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().home()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().home()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_LOCATE, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().find()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().find()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_CLEAN_SPOT, {}, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().spot()], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert str(mock_mirobo_is_off.mock_calls[-4]) == 'call.Vacuum().spot()' + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') # Set speed service: yield from hass.services.async_call( DOMAIN, SERVICE_SET_FAN_SPEED, {"fan_speed": 60}, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().set_fan_speed(60)], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert (str(mock_mirobo_is_off.mock_calls[-4]) + == 'call.Vacuum().set_fan_speed(60)') + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_SET_FAN_SPEED, {"fan_speed": "turbo"}, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().set_fan_speed(77)], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert (str(mock_mirobo_is_off.mock_calls[-4]) + == 'call.Vacuum().set_fan_speed(77)') + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') assert 'ERROR' not in caplog.text yield from hass.services.async_call( @@ -244,22 +253,27 @@ def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_off): yield from hass.services.async_call( DOMAIN, SERVICE_SEND_COMMAND, {"command": "raw"}, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().raw_command('raw', None)], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert (str(mock_mirobo_is_off.mock_calls[-4]) + == "call.Vacuum().raw_command('raw', None)") + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_SEND_COMMAND, {"command": "raw", "params": {"k1": 2}}, blocking=True) - mock_mirobo_is_off.assert_has_calls( - [mock.call.Vacuum().raw_command('raw', {'k1': 2})], any_order=True) - mock_mirobo_is_off.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_off.reset_mock() + assert (str(mock_mirobo_is_off.mock_calls[-4]) + == "call.Vacuum().raw_command('raw', {'k1': 2})") + assert str(mock_mirobo_is_off.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_off.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_off.mock_calls[-1]) + == 'call.Vacuum().clean_history()') @asyncio.coroutine -@pytest.mark.skip(reason="Fails") def test_xiaomi_specific_services(hass, caplog, mock_mirobo_is_on): """Test vacuum supported features.""" entity_name = 'test_vacuum_cleaner_2' @@ -294,37 +308,62 @@ def test_xiaomi_specific_services(hass, caplog, mock_mirobo_is_on): assert state.attributes.get(ATTR_CLEANED_TOTAL_AREA) == 323 assert state.attributes.get(ATTR_CLEANING_TOTAL_TIME) == 675 + # Check setting pause + yield from hass.services.async_call( + DOMAIN, SERVICE_START_PAUSE, blocking=True) + assert str(mock_mirobo_is_on.mock_calls[-4]) == 'call.Vacuum().pause()' + assert str(mock_mirobo_is_on.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_on.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_on.mock_calls[-1]) + == 'call.Vacuum().clean_history()') + # Xiaomi vacuum specific services: yield from hass.services.async_call( DOMAIN, SERVICE_START_REMOTE_CONTROL, {ATTR_ENTITY_ID: entity_id}, blocking=True) + assert (str(mock_mirobo_is_on.mock_calls[-4]) + == "call.Vacuum().manual_start()") + assert str(mock_mirobo_is_on.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_on.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_on.mock_calls[-1]) + == 'call.Vacuum().clean_history()') - mock_mirobo_is_on.assert_has_calls( - [mock.call.Vacuum().manual_start()], any_order=True) - mock_mirobo_is_on.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_on.reset_mock() - - control = {"duration": 1000, "rotation": -40, "velocity": -0.1} yield from hass.services.async_call( DOMAIN, SERVICE_MOVE_REMOTE_CONTROL, - control, blocking=True) - mock_mirobo_is_on.assert_has_calls( - [mock.call.Vacuum().manual_control(control)], any_order=True) - mock_mirobo_is_on.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_on.reset_mock() + {"duration": 1000, "rotation": -40, "velocity": -0.1}, blocking=True) + assert ('call.Vacuum().manual_control(' + in str(mock_mirobo_is_on.mock_calls[-4])) + assert 'duration=1000' in str(mock_mirobo_is_on.mock_calls[-4]) + assert 'rotation=-40' in str(mock_mirobo_is_on.mock_calls[-4]) + assert 'velocity=-0.1' in str(mock_mirobo_is_on.mock_calls[-4]) + assert str(mock_mirobo_is_on.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_on.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_on.mock_calls[-1]) + == 'call.Vacuum().clean_history()') yield from hass.services.async_call( DOMAIN, SERVICE_STOP_REMOTE_CONTROL, {}, blocking=True) - mock_mirobo_is_on.assert_has_calls( - [mock.call.Vacuum().manual_stop()], any_order=True) - mock_mirobo_is_on.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_on.reset_mock() + assert (str(mock_mirobo_is_on.mock_calls[-4]) + == "call.Vacuum().manual_stop()") + assert str(mock_mirobo_is_on.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_on.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_on.mock_calls[-1]) + == 'call.Vacuum().clean_history()') - control_once = {"duration": 2000, "rotation": 120, "velocity": 0.1} yield from hass.services.async_call( DOMAIN, SERVICE_MOVE_REMOTE_CONTROL_STEP, - control_once, blocking=True) - mock_mirobo_is_on.assert_has_calls( - [mock.call.Vacuum().manual_control_once(control_once)], any_order=True) - mock_mirobo_is_on.assert_has_calls(status_calls, any_order=True) - mock_mirobo_is_on.reset_mock() + {"duration": 2000, "rotation": 120, "velocity": 0.1}, blocking=True) + assert ('call.Vacuum().manual_control_once(' + in str(mock_mirobo_is_on.mock_calls[-4])) + assert 'duration=2000' in str(mock_mirobo_is_on.mock_calls[-4]) + assert 'rotation=120' in str(mock_mirobo_is_on.mock_calls[-4]) + assert 'velocity=0.1' in str(mock_mirobo_is_on.mock_calls[-4]) + assert str(mock_mirobo_is_on.mock_calls[-3]) == 'call.Vacuum().status()' + assert (str(mock_mirobo_is_on.mock_calls[-2]) + == 'call.Vacuum().consumable_status()') + assert (str(mock_mirobo_is_on.mock_calls[-1]) + == 'call.Vacuum().clean_history()')