diff --git a/.coveragerc b/.coveragerc index cf5c0a36684e3..c75c06e8d84a3 100644 --- a/.coveragerc +++ b/.coveragerc @@ -159,8 +159,6 @@ omit = homeassistant/components/fan/mqtt.py homeassistant/components/feedreader.py homeassistant/components/foursquare.py - homeassistant/components/garage_door/rpi_gpio.py - homeassistant/components/garage_door/wink.py homeassistant/components/hdmi_cec.py homeassistant/components/ifttt.py homeassistant/components/joaoapps_join.py @@ -307,11 +305,6 @@ omit = homeassistant/components/switch/tplink.py homeassistant/components/switch/transmission.py homeassistant/components/switch/wake_on_lan.py - homeassistant/components/thermostat/eq3btsmart.py - homeassistant/components/thermostat/heatmiser.py - homeassistant/components/thermostat/homematic.py - homeassistant/components/thermostat/proliphix.py - homeassistant/components/thermostat/radiotherm.py homeassistant/components/upnp.py homeassistant/components/weather/openweathermap.py homeassistant/components/zeroconf.py diff --git a/homeassistant/components/garage_door/__init__.py b/homeassistant/components/garage_door/__init__.py deleted file mode 100644 index c5576b1da844c..0000000000000 --- a/homeassistant/components/garage_door/__init__.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -Component to interface with garage doors that can be controlled remotely. - -For more details about this component, please refer to the documentation -at https://home-assistant.io/components/garage_door/ -""" -import logging -import os - -import voluptuous as vol - -from homeassistant.config import load_yaml_config_file -from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa -import homeassistant.helpers.config_validation as cv -from homeassistant.const import ( - STATE_CLOSED, STATE_OPEN, STATE_UNKNOWN, SERVICE_CLOSE, SERVICE_OPEN, - ATTR_ENTITY_ID) -from homeassistant.components import group - -DOMAIN = 'garage_door' -SCAN_INTERVAL = 30 - -GROUP_NAME_ALL_GARAGE_DOORS = 'all garage doors' -ENTITY_ID_ALL_GARAGE_DOORS = group.ENTITY_ID_FORMAT.format('all_garage_doors') - -ENTITY_ID_FORMAT = DOMAIN + '.{}' - -GARAGE_DOOR_SERVICE_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, -}) - -_LOGGER = logging.getLogger(__name__) - - -def is_closed(hass, entity_id=None): - """Return if the garage door is closed based on the statemachine.""" - entity_id = entity_id or ENTITY_ID_ALL_GARAGE_DOORS - return hass.states.is_state(entity_id, STATE_CLOSED) - - -def close_door(hass, entity_id=None): - """Close all or a specified garage door.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_CLOSE, data) - - -def open_door(hass, entity_id=None): - """Open all or specified garage door.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_OPEN, data) - - -def setup(hass, config): - """Track states and offer events for garage door.""" - _LOGGER.warning('This component has been deprecated in favour of the ' - '"cover" component and will be removed in the future.' - ' Please upgrade.') - component = EntityComponent( - _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_GARAGE_DOORS) - component.setup(config) - - def handle_garage_door_service(service): - """Handle calls to the garage door services.""" - target_locks = component.extract_from_service(service) - - for item in target_locks: - if service.service == SERVICE_CLOSE: - item.close_door() - else: - item.open_door() - - if item.should_poll: - item.update_ha_state(True) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - hass.services.register(DOMAIN, SERVICE_OPEN, handle_garage_door_service, - descriptions.get(SERVICE_OPEN), - schema=GARAGE_DOOR_SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_CLOSE, handle_garage_door_service, - descriptions.get(SERVICE_CLOSE), - schema=GARAGE_DOOR_SERVICE_SCHEMA) - return True - - -class GarageDoorDevice(Entity): - """Representation of a garage door.""" - - # pylint: disable=no-self-use - @property - def is_closed(self): - """Return true if door is closed.""" - return None - - def close_door(self): - """Close the garage door.""" - raise NotImplementedError() - - def open_door(self): - """Open the garage door.""" - raise NotImplementedError() - - @property - def state(self): - """Return the state of the garage door.""" - closed = self.is_closed - if closed is None: - return STATE_UNKNOWN - return STATE_CLOSED if closed else STATE_OPEN diff --git a/homeassistant/components/garage_door/demo.py b/homeassistant/components/garage_door/demo.py deleted file mode 100644 index dad8df7782c22..0000000000000 --- a/homeassistant/components/garage_door/demo.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Demo garage door platform that has two fake doors. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" -from homeassistant.components.garage_door import GarageDoorDevice -from homeassistant.const import STATE_CLOSED, STATE_OPEN - - -# pylint: disable=unused-argument -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Setup demo garage door platform.""" - add_devices_callback([ - DemoGarageDoor('Left Garage Door', STATE_CLOSED), - DemoGarageDoor('Right Garage Door', STATE_OPEN) - ]) - - -class DemoGarageDoor(GarageDoorDevice): - """Provides a demo garage door.""" - - def __init__(self, name, state): - """Initialize the garage door.""" - self._name = name - self._state = state - - @property - def should_poll(self): - """No polling needed for a demo garage door.""" - return False - - @property - def name(self): - """Return the name of the device if any.""" - return self._name - - @property - def is_closed(self): - """Return true if garage door is closed.""" - return self._state == STATE_CLOSED - - def close_door(self, **kwargs): - """Close the garage door.""" - self._state = STATE_CLOSED - self.update_ha_state() - - def open_door(self, **kwargs): - """Open the garage door.""" - self._state = STATE_OPEN - self.update_ha_state() diff --git a/homeassistant/components/garage_door/mqtt.py b/homeassistant/components/garage_door/mqtt.py deleted file mode 100644 index 8fa6a110be877..0000000000000 --- a/homeassistant/components/garage_door/mqtt.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -Support for MQTT garage doors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/garage_door.mqtt/ -""" -import logging - -import voluptuous as vol -from homeassistant.const import (STATE_OPEN, STATE_CLOSED, SERVICE_OPEN, - SERVICE_CLOSE) -import homeassistant.components.mqtt as mqtt -from homeassistant.components.garage_door import GarageDoorDevice -from homeassistant.const import ( - CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE) -from homeassistant.components.mqtt import ( - CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN) -import homeassistant.helpers.config_validation as cv - -_LOGGER = logging.getLogger(__name__) - -CONF_STATE_OPEN = 'state_open' -CONF_STATE_CLOSED = 'state_closed' -CONF_SERVICE_OPEN = 'service_open' -CONF_SERVICE_CLOSE = 'service_close' - -DEFAULT_NAME = 'MQTT Garage Door' -DEFAULT_OPTIMISTIC = False -DEFAULT_RETAIN = False - -DEPENDENCIES = ['mqtt'] - -PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, - vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, - vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string, - vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string, - vol.Optional(CONF_SERVICE_OPEN, default=SERVICE_OPEN): cv.string, - vol.Optional(CONF_SERVICE_CLOSE, default=SERVICE_CLOSE): cv.string -}) - - -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Add MQTT Garage Door.""" - value_template = config.get(CONF_VALUE_TEMPLATE) - if value_template is not None: - value_template.hass = hass - add_devices_callback([MqttGarageDoor( - hass, - config[CONF_NAME], - config.get(CONF_STATE_TOPIC), - config[CONF_COMMAND_TOPIC], - config[CONF_QOS], - config[CONF_RETAIN], - config[CONF_STATE_OPEN], - config[CONF_STATE_CLOSED], - config[CONF_SERVICE_OPEN], - config[CONF_SERVICE_CLOSE], - config[CONF_OPTIMISTIC], - value_template)]) - - -# pylint: disable=too-many-arguments, too-many-instance-attributes -class MqttGarageDoor(GarageDoorDevice): - """Representation of a MQTT garage door.""" - - def __init__(self, hass, name, state_topic, command_topic, qos, retain, - state_open, state_closed, service_open, service_close, - optimistic, value_template): - """Initialize the garage door.""" - self._hass = hass - self._name = name - self._state_topic = state_topic - self._command_topic = command_topic - self._qos = qos - self._retain = retain - self._state_open = state_open - self._state_closed = state_closed - self._service_open = service_open - self._service_close = service_close - self._optimistic = optimistic or state_topic is None - self._state = False - - def message_received(topic, payload, qos): - """A new MQTT message has been received.""" - if value_template is not None: - payload = value_template.render_with_possible_json_value( - payload) - if payload == self._state_open: - self._state = True - self.update_ha_state() - elif payload == self._state_closed: - self._state = False - self.update_ha_state() - - if self._state_topic is None: - # Force into optimistic mode. - self._optimistic = True - else: - mqtt.subscribe(hass, self._state_topic, message_received, - self._qos) - - @property - def name(self): - """Return the name of the garage door if any.""" - return self._name - - @property - def is_opened(self): - """Return true if door is closed.""" - return self._state - - @property - def is_closed(self): - """Return true if door is closed.""" - return self._state is False - - @property - def assumed_state(self): - """Return true if we do optimistic updates.""" - return self._optimistic - - def close_door(self): - """Close the door.""" - mqtt.publish(self.hass, self._command_topic, self._service_close, - self._qos, self._retain) - if self._optimistic: - # Optimistically assume that door has changed state. - self._state = False - self.update_ha_state() - - def open_door(self): - """Open the door.""" - mqtt.publish(self.hass, self._command_topic, self._service_open, - self._qos, self._retain) - if self._optimistic: - # Optimistically assume that door has changed state. - self._state = True - self.update_ha_state() diff --git a/homeassistant/components/garage_door/rpi_gpio.py b/homeassistant/components/garage_door/rpi_gpio.py deleted file mode 100644 index 3969e12371cef..0000000000000 --- a/homeassistant/components/garage_door/rpi_gpio.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -Support for building a Raspberry Pi garage controller in HA. - -Instructions for building the controller can be found here -https://github.com/andrewshilliday/garage-door-controller - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/garage_door.rpi_gpio/ -""" - -import logging -from time import sleep -import voluptuous as vol -from homeassistant.components.garage_door import GarageDoorDevice -import homeassistant.components.rpi_gpio as rpi_gpio -import homeassistant.helpers.config_validation as cv - -RELAY_TIME = 'relay_time' -STATE_PULL_MODE = 'state_pull_mode' -DEFAULT_PULL_MODE = 'UP' -DEFAULT_RELAY_TIME = .2 -DEPENDENCIES = ['rpi_gpio'] - -_LOGGER = logging.getLogger(__name__) - -_DOORS_SCHEMA = vol.All( - cv.ensure_list, - [ - vol.Schema({ - 'name': str, - 'relay_pin': int, - 'state_pin': int, - }) - ] -) -PLATFORM_SCHEMA = vol.Schema({ - 'platform': str, - vol.Required('doors'): _DOORS_SCHEMA, - vol.Optional(STATE_PULL_MODE, default=DEFAULT_PULL_MODE): cv.string, - vol.Optional(RELAY_TIME, default=DEFAULT_RELAY_TIME): vol.Coerce(int), -}) - - -# pylint: disable=unused-argument -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the garage door platform.""" - relay_time = config.get(RELAY_TIME) - state_pull_mode = config.get(STATE_PULL_MODE) - doors = [] - doors_conf = config.get('doors') - - for door in doors_conf: - doors.append(RPiGPIOGarageDoor(door['name'], door['relay_pin'], - door['state_pin'], - state_pull_mode, - relay_time)) - add_devices(doors) - - -class RPiGPIOGarageDoor(GarageDoorDevice): - """Representation of a Raspberry garage door.""" - - # pylint: disable=too-many-arguments - def __init__(self, name, relay_pin, state_pin, - state_pull_mode, relay_time): - """Initialize the garage door.""" - self._name = name - self._state = False - self._relay_pin = relay_pin - self._state_pin = state_pin - self._state_pull_mode = state_pull_mode - self._relay_time = relay_time - rpi_gpio.setup_output(self._relay_pin) - rpi_gpio.setup_input(self._state_pin, self._state_pull_mode) - rpi_gpio.write_output(self._relay_pin, True) - - @property - def unique_id(self): - """Return the ID of this garage door.""" - return "{}.{}".format(self.__class__, self._name) - - @property - def name(self): - """Return the name of the garage door if any.""" - return self._name - - def update(self): - """Update the state of the garage door.""" - self._state = rpi_gpio.read_input(self._state_pin) - - @property - def is_closed(self): - """Return true if door is closed.""" - return self._state - - def _trigger(self): - """Trigger the door.""" - rpi_gpio.write_output(self._relay_pin, False) - sleep(self._relay_time) - rpi_gpio.write_output(self._relay_pin, True) - - def close_door(self): - """Close the door.""" - if not self.is_closed: - self._trigger() - - def open_door(self): - """Open the door.""" - if self.is_closed: - self._trigger() diff --git a/homeassistant/components/garage_door/services.yaml b/homeassistant/components/garage_door/services.yaml deleted file mode 100644 index a73c05ce24edb..0000000000000 --- a/homeassistant/components/garage_door/services.yaml +++ /dev/null @@ -1,15 +0,0 @@ -open: - description: Open all or specified garage door - - fields: - entity_id: - description: Name(s) of garage door(s) to open - example: 'garage.main' - -close: - description: Close all or a specified garage door - - fields: - entity_id: - description: Name(s) of garage door(s) to close - example: 'garage.main' diff --git a/homeassistant/components/garage_door/wink.py b/homeassistant/components/garage_door/wink.py deleted file mode 100644 index c1436d7556a15..0000000000000 --- a/homeassistant/components/garage_door/wink.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Support for Wink garage doors. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/garage_door.wink/ -""" - -from homeassistant.components.garage_door import GarageDoorDevice -from homeassistant.components.wink import WinkDevice - -DEPENDENCIES = ['wink'] - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Wink garage door platform.""" - import pywink - - add_devices(WinkGarageDoorDevice(door) for door in - pywink.get_garage_doors()) - - -class WinkGarageDoorDevice(WinkDevice, GarageDoorDevice): - """Representation of a Wink garage door.""" - - def __init__(self, wink): - """Initialize the garage door.""" - WinkDevice.__init__(self, wink) - - @property - def is_closed(self): - """Return true if door is closed.""" - return self.wink.state() == 0 - - def close_door(self): - """Close the door.""" - self.wink.set_state(0) - - def open_door(self): - """Open the door.""" - self.wink.set_state(1) diff --git a/homeassistant/components/garage_door/zwave.py b/homeassistant/components/garage_door/zwave.py deleted file mode 100644 index b180dd76e460f..0000000000000 --- a/homeassistant/components/garage_door/zwave.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -Support for Zwave garage door components. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/garagedoor.zwave/ -""" -# Because we do not compile openzwave on CI -# pylint: disable=import-error -import logging -from homeassistant.components.garage_door import DOMAIN -from homeassistant.components.zwave import ZWaveDeviceEntity -from homeassistant.components import zwave -from homeassistant.components.garage_door import GarageDoorDevice - -COMMAND_CLASS_SWITCH_BINARY = 0x25 # 37 -COMMAND_CLASS_BARRIER_OPERATOR = 0x66 # 102 -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Find and return Z-Wave garage door device.""" - if discovery_info is None or zwave.NETWORK is None: - return - - node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]] - value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]] - - if value.command_class != zwave.const.COMMAND_CLASS_SWITCH_BINARY and \ - value.command_class != zwave.const.COMMAND_CLASS_BARRIER_OPERATOR: - return - if value.type != zwave.const.TYPE_BOOL: - return - if value.genre != zwave.const.GENRE_USER: - return - - value.set_change_verified(False) - add_devices([ZwaveGarageDoor(value)]) - - -class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, GarageDoorDevice): - """Representation of an Zwave garage door device.""" - - def __init__(self, value): - """Initialize the zwave garage door.""" - from openzwave.network import ZWaveNetwork - from pydispatch import dispatcher - ZWaveDeviceEntity.__init__(self, value, DOMAIN) - self._state = value.data - dispatcher.connect( - self.value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) - - def value_changed(self, value): - """Called when a value has changed on the network.""" - if self._value.value_id == value.value_id: - self._state = value.data - self.update_ha_state() - _LOGGER.debug("Value changed on network %s", value) - - @property - def is_closed(self): - """Return the current position of Zwave garage door.""" - return not self._state - - def close_door(self): - """Close the garage door.""" - self._value.data = False - - def open_door(self): - """Open the garage door.""" - self._value.data = True diff --git a/homeassistant/components/hvac/__init__.py b/homeassistant/components/hvac/__init__.py deleted file mode 100644 index ab27af480a7f3..0000000000000 --- a/homeassistant/components/hvac/__init__.py +++ /dev/null @@ -1,500 +0,0 @@ -""" -Provides functionality to interact with hvacs. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/hvac/ -""" -import logging -import os -from numbers import Number - -from homeassistant.helpers.entity_component import EntityComponent - -from homeassistant.config import load_yaml_config_file -import homeassistant.util as util -from homeassistant.util.temperature import convert as convert_temperature -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa -from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN, - TEMP_CELSIUS) - -DOMAIN = "hvac" - -ENTITY_ID_FORMAT = DOMAIN + ".{}" -SCAN_INTERVAL = 60 - -SERVICE_SET_AWAY_MODE = "set_away_mode" -SERVICE_SET_AUX_HEAT = "set_aux_heat" -SERVICE_SET_TEMPERATURE = "set_temperature" -SERVICE_SET_FAN_MODE = "set_fan_mode" -SERVICE_SET_OPERATION_MODE = "set_operation_mode" -SERVICE_SET_SWING_MODE = "set_swing_mode" -SERVICE_SET_HUMIDITY = "set_humidity" - -STATE_HEAT = "heat" -STATE_COOL = "cool" -STATE_IDLE = "idle" -STATE_AUTO = "auto" -STATE_DRY = "dry" -STATE_FAN_ONLY = "fan_only" - -ATTR_CURRENT_TEMPERATURE = "current_temperature" -ATTR_MAX_TEMP = "max_temp" -ATTR_MIN_TEMP = "min_temp" -ATTR_AWAY_MODE = "away_mode" -ATTR_AUX_HEAT = "aux_heat" -ATTR_FAN_MODE = "fan_mode" -ATTR_FAN_LIST = "fan_list" -ATTR_CURRENT_HUMIDITY = "current_humidity" -ATTR_HUMIDITY = "humidity" -ATTR_MAX_HUMIDITY = "max_humidity" -ATTR_MIN_HUMIDITY = "min_humidity" -ATTR_OPERATION_MODE = "operation_mode" -ATTR_OPERATION_LIST = "operation_list" -ATTR_SWING_MODE = "swing_mode" -ATTR_SWING_LIST = "swing_list" - -_LOGGER = logging.getLogger(__name__) - - -def set_away_mode(hass, away_mode, entity_id=None): - """Turn all or specified hvac away mode on.""" - data = { - ATTR_AWAY_MODE: away_mode - } - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_AWAY_MODE, data) - - -def set_aux_heat(hass, aux_heat, entity_id=None): - """Turn all or specified hvac auxillary heater on.""" - data = { - ATTR_AUX_HEAT: aux_heat - } - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_AUX_HEAT, data) - - -def set_temperature(hass, temperature, entity_id=None): - """Set new target temperature.""" - data = {ATTR_TEMPERATURE: temperature} - - if entity_id is not None: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, data) - - -def set_humidity(hass, humidity, entity_id=None): - """Set new target humidity.""" - data = {ATTR_HUMIDITY: humidity} - - if entity_id is not None: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_HUMIDITY, data) - - -def set_fan_mode(hass, fan, entity_id=None): - """Turn all or specified hvac fan mode on.""" - data = {ATTR_FAN_MODE: fan} - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_FAN_MODE, data) - - -def set_operation_mode(hass, operation_mode, entity_id=None): - """Set new target operation mode.""" - data = {ATTR_OPERATION_MODE: operation_mode} - - if entity_id is not None: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_OPERATION_MODE, data) - - -def set_swing_mode(hass, swing_mode, entity_id=None): - """Set new target swing mode.""" - data = {ATTR_SWING_MODE: swing_mode} - - if entity_id is not None: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_SWING_MODE, data) - - -# pylint: disable=too-many-branches -def setup(hass, config): - """Setup hvacs.""" - _LOGGER.warning('This component has been deprecated in favour of' - ' the "climate" component and will be removed ' - 'in the future. Please upgrade.') - component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) - component.setup(config) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - def away_mode_set_service(service): - """Set away mode on target hvacs.""" - target_hvacs = component.extract_from_service(service) - - away_mode = service.data.get(ATTR_AWAY_MODE) - - if away_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) - return - - for hvac in target_hvacs: - if away_mode: - hvac.turn_away_mode_on() - else: - hvac.turn_away_mode_off() - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, - descriptions.get(SERVICE_SET_AWAY_MODE)) - - def aux_heat_set_service(service): - """Set auxillary heater on target hvacs.""" - target_hvacs = component.extract_from_service(service) - - aux_heat = service.data.get(ATTR_AUX_HEAT) - - if aux_heat is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_AUX_HEAT, ATTR_AUX_HEAT) - return - - for hvac in target_hvacs: - if aux_heat: - hvac.turn_aux_heat_on() - else: - hvac.turn_aux_heat_off() - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_AUX_HEAT, aux_heat_set_service, - descriptions.get(SERVICE_SET_AUX_HEAT)) - - def temperature_set_service(service): - """Set temperature on the target hvacs.""" - target_hvacs = component.extract_from_service(service) - - temperature = util.convert( - service.data.get(ATTR_TEMPERATURE), float) - - if temperature is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_TEMPERATURE, ATTR_TEMPERATURE) - return - - for hvac in target_hvacs: - hvac.set_temperature(convert_temperature( - temperature, hass.config.units.temperature_unit, - hvac.unit_of_measurement)) - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, - descriptions.get(SERVICE_SET_TEMPERATURE)) - - def humidity_set_service(service): - """Set humidity on the target hvacs.""" - target_hvacs = component.extract_from_service(service) - - humidity = service.data.get(ATTR_HUMIDITY) - - if humidity is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_HUMIDITY, ATTR_HUMIDITY) - return - - for hvac in target_hvacs: - hvac.set_humidity(humidity) - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_HUMIDITY, humidity_set_service, - descriptions.get(SERVICE_SET_HUMIDITY)) - - def fan_mode_set_service(service): - """Set fan mode on target hvacs.""" - target_hvacs = component.extract_from_service(service) - - fan = service.data.get(ATTR_FAN_MODE) - - if fan is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_FAN_MODE, ATTR_FAN_MODE) - return - - for hvac in target_hvacs: - hvac.set_fan_mode(fan) - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, - descriptions.get(SERVICE_SET_FAN_MODE)) - - def operation_set_service(service): - """Set operating mode on the target hvacs.""" - target_hvacs = component.extract_from_service(service) - - operation_mode = service.data.get(ATTR_OPERATION_MODE) - - if operation_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_OPERATION_MODE, ATTR_OPERATION_MODE) - return - - for hvac in target_hvacs: - hvac.set_operation_mode(operation_mode) - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_OPERATION_MODE, operation_set_service, - descriptions.get(SERVICE_SET_OPERATION_MODE)) - - def swing_set_service(service): - """Set swing mode on the target hvacs.""" - target_hvacs = component.extract_from_service(service) - - swing_mode = service.data.get(ATTR_SWING_MODE) - - if swing_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_SWING_MODE, ATTR_SWING_MODE) - return - - for hvac in target_hvacs: - hvac.set_swing_mode(swing_mode) - - if hvac.should_poll: - hvac.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_SWING_MODE, swing_set_service, - descriptions.get(SERVICE_SET_SWING_MODE)) - return True - - -class HvacDevice(Entity): - """Representation of a hvac.""" - - # pylint: disable=too-many-public-methods,no-self-use - @property - def state(self): - """Return the current state.""" - return self.current_operation or STATE_UNKNOWN - - @property - def state_attributes(self): - """Return the optional state attributes.""" - data = { - ATTR_CURRENT_TEMPERATURE: - self._convert_for_display(self.current_temperature), - ATTR_MIN_TEMP: self._convert_for_display(self.min_temp), - ATTR_MAX_TEMP: self._convert_for_display(self.max_temp), - ATTR_TEMPERATURE: - self._convert_for_display(self.target_temperature), - } - - humidity = self.target_humidity - if humidity is not None: - data[ATTR_HUMIDITY] = humidity - data[ATTR_CURRENT_HUMIDITY] = self.current_humidity - data[ATTR_MIN_HUMIDITY] = self.min_humidity - data[ATTR_MAX_HUMIDITY] = self.max_humidity - - fan_mode = self.current_fan_mode - if fan_mode is not None: - data[ATTR_FAN_MODE] = fan_mode - data[ATTR_FAN_LIST] = self.fan_list - - operation_mode = self.current_operation - if operation_mode is not None: - data[ATTR_OPERATION_MODE] = operation_mode - data[ATTR_OPERATION_LIST] = self.operation_list - - swing_mode = self.current_swing_mode - if swing_mode is not None: - data[ATTR_SWING_MODE] = swing_mode - data[ATTR_SWING_LIST] = self.swing_list - - is_away = self.is_away_mode_on - if is_away is not None: - data[ATTR_AWAY_MODE] = STATE_ON if is_away else STATE_OFF - - is_aux_heat = self.is_aux_heat_on - if is_aux_heat is not None: - data[ATTR_AUX_HEAT] = STATE_ON if is_aux_heat else STATE_OFF - - return data - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - raise NotImplementedError - - @property - def current_humidity(self): - """Return the current humidity.""" - return None - - @property - def target_humidity(self): - """Return the humidity we try to reach.""" - return None - - @property - def current_operation(self): - """Return current operation ie. heat, cool, idle.""" - return None - - @property - def operation_list(self): - """List of available operation modes.""" - return None - - @property - def current_temperature(self): - """Return the current temperature.""" - return None - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - raise NotImplementedError - - @property - def is_away_mode_on(self): - """Return true if away mode is on.""" - return None - - @property - def is_aux_heat_on(self): - """Return true if away mode is on.""" - return None - - @property - def current_fan_mode(self): - """Return the fan setting.""" - return None - - @property - def fan_list(self): - """List of available fan modes.""" - return None - - @property - def current_swing_mode(self): - """Return the fan setting.""" - return None - - @property - def swing_list(self): - """List of available swing modes.""" - return None - - def set_temperature(self, temperature): - """Set new target temperature.""" - raise NotImplementedError() - - def set_humidity(self, humidity): - """Set new target humidity.""" - raise NotImplementedError() - - def set_fan_mode(self, fan): - """Set new target fan mode.""" - raise NotImplementedError() - - def set_operation_mode(self, operation_mode): - """Set new target operation mode.""" - raise NotImplementedError() - - def set_swing_mode(self, swing_mode): - """Set new target swing operation.""" - raise NotImplementedError() - - def turn_away_mode_on(self): - """Turn away mode on.""" - raise NotImplementedError() - - def turn_away_mode_off(self): - """Turn away mode off.""" - raise NotImplementedError() - - def turn_aux_heat_on(self): - """Turn auxillary heater on.""" - raise NotImplementedError() - - def turn_aux_heat_off(self): - """Turn auxillary heater off.""" - raise NotImplementedError() - - @property - def min_temp(self): - """Return the minimum temperature.""" - return convert_temperature(19, TEMP_CELSIUS, self.unit_of_measurement) - - @property - def max_temp(self): - """Return the maximum temperature.""" - return convert_temperature(30, TEMP_CELSIUS, self.unit_of_measurement) - - @property - def min_humidity(self): - """Return the minimum humidity.""" - return 30 - - @property - def max_humidity(self): - """Return the maximum humidity.""" - return 99 - - def _convert_for_display(self, temp): - """Convert temperature into preferred units for display purposes.""" - if temp is None or not isinstance(temp, Number): - return temp - - value = convert_temperature(temp, self.unit_of_measurement, - self.hass.config.units.temperature_unit) - - if self.hass.config.units.temperature_unit is TEMP_CELSIUS: - decimal_count = 1 - else: - # Users of fahrenheit generally expect integer units. - decimal_count = 0 - - return round(value, decimal_count) diff --git a/homeassistant/components/hvac/demo.py b/homeassistant/components/hvac/demo.py deleted file mode 100644 index 9e4f2c15d29c3..0000000000000 --- a/homeassistant/components/hvac/demo.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -Demo platform that offers a fake hvac. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" -from homeassistant.components.hvac import HvacDevice -from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Demo hvacs.""" - add_devices([ - DemoHvac("HeatPump", 68, TEMP_FAHRENHEIT, None, 77, "Auto Low", - None, None, "Auto", "Heat", None), - DemoHvac("Hvac", 21, TEMP_CELSIUS, True, 22, "On High", - 67, 54, "Off", "Cool", False), - ]) - - -# pylint: disable=too-many-arguments, too-many-public-methods -class DemoHvac(HvacDevice): - """Representation of a demo hvac.""" - - # pylint: disable=too-many-instance-attributes - def __init__(self, name, target_temperature, unit_of_measurement, - away, current_temperature, current_fan_mode, - target_humidity, current_humidity, current_swing_mode, - current_operation, aux): - """Initialize the hvac.""" - self._name = name - self._target_temperature = target_temperature - self._target_humidity = target_humidity - self._unit_of_measurement = unit_of_measurement - self._away = away - self._current_temperature = current_temperature - self._current_humidity = current_humidity - self._current_fan_mode = current_fan_mode - self._current_operation = current_operation - self._aux = aux - self._current_swing_mode = current_swing_mode - self._fan_list = ["On Low", "On High", "Auto Low", "Auto High", "Off"] - self._operation_list = ["Heat", "Cool", "Auto Changeover", "Off"] - self._swing_list = ["Auto", 1, 2, 3, "Off"] - - @property - def should_poll(self): - """Polling not needed for a demo hvac.""" - return False - - @property - def name(self): - """Return the name of the hvac.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return self._unit_of_measurement - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._current_temperature - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temperature - - @property - def current_humidity(self): - """Return the current humidity.""" - return self._current_humidity - - @property - def target_humidity(self): - """Return the humidity we try to reach.""" - return self._target_humidity - - @property - def current_operation(self): - """Return current operation ie. heat, cool, idle.""" - return self._current_operation - - @property - def operation_list(self): - """List of available operation modes.""" - return self._operation_list - - @property - def is_away_mode_on(self): - """Return if away mode is on.""" - return self._away - - @property - def is_aux_heat_on(self): - """Return true if away mode is on.""" - return self._aux - - @property - def current_fan_mode(self): - """Return the fan setting.""" - return self._current_fan_mode - - @property - def fan_list(self): - """List of available fan modes.""" - return self._fan_list - - def set_temperature(self, temperature): - """Set new target temperature.""" - self._target_temperature = temperature - self.update_ha_state() - - def set_humidity(self, humidity): - """Set new target temperature.""" - self._target_humidity = humidity - self.update_ha_state() - - def set_swing_mode(self, swing_mode): - """Set new target temperature.""" - self._current_swing_mode = swing_mode - self.update_ha_state() - - def set_fan_mode(self, fan): - """Set new target temperature.""" - self._current_fan_mode = fan - self.update_ha_state() - - def set_operation_mode(self, operation_mode): - """Set new target temperature.""" - self._current_operation = operation_mode - self.update_ha_state() - - @property - def current_swing_mode(self): - """Return the swing setting.""" - return self._current_swing_mode - - @property - def swing_list(self): - """List of available swing modes.""" - return self._swing_list - - def turn_away_mode_on(self): - """Turn away mode on.""" - self._away = True - self.update_ha_state() - - def turn_away_mode_off(self): - """Turn away mode off.""" - self._away = False - self.update_ha_state() - - def turn_aux_heat_on(self): - """Turn away auxillary heater on.""" - self._aux = True - self.update_ha_state() - - def turn_aux_heat_off(self): - """Turn auxillary heater off.""" - self._aux = False - self.update_ha_state() diff --git a/homeassistant/components/hvac/services.yaml b/homeassistant/components/hvac/services.yaml deleted file mode 100644 index 5d9f746339968..0000000000000 --- a/homeassistant/components/hvac/services.yaml +++ /dev/null @@ -1,84 +0,0 @@ -set_aux_heat: - description: Turn auxillary heater on/off for hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.kitchen' - - aux_heat: - description: New value of axillary heater - example: true - -set_away_mode: - description: Turn away mode on/off for hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.kitchen' - - away_mode: - description: New value of away mode - example: true - -set_temperature: - description: Set target temperature of hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.kitchen' - - temperature: - description: New target temperature for hvac - example: 25 - -set_humidity: - description: Set target humidity of hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.kitchen' - - humidity: - description: New target humidity for hvac - example: 60 - -set_fan_mode: - description: Set fan operation for hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.nest' - - fan: - description: New value of fan mode - example: On Low - -set_operation_mode: - description: Set operation mode for hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.nest' - - operation_mode: - description: New value of operation mode - example: Heat - - -set_swing_mode: - description: Set swing operation for hvac - - fields: - entity_id: - description: Name(s) of entities to change - example: 'hvac.nest' - - swing_mode: - description: New value of swing mode - example: 1 diff --git a/homeassistant/components/hvac/zwave.py b/homeassistant/components/hvac/zwave.py deleted file mode 100755 index 5415fe0b41c51..0000000000000 --- a/homeassistant/components/hvac/zwave.py +++ /dev/null @@ -1,241 +0,0 @@ -""" -Support for ZWave HVAC devices. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/hvac.zwave/ -""" -# Because we do not compile openzwave on CI -# pylint: disable=import-error -import logging -from homeassistant.components.hvac import DOMAIN -from homeassistant.components.hvac import HvacDevice -from homeassistant.components.zwave import ZWaveDeviceEntity -from homeassistant.components import zwave -from homeassistant.const import (TEMP_FAHRENHEIT, TEMP_CELSIUS) - -_LOGGER = logging.getLogger(__name__) - -CONF_NAME = 'name' -DEFAULT_NAME = 'ZWave Hvac' - -REMOTEC = 0x5254 -REMOTEC_ZXT_120 = 0x8377 -REMOTEC_ZXT_120_THERMOSTAT = (REMOTEC, REMOTEC_ZXT_120, 0) - -WORKAROUND_ZXT_120 = 'zxt_120' - -DEVICE_MAPPINGS = { - REMOTEC_ZXT_120_THERMOSTAT: WORKAROUND_ZXT_120 -} - -ZXT_120_SET_TEMP = { - 'Heat': 1, - 'Cool': 2, - 'Dry Air': 8, - 'Auto Changeover': 10 -} - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the ZWave Hvac devices.""" - if discovery_info is None or zwave.NETWORK is None: - _LOGGER.debug("No discovery_info=%s or no NETWORK=%s", - discovery_info, zwave.NETWORK) - return - - node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]] - value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]] - value.set_change_verified(False) - add_devices([ZWaveHvac(value)]) - _LOGGER.debug("discovery_info=%s and zwave.NETWORK=%s", - discovery_info, zwave.NETWORK) - - -# pylint: disable=too-many-arguments, abstract-method -class ZWaveHvac(ZWaveDeviceEntity, HvacDevice): - """Represents a HeatControl hvac.""" - - # pylint: disable=too-many-public-methods, too-many-instance-attributes - def __init__(self, value): - """Initialize the zwave hvac.""" - from openzwave.network import ZWaveNetwork - from pydispatch import dispatcher - ZWaveDeviceEntity.__init__(self, value, DOMAIN) - self._node = value.node - self._target_temperature = None - self._current_temperature = None - self._current_operation = None - self._operation_list = None - self._current_operation_state = None - self._current_fan_mode = None - self._fan_list = None - self._current_swing_mode = None - self._swing_list = None - self._unit = None - self._zxt_120 = None - self.update_properties() - # register listener - dispatcher.connect( - self.value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) - # Make sure that we have values for the key before converting to int - if (value.node.manufacturer_id.strip() and - value.node.product_id.strip()): - specific_sensor_key = (int(value.node.manufacturer_id, 16), - int(value.node.product_id, 16), - value.index) - - if specific_sensor_key in DEVICE_MAPPINGS: - if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_ZXT_120: - _LOGGER.debug("Remotec ZXT-120 Zwave Thermostat as HVAC") - self._zxt_120 = 1 - - def value_changed(self, value): - """Called when a value has changed on the network.""" - if self._value.value_id == value.value_id or \ - self._value.node == value.node: - self.update_properties() - self.update_ha_state() - _LOGGER.debug("Value changed on network %s", value) - - def update_properties(self): - """Callback on data change for the registered node/value pair.""" - # Set point - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT) - .values()): - if int(value.data) != 0: - self._target_temperature = int(value.data) - # Operation Mode - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE) - .values()): - self._current_operation = value.data - self._operation_list = list(value.data_items) - _LOGGER.debug("self._operation_list=%s", self._operation_list) - # Current Temp - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL) - .values()): - if value.label == 'Temperature': - self._current_temperature = int(value.data) - self._unit = value.units - # Fan Mode - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE) - .values()): - self._current_operation_state = value.data - self._fan_list = list(value.data_items) - _LOGGER.debug("self._fan_list=%s", self._fan_list) - _LOGGER.debug("self._current_operation_state=%s", - self._current_operation_state) - # Swing mode - if self._zxt_120 == 1: - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_CONFIGURATION) - .values()): - if value.command_class == 112 and value.index == 33: - self._current_swing_mode = value.data - self._swing_list = list(value.data_items) - _LOGGER.debug("self._swing_list=%s", self._swing_list) - - @property - def should_poll(self): - """No polling on ZWave.""" - return False - - @property - def current_fan_mode(self): - """Return the fan speed set.""" - return self._current_operation_state - - @property - def fan_list(self): - """List of available fan modes.""" - return self._fan_list - - @property - def current_swing_mode(self): - """Return the swing mode set.""" - return self._current_swing_mode - - @property - def swing_list(self): - """List of available swing modes.""" - return self._swing_list - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - unit = self._unit - if unit == 'C': - return TEMP_CELSIUS - elif unit == 'F': - return TEMP_FAHRENHEIT - else: - _LOGGER.exception("unit_of_measurement=%s is not valid", - unit) - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._current_temperature - - @property - def current_operation(self): - """Return the current operation mode.""" - return self._current_operation - - @property - def operation_list(self): - """List of available operation modes.""" - return self._operation_list - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temperature - - def set_temperature(self, temperature): - """Set new target temperature.""" - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT) - .values()): - if value.command_class != 67: - continue - if self._zxt_120: - # ZXT-120 does not support get setpoint - self._target_temperature = temperature - if ZXT_120_SET_TEMP.get(self._current_operation) \ - != value.index: - continue - # ZXT-120 responds only to whole int - value.data = int(round(temperature, 0)) - else: - value.data = int(temperature) - break - - def set_fan_mode(self, fan): - """Set new target fan mode.""" - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE) - .values()): - if value.command_class == 68 and value.index == 0: - value.data = bytes(fan, 'utf-8') - break - - def set_operation_mode(self, operation_mode): - """Set new target operation mode.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE).values(): - if value.command_class == 64 and value.index == 0: - value.data = bytes(operation_mode, 'utf-8') - break - - def set_swing_mode(self, swing_mode): - """Set new target swing mode.""" - if self._zxt_120 == 1: - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_CONFIGURATION).values(): - if value.command_class == 112 and value.index == 33: - value.data = bytes(swing_mode, 'utf-8') - break diff --git a/homeassistant/components/rollershutter/__init__.py b/homeassistant/components/rollershutter/__init__.py deleted file mode 100644 index 3928eb384d805..0000000000000 --- a/homeassistant/components/rollershutter/__init__.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -Support for Roller shutters. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rollershutter/ -""" -import os -import logging - -import voluptuous as vol - -from homeassistant.config import load_yaml_config_file -from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa -import homeassistant.helpers.config_validation as cv -from homeassistant.components import group -from homeassistant.const import ( - SERVICE_MOVE_UP, SERVICE_MOVE_DOWN, SERVICE_MOVE_POSITION, SERVICE_STOP, - STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) - - -DOMAIN = 'rollershutter' -SCAN_INTERVAL = 15 - -GROUP_NAME_ALL_ROLLERSHUTTERS = 'all rollershutters' -ENTITY_ID_ALL_ROLLERSHUTTERS = group.ENTITY_ID_FORMAT.format( - 'all_rollershutters') - -ENTITY_ID_FORMAT = DOMAIN + '.{}' - -_LOGGER = logging.getLogger(__name__) - -ATTR_CURRENT_POSITION = 'current_position' -ATTR_POSITION = 'position' - -ROLLERSHUTTER_SERVICE_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, -}) - -ROLLERSHUTTER_MOVE_POSITION_SCHEMA = ROLLERSHUTTER_SERVICE_SCHEMA.extend({ - vol.Required(ATTR_POSITION): - vol.All(vol.Coerce(int), vol.Range(min=0, max=100)), -}) - - -def is_open(hass, entity_id=None): - """Return if the roller shutter is open based on the statemachine.""" - entity_id = entity_id or ENTITY_ID_ALL_ROLLERSHUTTERS - return hass.states.is_state(entity_id, STATE_OPEN) - - -def move_up(hass, entity_id=None): - """Move up all or specified roller shutter.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_MOVE_UP, data) - - -def move_down(hass, entity_id=None): - """Move down all or specified roller shutter.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_MOVE_DOWN, data) - - -def move_position(hass, position, entity_id=None): - """Move to specific position all or specified roller shutter.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} - data[ATTR_POSITION] = position - hass.services.call(DOMAIN, SERVICE_MOVE_POSITION, data) - - -def stop(hass, entity_id=None): - """Stop all or specified roller shutter.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_STOP, data) - - -def setup(hass, config): - """Track states and offer events for roller shutters.""" - _LOGGER.warning('This component has been deprecated in favour of the ' - '"cover" component and will be removed in the future.' - ' Please upgrade.') - component = EntityComponent( - _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_ROLLERSHUTTERS) - component.setup(config) - - def handle_rollershutter_service(service): - """Handle calls to the roller shutter services.""" - target_rollershutters = component.extract_from_service(service) - - for rollershutter in target_rollershutters: - if service.service == SERVICE_MOVE_UP: - rollershutter.move_up() - elif service.service == SERVICE_MOVE_DOWN: - rollershutter.move_down() - elif service.service == SERVICE_MOVE_POSITION: - rollershutter.move_position(service.data[ATTR_POSITION]) - elif service.service == SERVICE_STOP: - rollershutter.stop() - - if rollershutter.should_poll: - rollershutter.update_ha_state(True) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - hass.services.register(DOMAIN, SERVICE_MOVE_UP, - handle_rollershutter_service, - descriptions.get(SERVICE_MOVE_UP), - schema=ROLLERSHUTTER_SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_MOVE_DOWN, - handle_rollershutter_service, - descriptions.get(SERVICE_MOVE_DOWN), - schema=ROLLERSHUTTER_SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_MOVE_POSITION, - handle_rollershutter_service, - descriptions.get(SERVICE_MOVE_POSITION), - schema=ROLLERSHUTTER_MOVE_POSITION_SCHEMA) - hass.services.register(DOMAIN, SERVICE_STOP, - handle_rollershutter_service, - descriptions.get(SERVICE_STOP), - schema=ROLLERSHUTTER_SERVICE_SCHEMA) - return True - - -class RollershutterDevice(Entity): - """Representation a rollers hutter.""" - - # pylint: disable=no-self-use - @property - def current_position(self): - """Return current position of roller shutter. - - None is unknown, 0 is closed, 100 is fully open. - """ - raise NotImplementedError() - - @property - def state(self): - """Return the state of the roller shutter.""" - current = self.current_position - - if current is None: - return STATE_UNKNOWN - - return STATE_CLOSED if current == 0 else STATE_OPEN - - @property - def state_attributes(self): - """Return the state attributes.""" - current = self.current_position - - if current is None: - return None - - return { - ATTR_CURRENT_POSITION: current - } - - def move_up(self, **kwargs): - """Move the roller shutter down.""" - raise NotImplementedError() - - def move_down(self, **kwargs): - """Move the roller shutter up.""" - raise NotImplementedError() - - def move_position(self, **kwargs): - """Move the roller shutter to a specific position.""" - raise NotImplementedError() - - def stop(self, **kwargs): - """Stop the roller shutter.""" - raise NotImplementedError() diff --git a/homeassistant/components/rollershutter/command_line.py b/homeassistant/components/rollershutter/command_line.py deleted file mode 100644 index 8ee88ae9ce584..0000000000000 --- a/homeassistant/components/rollershutter/command_line.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Support for command roller shutters. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rollershutter.command_line/ -""" -import logging -import subprocess - -from homeassistant.components.rollershutter import RollershutterDevice -from homeassistant.const import CONF_VALUE_TEMPLATE -from homeassistant.helpers.template import Template - -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Setup roller shutter controlled by shell commands.""" - rollershutters = config.get('rollershutters', {}) - devices = [] - - for dev_name, properties in rollershutters.items(): - value_template = properties.get(CONF_VALUE_TEMPLATE) - - if value_template is not None: - value_template = Template(value_template, hass) - - devices.append( - CommandRollershutter( - hass, - properties.get('name', dev_name), - properties.get('upcmd', 'true'), - properties.get('downcmd', 'true'), - properties.get('stopcmd', 'true'), - properties.get('statecmd', False), - value_template)) - add_devices_callback(devices) - - -# pylint: disable=abstract-method -# pylint: disable=too-many-arguments, too-many-instance-attributes -class CommandRollershutter(RollershutterDevice): - """Representation a command line roller shutter.""" - - # pylint: disable=too-many-arguments - def __init__(self, hass, name, command_up, command_down, command_stop, - command_state, value_template): - """Initialize the roller shutter.""" - self._hass = hass - self._name = name - self._state = None - self._command_up = command_up - self._command_down = command_down - self._command_stop = command_stop - self._command_state = command_state - self._value_template = value_template - - @staticmethod - def _move_rollershutter(command): - """Execute the actual commands.""" - _LOGGER.info('Running command: %s', command) - - success = (subprocess.call(command, shell=True) == 0) - - if not success: - _LOGGER.error('Command failed: %s', command) - - return success - - @staticmethod - def _query_state_value(command): - """Execute state command for return value.""" - _LOGGER.info('Running state command: %s', command) - - try: - return_value = subprocess.check_output(command, shell=True) - return return_value.strip().decode('utf-8') - except subprocess.CalledProcessError: - _LOGGER.error('Command failed: %s', command) - - @property - def should_poll(self): - """Only poll if we have state command.""" - return self._command_state is not None - - @property - def name(self): - """Return the name of the roller shutter.""" - return self._name - - @property - def current_position(self): - """Return current position of roller shutter. - - None is unknown, 0 is closed, 100 is fully open. - """ - return self._state - - def _query_state(self): - """Query for the state.""" - if not self._command_state: - _LOGGER.error('No state command specified') - return - return self._query_state_value(self._command_state) - - def update(self): - """Update device state.""" - if self._command_state: - payload = str(self._query_state()) - if self._value_template: - payload = self._value_template.render_with_possible_json_value( - payload) - self._state = int(payload) - - def move_up(self, **kwargs): - """Move the roller shutter up.""" - self._move_rollershutter(self._command_up) - - def move_down(self, **kwargs): - """Move the roller shutter down.""" - self._move_rollershutter(self._command_down) - - def stop(self, **kwargs): - """Stop the device.""" - self._move_rollershutter(self._command_stop) diff --git a/homeassistant/components/rollershutter/demo.py b/homeassistant/components/rollershutter/demo.py deleted file mode 100644 index 6799d062e4329..0000000000000 --- a/homeassistant/components/rollershutter/demo.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Demo platform for the rollor shutter component. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" -from homeassistant.components.rollershutter import RollershutterDevice -from homeassistant.helpers.event import track_utc_time_change - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Demo roller shutters.""" - add_devices([ - DemoRollershutter(hass, 'Kitchen Window', 0), - DemoRollershutter(hass, 'Living Room Window', 100), - ]) - - -class DemoRollershutter(RollershutterDevice): - """Representation of a demo roller shutter.""" - - # pylint: disable=no-self-use - def __init__(self, hass, name, position): - """Initialize the roller shutter.""" - self.hass = hass - self._name = name - self._position = position - self._moving_up = True - self._unsub_listener = None - - @property - def name(self): - """Return the name of the roller shutter.""" - return self._name - - @property - def should_poll(self): - """No polling needed for a demo roller shutter.""" - return False - - @property - def current_position(self): - """Return the current position of the roller shutter.""" - return self._position - - def move_up(self, **kwargs): - """Move the roller shutter down.""" - if self._position == 0: - return - - self._listen() - self._moving_up = True - - def move_down(self, **kwargs): - """Move the roller shutter up.""" - if self._position == 100: - return - - self._listen() - self._moving_up = False - - def move_position(self, position, **kwargs): - """Move the roller shutter to a specific position.""" - if self._position == position: - return - - self._listen() - self._moving_up = position < self._position - - def stop(self, **kwargs): - """Stop the roller shutter.""" - if self._unsub_listener is not None: - self._unsub_listener() - self._unsub_listener = None - - def _listen(self): - """Listen for changes.""" - if self._unsub_listener is None: - self._unsub_listener = track_utc_time_change(self.hass, - self._time_changed) - - def _time_changed(self, now): - """Track time changes.""" - if self._moving_up: - self._position -= 10 - else: - self._position += 10 - - if self._position % 100 == 0: - self.stop() - - self.update_ha_state() diff --git a/homeassistant/components/rollershutter/mqtt.py b/homeassistant/components/rollershutter/mqtt.py deleted file mode 100644 index aa0839ff094c6..0000000000000 --- a/homeassistant/components/rollershutter/mqtt.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -Support for MQTT roller shutters. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rollershutter.mqtt/ -""" -import logging - -import voluptuous as vol - -import homeassistant.components.mqtt as mqtt -from homeassistant.components.rollershutter import RollershutterDevice -from homeassistant.const import CONF_NAME, CONF_VALUE_TEMPLATE -from homeassistant.components.mqtt import ( - CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS) -import homeassistant.helpers.config_validation as cv - -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['mqtt'] - -CONF_PAYLOAD_UP = 'payload_up' -CONF_PAYLOAD_DOWN = 'payload_down' -CONF_PAYLOAD_STOP = 'payload_stop' - -DEFAULT_NAME = "MQTT Rollershutter" -DEFAULT_PAYLOAD_UP = "UP" -DEFAULT_PAYLOAD_DOWN = "DOWN" -DEFAULT_PAYLOAD_STOP = "STOP" - -PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_PAYLOAD_UP, default=DEFAULT_PAYLOAD_UP): cv.string, - vol.Optional(CONF_PAYLOAD_DOWN, default=DEFAULT_PAYLOAD_DOWN): cv.string, - vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string, -}) - - -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Add MQTT Rollershutter.""" - value_template = config.get(CONF_VALUE_TEMPLATE) - if value_template is not None: - value_template.hass = hass - add_devices_callback([MqttRollershutter( - hass, - config[CONF_NAME], - config.get(CONF_STATE_TOPIC), - config[CONF_COMMAND_TOPIC], - config[CONF_QOS], - config[CONF_PAYLOAD_UP], - config[CONF_PAYLOAD_DOWN], - config[CONF_PAYLOAD_STOP], - value_template, - )]) - - -# pylint: disable=abstract-method -# pylint: disable=too-many-arguments, too-many-instance-attributes -class MqttRollershutter(RollershutterDevice): - """Representation of a roller shutter that can be controlled using MQTT.""" - - def __init__(self, hass, name, state_topic, command_topic, qos, - payload_up, payload_down, payload_stop, value_template): - """Initialize the roller shutter.""" - self._state = None - self._hass = hass - self._name = name - self._state_topic = state_topic - self._command_topic = command_topic - self._qos = qos - self._payload_up = payload_up - self._payload_down = payload_down - self._payload_stop = payload_stop - - if self._state_topic is None: - return - - def message_received(topic, payload, qos): - """A new MQTT message has been received.""" - if value_template is not None: - payload = value_template.render_with_possible_json_value( - payload) - if payload.isnumeric() and 0 <= int(payload) <= 100: - self._state = int(payload) - self.update_ha_state() - else: - _LOGGER.warning( - "Payload is expected to be an integer between 0 and 100") - - mqtt.subscribe(hass, self._state_topic, message_received, self._qos) - - @property - def should_poll(self): - """No polling needed.""" - return False - - @property - def name(self): - """Return the name of the roller shutter.""" - return self._name - - @property - def current_position(self): - """Return current position of roller shutter. - - None is unknown, 0 is closed, 100 is fully open. - """ - return self._state - - def move_up(self, **kwargs): - """Move the roller shutter up.""" - mqtt.publish(self.hass, self._command_topic, self._payload_up, - self._qos) - - def move_down(self, **kwargs): - """Move the roller shutter down.""" - mqtt.publish(self.hass, self._command_topic, self._payload_down, - self._qos) - - def stop(self, **kwargs): - """Stop the device.""" - mqtt.publish(self.hass, self._command_topic, self._payload_stop, - self._qos) diff --git a/homeassistant/components/rollershutter/rfxtrx.py b/homeassistant/components/rollershutter/rfxtrx.py deleted file mode 100644 index 19bcea4e8923b..0000000000000 --- a/homeassistant/components/rollershutter/rfxtrx.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Support for RFXtrx roller shutter components. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/rollershutter.rfxtrx/ -""" - -import homeassistant.components.rfxtrx as rfxtrx -from homeassistant.components.rollershutter import RollershutterDevice - -DEPENDENCIES = ['rfxtrx'] - -PLATFORM_SCHEMA = rfxtrx.DEFAULT_SCHEMA - - -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Setup the Demo roller shutters.""" - import RFXtrx as rfxtrxmod - - # Add rollershutter from config file - rollershutters = rfxtrx.get_devices_from_config(config, - RfxtrxRollershutter) - add_devices_callback(rollershutters) - - def rollershutter_update(event): - """Callback for roller shutter updates from the RFXtrx gateway.""" - if not isinstance(event.device, rfxtrxmod.LightingDevice) or \ - event.device.known_to_be_dimmable or \ - not event.device.known_to_be_rollershutter: - return - - new_device = rfxtrx.get_new_device(event, config, RfxtrxRollershutter) - if new_device: - add_devices_callback([new_device]) - - rfxtrx.apply_received_command(event) - - # Subscribe to main rfxtrx events - if rollershutter_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS: - rfxtrx.RECEIVED_EVT_SUBSCRIBERS.append(rollershutter_update) - - -# pylint: disable=abstract-method -class RfxtrxRollershutter(rfxtrx.RfxtrxDevice, RollershutterDevice): - """Representation of an rfxtrx roller shutter.""" - - @property - def should_poll(self): - """No polling available in rfxtrx roller shutter.""" - return False - - @property - def current_position(self): - """No position available in rfxtrx roller shutter.""" - return None - - def move_up(self, **kwargs): - """Move the roller shutter up.""" - self._send_command("roll_up") - - def move_down(self, **kwargs): - """Move the roller shutter down.""" - self._send_command("roll_down") - - def stop(self, **kwargs): - """Stop the roller shutter.""" - self._send_command("stop_roll") diff --git a/homeassistant/components/rollershutter/scsgate.py b/homeassistant/components/rollershutter/scsgate.py deleted file mode 100644 index e67395d054c99..0000000000000 --- a/homeassistant/components/rollershutter/scsgate.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -Allow to configure a SCSGate roller shutter. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rollershutter.scsgate/ -""" -import logging - -import homeassistant.components.scsgate as scsgate -from homeassistant.components.rollershutter import RollershutterDevice - -DEPENDENCIES = ['scsgate'] - - -def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Setup the SCSGate roller shutter.""" - devices = config.get('devices') - rollershutters = [] - logger = logging.getLogger(__name__) - - if devices: - for _, entity_info in devices.items(): - if entity_info['scs_id'] in scsgate.SCSGATE.devices: - continue - - logger.info("Adding %s scsgate.rollershutter", entity_info['name']) - - name = entity_info['name'] - scs_id = entity_info['scs_id'] - rollershutter = SCSGateRollerShutter( - name=name, - scs_id=scs_id, - logger=logger) - scsgate.SCSGATE.add_device(rollershutter) - rollershutters.append(rollershutter) - - add_devices_callback(rollershutters) - - -# pylint: disable=abstract-method -# pylint: disable=too-many-arguments, too-many-instance-attributes -class SCSGateRollerShutter(RollershutterDevice): - """Representation of SCSGate rollershutter.""" - - def __init__(self, scs_id, name, logger): - """Initialize the roller shutter.""" - self._scs_id = scs_id - self._name = name - self._logger = logger - - @property - def scs_id(self): - """Return the SCSGate ID.""" - return self._scs_id - - @property - def should_poll(self): - """No polling needed.""" - return False - - @property - def name(self): - """Return the name of the roller shutter.""" - return self._name - - @property - def current_position(self): - """Return current position of roller shutter. - - None is unknown, 0 is closed, 100 is fully open. - """ - return None - - def move_up(self, **kwargs): - """Move the roller shutter up.""" - from scsgate.tasks import RaiseRollerShutterTask - - scsgate.SCSGATE.append_task( - RaiseRollerShutterTask(target=self._scs_id)) - - def move_down(self, **kwargs): - """Move the rollers hutter down.""" - from scsgate.tasks import LowerRollerShutterTask - - scsgate.SCSGATE.append_task( - LowerRollerShutterTask(target=self._scs_id)) - - def stop(self, **kwargs): - """Stop the device.""" - from scsgate.tasks import HaltRollerShutterTask - - scsgate.SCSGATE.append_task(HaltRollerShutterTask(target=self._scs_id)) - - def process_event(self, message): - """Handle a SCSGate message related with this roller shutter.""" - self._logger.debug( - "Rollershutter %s, got message %s", - self._scs_id, message.toggled) diff --git a/homeassistant/components/rollershutter/services.yaml b/homeassistant/components/rollershutter/services.yaml deleted file mode 100644 index 2991693961b6f..0000000000000 --- a/homeassistant/components/rollershutter/services.yaml +++ /dev/null @@ -1,31 +0,0 @@ -move_up: - description: Move up all or specified roller shutter - - fields: - entity_id: - description: Name(s) of roller shutter(s) to move up - example: 'rollershutter.living_room' - -move_down: - description: Move down all or specified roller shutter - - fields: - entity_id: - description: Name(s) of roller shutter(s) to move down - example: 'rollershutter.living_room' - -move_position: - description: Move to specific position all or specified roller shutter - - fields: - position: - description: Position of the rollershutter (0 to 100) - example: 30 - -stop: - description: Stop all or specified roller shutter - - fields: - entity_id: - description: Name(s) of roller shutter(s) to stop - example: 'rollershutter.living_room' diff --git a/homeassistant/components/rollershutter/wink.py b/homeassistant/components/rollershutter/wink.py deleted file mode 100644 index 3ba1c578ef887..0000000000000 --- a/homeassistant/components/rollershutter/wink.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Support for Wink Shades. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rollershutter.wink/ -""" - -from homeassistant.components.rollershutter import RollershutterDevice -from homeassistant.components.wink import WinkDevice - -DEPENDENCIES = ['wink'] - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Wink rollershutter platform.""" - import pywink - - add_devices(WinkRollershutterDevice(shade) for shade in - pywink.get_shades()) - - -# pylint: disable=abstract-method -class WinkRollershutterDevice(WinkDevice, RollershutterDevice): - """Representation of a Wink rollershutter (shades).""" - - def __init__(self, wink): - """Initialize the rollershutter.""" - WinkDevice.__init__(self, wink) - - @property - def should_poll(self): - """Wink Shades don't track their position.""" - return False - - def move_down(self): - """Close the shade.""" - self.wink.set_state(0) - - def move_up(self): - """Open the shade.""" - self.wink.set_state(1) - - @property - def current_position(self): - """Return current position of roller shutter. - - Wink reports blind shade positions as 0 or 1. - home-assistant expects: - None is unknown, 0 is closed, 100 is fully open. - """ - state = self.wink.state() - if state == 0: - return 0 - elif state == 1: - return 100 - else: - return None - - def stop(self): - """Can't stop Wink rollershutter due to API.""" - pass diff --git a/homeassistant/components/rollershutter/zwave.py b/homeassistant/components/rollershutter/zwave.py deleted file mode 100644 index e0f1d2b6e4bae..0000000000000 --- a/homeassistant/components/rollershutter/zwave.py +++ /dev/null @@ -1,139 +0,0 @@ -""" -Support for Zwave roller shutter components. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/rollershutter.zwave/ -""" -# Because we do not compile openzwave on CI -# pylint: disable=import-error -import logging -from homeassistant.components.rollershutter import DOMAIN -from homeassistant.components.zwave import ZWaveDeviceEntity -from homeassistant.components import zwave -from homeassistant.components.rollershutter import RollershutterDevice - -SOMFY = 0x47 -SOMFY_ZRTSI = 0x5a52 -SOMFY_ZRTSI_CONTROLLER = (SOMFY, SOMFY_ZRTSI) -WORKAROUND = 'workaround' - -DEVICE_MAPPINGS = { - SOMFY_ZRTSI_CONTROLLER: WORKAROUND -} - -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Find and return Z-Wave roller shutters.""" - if discovery_info is None or zwave.NETWORK is None: - return - - node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]] - value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]] - - if value.command_class != zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL: - return - if value.index != 0: - return - - value.set_change_verified(False) - add_devices([ZwaveRollershutter(value)]) - - -class ZwaveRollershutter(zwave.ZWaveDeviceEntity, RollershutterDevice): - """Representation of an Zwave roller shutter.""" - - def __init__(self, value): - """Initialize the zwave rollershutter.""" - import libopenzwave - from openzwave.network import ZWaveNetwork - from pydispatch import dispatcher - ZWaveDeviceEntity.__init__(self, value, DOMAIN) - self._lozwmgr = libopenzwave.PyManager() - self._lozwmgr.create() - self._node = value.node - self._current_position = None - self._workaround = None - dispatcher.connect( - self.value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) - if (value.node.manufacturer_id.strip() and - value.node.product_id.strip()): - specific_sensor_key = (int(value.node.manufacturer_id, 16), - int(value.node.product_type, 16)) - - if specific_sensor_key in DEVICE_MAPPINGS: - if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND: - _LOGGER.debug("Controller without positioning feedback") - self._workaround = 1 - - def value_changed(self, value): - """Called when a value has changed on the network.""" - if self._value.value_id == value.value_id or \ - self._value.node == value.node: - self.update_properties() - self.update_ha_state() - _LOGGER.debug("Value changed on network %s", value) - - def update_properties(self): - """Callback on data change for the registered node/value pair.""" - # Position value - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and \ - value.label == 'Level': - self._current_position = value.data - - @property - def current_position(self): - """Return the current position of Zwave roller shutter.""" - if not self._workaround: - if self._current_position is not None: - if self._current_position <= 5: - return 100 - elif self._current_position >= 95: - return 0 - else: - return 100 - self._current_position - - def move_up(self, **kwargs): - """Move the roller shutter up.""" - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL) - .values()): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Open' or value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Down': - self._lozwmgr.pressButton(value.value_id) - break - - def move_down(self, **kwargs): - """Move the roller shutter down.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Up' or value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Close': - self._lozwmgr.pressButton(value.value_id) - break - - def move_position(self, position, **kwargs): - """Move the roller shutter to a specific position.""" - self._node.set_dimmer(self._value.value_id, 100 - position) - - def stop(self, **kwargs): - """Stop the roller shutter.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Open' or value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Down': - self._lozwmgr.releaseButton(value.value_id) - break diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py deleted file mode 100644 index 52452ef0e5967..0000000000000 --- a/homeassistant/components/thermostat/__init__.py +++ /dev/null @@ -1,330 +0,0 @@ -""" -Provides functionality to interact with thermostats. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/thermostat/ -""" -import logging -import os -from numbers import Number - -import voluptuous as vol - -from homeassistant.helpers.entity_component import EntityComponent - -from homeassistant.config import load_yaml_config_file -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa -import homeassistant.helpers.config_validation as cv -from homeassistant.util.temperature import convert -from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN, - TEMP_CELSIUS) - -DOMAIN = "thermostat" - -ENTITY_ID_FORMAT = DOMAIN + ".{}" -SCAN_INTERVAL = 60 - -SERVICE_SET_AWAY_MODE = "set_away_mode" -SERVICE_SET_TEMPERATURE = "set_temperature" -SERVICE_SET_FAN_MODE = "set_fan_mode" -SERVICE_SET_HVAC_MODE = "set_hvac_mode" - -STATE_HEAT = "heat" -STATE_COOL = "cool" -STATE_IDLE = "idle" -STATE_AUTO = "auto" - -ATTR_CURRENT_TEMPERATURE = "current_temperature" -ATTR_AWAY_MODE = "away_mode" -ATTR_FAN = "fan" -ATTR_HVAC_MODE = "hvac_mode" -ATTR_MAX_TEMP = "max_temp" -ATTR_MIN_TEMP = "min_temp" -ATTR_TEMPERATURE_LOW = "target_temp_low" -ATTR_TEMPERATURE_HIGH = "target_temp_high" -ATTR_OPERATION = "current_operation" - -_LOGGER = logging.getLogger(__name__) - -SET_AWAY_MODE_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, - vol.Required(ATTR_AWAY_MODE): cv.boolean, -}) -SET_TEMPERATURE_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, - vol.Required(ATTR_TEMPERATURE): vol.Coerce(float), -}) -SET_FAN_MODE_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, - vol.Required(ATTR_FAN): cv.boolean, -}) -SET_HVAC_MODE_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, - vol.Required(ATTR_HVAC_MODE): cv.string, -}) - - -def set_away_mode(hass, away_mode, entity_id=None): - """Turn all or specified thermostat away mode on.""" - data = { - ATTR_AWAY_MODE: away_mode - } - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_AWAY_MODE, data) - - -def set_temperature(hass, temperature, entity_id=None): - """Set new target temperature.""" - data = {ATTR_TEMPERATURE: temperature} - - if entity_id is not None: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, data) - - -def set_fan_mode(hass, fan_mode, entity_id=None): - """Turn all or specified thermostat fan mode on.""" - data = { - ATTR_FAN: fan_mode - } - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_FAN_MODE, data) - - -def set_hvac_mode(hass, hvac_mode, entity_id=None): - """Set specified thermostat hvac mode.""" - data = { - ATTR_HVAC_MODE: hvac_mode - } - - if entity_id: - data[ATTR_ENTITY_ID] = entity_id - - hass.services.call(DOMAIN, SERVICE_SET_HVAC_MODE, data) - - -# pylint: disable=too-many-branches -def setup(hass, config): - """Setup thermostats.""" - _LOGGER.warning('This component has been deprecated in favour of' - ' the "climate" component and will be removed ' - 'in the future. Please upgrade.') - component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) - component.setup(config) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - def away_mode_set_service(service): - """Set away mode on target thermostats.""" - target_thermostats = component.extract_from_service(service) - - away_mode = service.data[ATTR_AWAY_MODE] - - for thermostat in target_thermostats: - if away_mode: - thermostat.turn_away_mode_on() - else: - thermostat.turn_away_mode_off() - - thermostat.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_AWAY_MODE, away_mode_set_service, - descriptions.get(SERVICE_SET_AWAY_MODE), - schema=SET_AWAY_MODE_SCHEMA) - - def temperature_set_service(service): - """Set temperature on the target thermostats.""" - target_thermostats = component.extract_from_service(service) - - temperature = service.data[ATTR_TEMPERATURE] - - for thermostat in target_thermostats: - converted_temperature = convert( - temperature, hass.config.units.temperature_unit, - thermostat.unit_of_measurement) - - thermostat.set_temperature(converted_temperature) - thermostat.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_TEMPERATURE, temperature_set_service, - descriptions.get(SERVICE_SET_TEMPERATURE), - schema=SET_TEMPERATURE_SCHEMA) - - def fan_mode_set_service(service): - """Set fan mode on target thermostats.""" - target_thermostats = component.extract_from_service(service) - - fan_mode = service.data[ATTR_FAN] - - for thermostat in target_thermostats: - if fan_mode: - thermostat.turn_fan_on() - else: - thermostat.turn_fan_off() - - thermostat.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_FAN_MODE, fan_mode_set_service, - descriptions.get(SERVICE_SET_FAN_MODE), - schema=SET_FAN_MODE_SCHEMA) - - def hvac_mode_set_service(service): - """Set hvac mode on target thermostats.""" - target_thermostats = component.extract_from_service(service) - - hvac_mode = service.data[ATTR_HVAC_MODE] - - for thermostat in target_thermostats: - thermostat.set_hvac_mode(hvac_mode) - - thermostat.update_ha_state(True) - - hass.services.register( - DOMAIN, SERVICE_SET_HVAC_MODE, hvac_mode_set_service, - descriptions.get(SERVICE_SET_HVAC_MODE), - schema=SET_HVAC_MODE_SCHEMA) - - return True - - -class ThermostatDevice(Entity): - """Representation of a thermostat.""" - - # pylint: disable=no-self-use - @property - def state(self): - """Return the current state.""" - return self.target_temperature or STATE_UNKNOWN - - @property - def state_attributes(self): - """Return the optional state attributes.""" - data = { - ATTR_CURRENT_TEMPERATURE: - self._convert_for_display(self.current_temperature), - ATTR_MIN_TEMP: self._convert_for_display(self.min_temp), - ATTR_MAX_TEMP: self._convert_for_display(self.max_temp), - ATTR_TEMPERATURE: - self._convert_for_display(self.target_temperature), - ATTR_TEMPERATURE_LOW: - self._convert_for_display(self.target_temperature_low), - ATTR_TEMPERATURE_HIGH: - self._convert_for_display(self.target_temperature_high), - } - - operation = self.operation - if operation is not None: - data[ATTR_OPERATION] = operation - - is_away = self.is_away_mode_on - if is_away is not None: - data[ATTR_AWAY_MODE] = STATE_ON if is_away else STATE_OFF - - is_fan_on = self.is_fan_on - if is_fan_on is not None: - data[ATTR_FAN] = STATE_ON if is_fan_on else STATE_OFF - - return data - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - raise NotImplementedError - - @property - def current_temperature(self): - """Return the current temperature.""" - raise NotImplementedError - - @property - def operation(self): - """Return current operation ie. heat, cool, idle.""" - return None - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - raise NotImplementedError - - @property - def target_temperature_low(self): - """Return the lower bound temperature we try to reach.""" - return self.target_temperature - - @property - def target_temperature_high(self): - """Return the upper bound temperature we try to reach.""" - return self.target_temperature - - @property - def is_away_mode_on(self): - """Return true if away mode is on.""" - return None - - @property - def is_fan_on(self): - """Return true if the fan is on.""" - return None - - def set_temperature(self, temperature): - """Set new target temperature.""" - raise NotImplementedError() - - def set_hvac_mode(self, hvac_mode): - """Set hvac mode.""" - raise NotImplementedError() - - def turn_away_mode_on(self): - """Turn away mode on.""" - raise NotImplementedError() - - def turn_away_mode_off(self): - """Turn away mode off.""" - raise NotImplementedError() - - def turn_fan_on(self): - """Turn fan on.""" - raise NotImplementedError() - - def turn_fan_off(self): - """Turn fan off.""" - raise NotImplementedError() - - @property - def min_temp(self): - """Return the minimum temperature.""" - return convert(7, TEMP_CELSIUS, self.unit_of_measurement) - - @property - def max_temp(self): - """Return the maximum temperature.""" - return convert(35, TEMP_CELSIUS, self.unit_of_measurement) - - def _convert_for_display(self, temp): - """Convert temperature into preferred units for display purposes.""" - if temp is None or not isinstance(temp, Number): - return temp - - value = self.hass.config.units.temperature(temp, - self.unit_of_measurement) - - if self.hass.config.units.is_metric: - decimal_count = 1 - else: - # Users of fahrenheit generally expect integer units. - decimal_count = 0 - - return round(value, decimal_count) diff --git a/homeassistant/components/thermostat/demo.py b/homeassistant/components/thermostat/demo.py deleted file mode 100644 index 7718299ef6a35..0000000000000 --- a/homeassistant/components/thermostat/demo.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -Demo platform that offers a fake thermostat. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/demo/ -""" -from homeassistant.components.thermostat import ThermostatDevice -from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Demo thermostats.""" - add_devices([ - DemoThermostat("Nest", 21, TEMP_CELSIUS, False, 19, False), - DemoThermostat("Thermostat", 68, TEMP_FAHRENHEIT, True, 77, True), - ]) - - -# pylint: disable=too-many-arguments, abstract-method -class DemoThermostat(ThermostatDevice): - """Representation of a demo thermostat.""" - - def __init__(self, name, target_temperature, unit_of_measurement, - away, current_temperature, is_fan_on): - """Initialize the thermostat.""" - self._name = name - self._target_temperature = target_temperature - self._unit_of_measurement = unit_of_measurement - self._away = away - self._current_temperature = current_temperature - self._is_fan_on = is_fan_on - - @property - def should_poll(self): - """No polling needed for a demo thermostat.""" - return False - - @property - def name(self): - """Return the name of the thermostat.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return self._unit_of_measurement - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._current_temperature - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temperature - - @property - def is_away_mode_on(self): - """Return if away mode is on.""" - return self._away - - @property - def is_fan_on(self): - """Return true if the fan is on.""" - return self._is_fan_on - - def set_temperature(self, temperature): - """Set new target temperature.""" - self._target_temperature = temperature - - def turn_away_mode_on(self): - """Turn away mode on.""" - self._away = True - - def turn_away_mode_off(self): - """Turn away mode off.""" - self._away = False - - def turn_fan_on(self): - """Turn fan on.""" - self._is_fan_on = True - - def turn_fan_off(self): - """Turn fan off.""" - self._is_fan_on = False diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py deleted file mode 100644 index 577a33c87f499..0000000000000 --- a/homeassistant/components/thermostat/ecobee.py +++ /dev/null @@ -1,246 +0,0 @@ -""" -Platform for Ecobee Thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.ecobee/ -""" -import logging -from os import path -import voluptuous as vol - -from homeassistant.components import ecobee -from homeassistant.components.thermostat import ( - DOMAIN, STATE_COOL, STATE_HEAT, STATE_IDLE, ThermostatDevice) -from homeassistant.const import ( - ATTR_ENTITY_ID, STATE_OFF, STATE_ON, TEMP_FAHRENHEIT) -from homeassistant.config import load_yaml_config_file -import homeassistant.helpers.config_validation as cv - -DEPENDENCIES = ['ecobee'] -_LOGGER = logging.getLogger(__name__) -ECOBEE_CONFIG_FILE = 'ecobee.conf' -_CONFIGURING = {} - -ATTR_FAN_MIN_ON_TIME = "fan_min_on_time" -SERVICE_SET_FAN_MIN_ON_TIME = "ecobee_set_fan_min_on_time" -SET_FAN_MIN_ON_TIME_SCHEMA = vol.Schema({ - vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, - vol.Required(ATTR_FAN_MIN_ON_TIME): vol.Coerce(int), -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Ecobee Thermostat Platform.""" - if discovery_info is None: - return - data = ecobee.NETWORK - hold_temp = discovery_info['hold_temp'] - _LOGGER.info( - "Loading ecobee thermostat component with hold_temp set to %s", - hold_temp) - devices = [Thermostat(data, index, hold_temp) - for index in range(len(data.ecobee.thermostats))] - add_devices(devices) - - def fan_min_on_time_set_service(service): - """Set the minimum fan on time on the target thermostats.""" - entity_id = service.data.get('entity_id') - - if entity_id: - target_thermostats = [device for device in devices - if device.entity_id == entity_id] - else: - target_thermostats = devices - - fan_min_on_time = service.data[ATTR_FAN_MIN_ON_TIME] - - for thermostat in target_thermostats: - thermostat.set_fan_min_on_time(str(fan_min_on_time)) - - thermostat.update_ha_state(True) - - descriptions = load_yaml_config_file( - path.join(path.dirname(__file__), 'services.yaml')) - - hass.services.register( - DOMAIN, SERVICE_SET_FAN_MIN_ON_TIME, fan_min_on_time_set_service, - descriptions.get(SERVICE_SET_FAN_MIN_ON_TIME), - schema=SET_FAN_MIN_ON_TIME_SCHEMA) - - -# pylint: disable=too-many-public-methods, abstract-method -class Thermostat(ThermostatDevice): - """A thermostat class for Ecobee.""" - - def __init__(self, data, thermostat_index, hold_temp): - """Initialize the thermostat.""" - self.data = data - self.thermostat_index = thermostat_index - self.thermostat = self.data.ecobee.get_thermostat( - self.thermostat_index) - self._name = self.thermostat['name'] - self.hold_temp = hold_temp - - def update(self): - """Get the latest state from the thermostat.""" - self.data.update() - self.thermostat = self.data.ecobee.get_thermostat( - self.thermostat_index) - - @property - def name(self): - """Return the name of the Ecobee Thermostat.""" - return self.thermostat['name'] - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return TEMP_FAHRENHEIT - - @property - def current_temperature(self): - """Return the current temperature.""" - return self.thermostat['runtime']['actualTemperature'] / 10 - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - if self.hvac_mode == 'heat' or self.hvac_mode == 'auxHeatOnly': - return self.target_temperature_low - elif self.hvac_mode == 'cool': - return self.target_temperature_high - else: - return (self.target_temperature_low + - self.target_temperature_high) / 2 - - @property - def target_temperature_low(self): - """Return the lower bound temperature we try to reach.""" - return int(self.thermostat['runtime']['desiredHeat'] / 10) - - @property - def target_temperature_high(self): - """Return the upper bound temperature we try to reach.""" - return int(self.thermostat['runtime']['desiredCool'] / 10) - - @property - def humidity(self): - """Return the current humidity.""" - return self.thermostat['runtime']['actualHumidity'] - - @property - def desired_fan_mode(self): - """Return the desired fan mode of operation.""" - return self.thermostat['runtime']['desiredFanMode'] - - @property - def fan(self): - """Return the current fan state.""" - if 'fan' in self.thermostat['equipmentStatus']: - return STATE_ON - else: - return STATE_OFF - - @property - def operation(self): - """Return current operation ie. heat, cool, idle.""" - status = self.thermostat['equipmentStatus'] - if status == '': - return STATE_IDLE - elif 'Cool' in status: - return STATE_COOL - elif 'auxHeat' in status: - return STATE_HEAT - elif 'heatPump' in status: - return STATE_HEAT - else: - return status - - @property - def mode(self): - """Return current mode ie. home, away, sleep.""" - return self.thermostat['program']['currentClimateRef'] - - @property - def hvac_mode(self): - """Return current hvac mode ie. auto, auxHeatOnly, cool, heat, off.""" - return self.thermostat['settings']['hvacMode'] - - @property - def fan_min_on_time(self): - """Return current fan minimum on time.""" - return self.thermostat['settings']['fanMinOnTime'] - - @property - def device_state_attributes(self): - """Return device specific state attributes.""" - # Move these to Thermostat Device and make them global - return { - "humidity": self.humidity, - "fan": self.fan, - "mode": self.mode, - "hvac_mode": self.hvac_mode, - "fan_min_on_time": self.fan_min_on_time - } - - @property - def is_away_mode_on(self): - """Return true if away mode is on.""" - mode = self.mode - events = self.thermostat['events'] - for event in events: - if event['running']: - mode = event['holdClimateRef'] - break - return 'away' in mode - - def turn_away_mode_on(self): - """Turn away on.""" - if self.hold_temp: - self.data.ecobee.set_climate_hold(self.thermostat_index, - "away", "indefinite") - else: - self.data.ecobee.set_climate_hold(self.thermostat_index, "away") - - def turn_away_mode_off(self): - """Turn away off.""" - self.data.ecobee.resume_program(self.thermostat_index) - - def set_temperature(self, temperature): - """Set new target temperature.""" - temperature = int(temperature) - low_temp = temperature - 1 - high_temp = temperature + 1 - if self.hold_temp: - self.data.ecobee.set_hold_temp(self.thermostat_index, low_temp, - high_temp, "indefinite") - else: - self.data.ecobee.set_hold_temp(self.thermostat_index, low_temp, - high_temp) - - def set_hvac_mode(self, mode): - """Set HVAC mode (auto, auxHeatOnly, cool, heat, off).""" - self.data.ecobee.set_hvac_mode(self.thermostat_index, mode) - - def set_fan_min_on_time(self, fan_min_on_time): - """Set the minimum fan on time.""" - self.data.ecobee.set_fan_min_on_time(self.thermostat_index, - fan_min_on_time) - - # Home and Sleep mode aren't used in UI yet: - - # def turn_home_mode_on(self): - # """ Turns home mode on. """ - # self.data.ecobee.set_climate_hold(self.thermostat_index, "home") - - # def turn_home_mode_off(self): - # """ Turns home mode off. """ - # self.data.ecobee.resume_program(self.thermostat_index) - - # def turn_sleep_mode_on(self): - # """ Turns sleep mode on. """ - # self.data.ecobee.set_climate_hold(self.thermostat_index, "sleep") - - # def turn_sleep_mode_off(self): - # """ Turns sleep mode off. """ - # self.data.ecobee.resume_program(self.thermostat_index) diff --git a/homeassistant/components/thermostat/eq3btsmart.py b/homeassistant/components/thermostat/eq3btsmart.py deleted file mode 100644 index a2aec1b8f6079..0000000000000 --- a/homeassistant/components/thermostat/eq3btsmart.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Support for eq3 Bluetooth Smart thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.eq3btsmart/ -""" -import logging - -from homeassistant.components.thermostat import ThermostatDevice -from homeassistant.const import TEMP_CELSIUS -from homeassistant.util.temperature import convert - -REQUIREMENTS = ['bluepy_devices==0.2.0'] - -CONF_MAC = 'mac' -CONF_DEVICES = 'devices' -CONF_ID = 'id' - -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the eq3 BLE thermostats.""" - devices = [] - - for name, device_cfg in config[CONF_DEVICES].items(): - mac = device_cfg[CONF_MAC] - devices.append(EQ3BTSmartThermostat(mac, name)) - - add_devices(devices) - return True - - -# pylint: disable=too-many-instance-attributes, import-error, abstract-method -class EQ3BTSmartThermostat(ThermostatDevice): - """Representation of a EQ3 Bluetooth Smart thermostat.""" - - def __init__(self, _mac, _name): - """Initialize the thermostat.""" - from bluepy_devices.devices import eq3btsmart - - self._name = _name - - self._thermostat = eq3btsmart.EQ3BTSmartThermostat(_mac) - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement that is used.""" - return TEMP_CELSIUS - - @property - def current_temperature(self): - """Can not report temperature, so return target_temperature.""" - return self.target_temperature - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._thermostat.target_temperature - - def set_temperature(self, temperature): - """Set new target temperature.""" - self._thermostat.target_temperature = temperature - - @property - def device_state_attributes(self): - """Return the device specific state attributes.""" - return {"mode": self._thermostat.mode, - "mode_readable": self._thermostat.mode_readable} - - @property - def min_temp(self): - """Return the minimum temperature.""" - return convert(self._thermostat.min_temp, TEMP_CELSIUS, - self.unit_of_measurement) - - @property - def max_temp(self): - """Return the maximum temperature.""" - return convert(self._thermostat.max_temp, TEMP_CELSIUS, - self.unit_of_measurement) - - def update(self): - """Update the data from the thermostat.""" - self._thermostat.update() diff --git a/homeassistant/components/thermostat/heat_control.py b/homeassistant/components/thermostat/heat_control.py deleted file mode 100644 index faf4059f89191..0000000000000 --- a/homeassistant/components/thermostat/heat_control.py +++ /dev/null @@ -1,215 +0,0 @@ -""" -Adds support for heat control units. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.heat_control/ -""" -import logging -import voluptuous as vol - -import homeassistant.helpers.config_validation as cv -from homeassistant.components import switch -from homeassistant.components.thermostat import ( - STATE_HEAT, STATE_COOL, STATE_IDLE, ThermostatDevice) -from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF -from homeassistant.helpers import condition -from homeassistant.helpers.event import track_state_change - -DEPENDENCIES = ['switch', 'sensor'] - -TOL_TEMP = 0.3 - -CONF_NAME = 'name' -DEFAULT_NAME = 'Heat Control' -CONF_HEATER = 'heater' -CONF_SENSOR = 'target_sensor' -CONF_MIN_TEMP = 'min_temp' -CONF_MAX_TEMP = 'max_temp' -CONF_TARGET_TEMP = 'target_temp' -CONF_AC_MODE = 'ac_mode' -CONF_MIN_DUR = 'min_cycle_duration' - -_LOGGER = logging.getLogger(__name__) - -PLATFORM_SCHEMA = vol.Schema({ - vol.Required("platform"): "heat_control", - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Required(CONF_HEATER): cv.entity_id, - vol.Required(CONF_SENSOR): cv.entity_id, - vol.Optional(CONF_MIN_TEMP): vol.Coerce(float), - vol.Optional(CONF_MAX_TEMP): vol.Coerce(float), - vol.Optional(CONF_TARGET_TEMP): vol.Coerce(float), - vol.Optional(CONF_AC_MODE): vol.Coerce(bool), - vol.Optional(CONF_MIN_DUR): vol.All(cv.time_period, cv.positive_timedelta), -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the heat control thermostat.""" - name = config.get(CONF_NAME) - heater_entity_id = config.get(CONF_HEATER) - sensor_entity_id = config.get(CONF_SENSOR) - min_temp = config.get(CONF_MIN_TEMP) - max_temp = config.get(CONF_MAX_TEMP) - target_temp = config.get(CONF_TARGET_TEMP) - ac_mode = config.get(CONF_AC_MODE) - min_cycle_duration = config.get(CONF_MIN_DUR) - - add_devices([HeatControl(hass, name, heater_entity_id, sensor_entity_id, - min_temp, max_temp, target_temp, ac_mode, - min_cycle_duration)]) - - -# pylint: disable=too-many-instance-attributes, abstract-method -class HeatControl(ThermostatDevice): - """Representation of a HeatControl device.""" - - # pylint: disable=too-many-arguments - def __init__(self, hass, name, heater_entity_id, sensor_entity_id, - min_temp, max_temp, target_temp, ac_mode, min_cycle_duration): - """Initialize the thermostat.""" - self.hass = hass - self._name = name - self.heater_entity_id = heater_entity_id - self.ac_mode = ac_mode - self.min_cycle_duration = min_cycle_duration - - self._active = False - self._cur_temp = None - self._min_temp = min_temp - self._max_temp = max_temp - self._target_temp = target_temp - self._unit = hass.config.units.temperature_unit - - track_state_change(hass, sensor_entity_id, self._sensor_changed) - - sensor_state = hass.states.get(sensor_entity_id) - if sensor_state: - self._update_temp(sensor_state) - - @property - def should_poll(self): - """No polling needed.""" - return False - - @property - def name(self): - """Return the name of the thermostat.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return self._unit - - @property - def current_temperature(self): - """Return the sensor temperature.""" - return self._cur_temp - - @property - def operation(self): - """Return current operation ie. heat, cool, idle.""" - if self.ac_mode: - cooling = self._active and self._is_device_active - return STATE_COOL if cooling else STATE_IDLE - else: - heating = self._active and self._is_device_active - return STATE_HEAT if heating else STATE_IDLE - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temp - - def set_temperature(self, temperature): - """Set new target temperature.""" - self._target_temp = temperature - self._control_heating() - self.update_ha_state() - - @property - def min_temp(self): - """Return the minimum temperature.""" - # pylint: disable=no-member - if self._min_temp: - return self._min_temp - else: - # get default temp from super class - return ThermostatDevice.min_temp.fget(self) - - @property - def max_temp(self): - """Return the maximum temperature.""" - # pylint: disable=no-member - if self._min_temp: - return self._max_temp - else: - # Get default temp from super class - return ThermostatDevice.max_temp.fget(self) - - def _sensor_changed(self, entity_id, old_state, new_state): - """Called when temperature changes.""" - if new_state is None: - return - - self._update_temp(new_state) - self._control_heating() - self.update_ha_state() - - def _update_temp(self, state): - """Update thermostat with latest state from sensor.""" - unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) - - try: - self._cur_temp = self.hass.config.units.temperature( - float(state.state), unit) - except ValueError as ex: - _LOGGER.error('Unable to update from sensor: %s', ex) - - def _control_heating(self): - """Check if we need to turn heating on or off.""" - if not self._active and None not in (self._cur_temp, - self._target_temp): - self._active = True - _LOGGER.info('Obtained current and target temperature. ' - 'Heat control active.') - - if not self._active: - return - - if self.min_cycle_duration: - if self._is_device_active: - current_state = STATE_ON - else: - current_state = STATE_OFF - long_enough = condition.state(self.hass, self.heater_entity_id, - current_state, - self.min_cycle_duration) - if not long_enough: - return - - if self.ac_mode: - too_hot = self._cur_temp - self._target_temp > TOL_TEMP - is_cooling = self._is_device_active - if too_hot and not is_cooling: - _LOGGER.info('Turning on AC %s', self.heater_entity_id) - switch.turn_on(self.hass, self.heater_entity_id) - elif not too_hot and is_cooling: - _LOGGER.info('Turning off AC %s', self.heater_entity_id) - switch.turn_off(self.hass, self.heater_entity_id) - else: - too_cold = self._target_temp - self._cur_temp > TOL_TEMP - is_heating = self._is_device_active - - if too_cold and not is_heating: - _LOGGER.info('Turning on heater %s', self.heater_entity_id) - switch.turn_on(self.hass, self.heater_entity_id) - elif not too_cold and is_heating: - _LOGGER.info('Turning off heater %s', self.heater_entity_id) - switch.turn_off(self.hass, self.heater_entity_id) - - @property - def _is_device_active(self): - """If the toggleable device is currently active.""" - return switch.is_on(self.hass, self.heater_entity_id) diff --git a/homeassistant/components/thermostat/heatmiser.py b/homeassistant/components/thermostat/heatmiser.py deleted file mode 100644 index e7bbfd72f9b4e..0000000000000 --- a/homeassistant/components/thermostat/heatmiser.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -Support for the PRT Heatmiser themostats using the V3 protocol. - -See https://github.com/andylockran/heatmiserV3 for more info on the -heatmiserV3 module dependency. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.heatmiser/ -""" -import logging - -from homeassistant.components.thermostat import ThermostatDevice -from homeassistant.const import TEMP_CELSIUS - -CONF_IPADDRESS = 'ipaddress' -CONF_PORT = 'port' -CONF_TSTATS = 'tstats' - -REQUIREMENTS = ["heatmiserV3==0.9.1"] - -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the heatmiser thermostat.""" - from heatmiserV3 import heatmiser, connection - - ipaddress = str(config[CONF_IPADDRESS]) - port = str(config[CONF_PORT]) - - if ipaddress is None or port is None: - _LOGGER.error("Missing required configuration items %s or %s", - CONF_IPADDRESS, CONF_PORT) - return False - - serport = connection.connection(ipaddress, port) - serport.open() - - tstats = [] - if CONF_TSTATS in config: - tstats = config[CONF_TSTATS] - - if tstats is None: - _LOGGER.error("No thermostats configured.") - return False - - for tstat in tstats: - add_devices([ - HeatmiserV3Thermostat( - heatmiser, - tstat.get("id"), - tstat.get("name"), - serport) - ]) - return - - -class HeatmiserV3Thermostat(ThermostatDevice): - """Representation of a HeatmiserV3 thermostat.""" - - # pylint: disable=too-many-instance-attributes, abstract-method - def __init__(self, heatmiser, device, name, serport): - """Initialize the thermostat.""" - self.heatmiser = heatmiser - self.device = device - self.serport = serport - self._current_temperature = None - self._name = name - self._id = device - self.dcb = None - self.update() - self._target_temperature = int(self.dcb.get("roomset")) - - @property - def name(self): - """Return the name of the thermostat, if any.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement which this thermostat uses.""" - return TEMP_CELSIUS - - @property - def current_temperature(self): - """Return the current temperature.""" - if self.dcb is not None: - low = self.dcb.get("floortemplow ") - high = self.dcb.get("floortemphigh") - temp = (high*256 + low)/10.0 - self._current_temperature = temp - else: - self._current_temperature = None - return self._current_temperature - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temperature - - def set_temperature(self, temperature): - """Set new target temperature.""" - temperature = int(temperature) - self.heatmiser.hmSendAddress( - self._id, - 18, - temperature, - 1, - self.serport) - self._target_temperature = int(temperature) - - def update(self): - """Get the latest data.""" - self.dcb = self.heatmiser.hmReadAddress(self._id, 'prt', self.serport) diff --git a/homeassistant/components/thermostat/honeywell.py b/homeassistant/components/thermostat/honeywell.py deleted file mode 100644 index 31b2e1945b296..0000000000000 --- a/homeassistant/components/thermostat/honeywell.py +++ /dev/null @@ -1,266 +0,0 @@ -""" -Support for Honeywell Round Connected and Honeywell Evohome thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.honeywell/ -""" -import logging -import socket - -from homeassistant.components.thermostat import ThermostatDevice -from homeassistant.const import ( - CONF_PASSWORD, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT) - -REQUIREMENTS = ['evohomeclient==0.2.5', - 'somecomfort==0.3.2'] - -_LOGGER = logging.getLogger(__name__) - -CONF_AWAY_TEMP = "away_temperature" -DEFAULT_AWAY_TEMP = 16 - - -def _setup_round(username, password, config, add_devices): - """Setup rounding function.""" - from evohomeclient import EvohomeClient - - try: - away_temp = float(config.get(CONF_AWAY_TEMP, DEFAULT_AWAY_TEMP)) - except ValueError: - _LOGGER.error("value entered for item %s should convert to a number", - CONF_AWAY_TEMP) - return False - - evo_api = EvohomeClient(username, password) - - try: - zones = evo_api.temperatures(force_refresh=True) - for i, zone in enumerate(zones): - add_devices([RoundThermostat(evo_api, - zone['id'], - i == 0, - away_temp)]) - except socket.error: - _LOGGER.error( - "Connection error logging into the honeywell evohome web service" - ) - return False - return True - - -# config will be used later -def _setup_us(username, password, config, add_devices): - """Setup user.""" - import somecomfort - - try: - client = somecomfort.SomeComfort(username, password) - except somecomfort.AuthError: - _LOGGER.error('Failed to login to honeywell account %s', username) - return False - except somecomfort.SomeComfortError as ex: - _LOGGER.error('Failed to initialize honeywell client: %s', str(ex)) - return False - - dev_id = config.get('thermostat') - loc_id = config.get('location') - - add_devices([HoneywellUSThermostat(client, device) - for location in client.locations_by_id.values() - for device in location.devices_by_id.values() - if ((not loc_id or location.locationid == loc_id) and - (not dev_id or device.deviceid == dev_id))]) - return True - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the honeywel thermostat.""" - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - region = config.get('region', 'eu').lower() - - if username is None or password is None: - _LOGGER.error("Missing required configuration items %s or %s", - CONF_USERNAME, CONF_PASSWORD) - return False - if region not in ('us', 'eu'): - _LOGGER.error('Region `%s` is invalid (use either us or eu)', region) - return False - - if region == 'us': - return _setup_us(username, password, config, add_devices) - else: - return _setup_round(username, password, config, add_devices) - - -class RoundThermostat(ThermostatDevice): - """Representation of a Honeywell Round Connected thermostat.""" - - # pylint: disable=too-many-instance-attributes, abstract-method - def __init__(self, device, zone_id, master, away_temp): - """Initialize the thermostat.""" - self.device = device - self._current_temperature = None - self._target_temperature = None - self._name = "round connected" - self._id = zone_id - self._master = master - self._is_dhw = False - self._away_temp = away_temp - self._away = False - self.update() - - @property - def name(self): - """Return the name of the honeywell, if any.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._current_temperature - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - if self._is_dhw: - return None - return self._target_temperature - - def set_temperature(self, temperature): - """Set new target temperature.""" - self.device.set_temperature(self._name, temperature) - - @property - def operation(self: ThermostatDevice) -> str: - """Get the current operation of the system.""" - return getattr(self.device, 'system_mode', None) - - @property - def is_away_mode_on(self): - """Return true if away mode is on.""" - return self._away - - def set_hvac_mode(self: ThermostatDevice, hvac_mode: str) -> None: - """Set the HVAC mode for the thermostat.""" - if hasattr(self.device, 'system_mode'): - self.device.system_mode = hvac_mode - - def turn_away_mode_on(self): - """Turn away on. - - Evohome does have a proprietary away mode, but it doesn't really work - the way it should. For example: If you set a temperature manually - it doesn't get overwritten when away mode is switched on. - """ - self._away = True - self.device.set_temperature(self._name, self._away_temp) - - def turn_away_mode_off(self): - """Turn away off.""" - self._away = False - self.device.cancel_temp_override(self._name) - - def update(self): - """Get the latest date.""" - try: - # Only refresh if this is the "master" device, - # others will pick up the cache - for val in self.device.temperatures(force_refresh=self._master): - if val['id'] == self._id: - data = val - - except StopIteration: - _LOGGER.error("Did not receive any temperature data from the " - "evohomeclient API.") - return - - self._current_temperature = data['temp'] - self._target_temperature = data['setpoint'] - if data['thermostat'] == "DOMESTIC_HOT_WATER": - self._name = "Hot Water" - self._is_dhw = True - else: - self._name = data['name'] - self._is_dhw = False - - -# pylint: disable=abstract-method -class HoneywellUSThermostat(ThermostatDevice): - """Representation of a Honeywell US Thermostat.""" - - def __init__(self, client, device): - """Initialize the thermostat.""" - self._client = client - self._device = device - - @property - def is_fan_on(self): - """Return true if fan is on.""" - return self._device.fan_running - - @property - def name(self): - """Return the name of the honeywell, if any.""" - return self._device.name - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return (TEMP_CELSIUS if self._device.temperature_unit == 'C' - else TEMP_FAHRENHEIT) - - @property - def current_temperature(self): - """Return the current temperature.""" - self._device.refresh() - return self._device.current_temperature - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - if self._device.system_mode == 'cool': - return self._device.setpoint_cool - else: - return self._device.setpoint_heat - - @property - def operation(self: ThermostatDevice) -> str: - """Return current operation ie. heat, cool, idle.""" - return getattr(self._device, 'system_mode', None) - - def set_temperature(self, temperature): - """Set target temperature.""" - import somecomfort - try: - if self._device.system_mode == 'cool': - self._device.setpoint_cool = temperature - else: - self._device.setpoint_heat = temperature - except somecomfort.SomeComfortError: - _LOGGER.error('Temperature %.1f out of range', temperature) - - @property - def device_state_attributes(self): - """Return the device specific state attributes.""" - return {'fan': (self.is_fan_on and 'running' or 'idle'), - 'fanmode': self._device.fan_mode, - 'system_mode': self._device.system_mode} - - def turn_away_mode_on(self): - """Turn away on.""" - pass - - def turn_away_mode_off(self): - """Turn away off.""" - pass - - def set_hvac_mode(self: ThermostatDevice, hvac_mode: str) -> None: - """Set the system mode (Cool, Heat, etc).""" - if hasattr(self._device, 'system_mode'): - self._device.system_mode = hvac_mode diff --git a/homeassistant/components/thermostat/knx.py b/homeassistant/components/thermostat/knx.py deleted file mode 100644 index af8c2af156ba5..0000000000000 --- a/homeassistant/components/thermostat/knx.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -Support for KNX thermostats. - -For more details about this platform, please refer to the documentation -https://home-assistant.io/components/knx/ -""" -import logging - -from homeassistant.components.thermostat import ThermostatDevice -from homeassistant.const import TEMP_CELSIUS - -from homeassistant.components.knx import ( - KNXConfig, KNXMultiAddressDevice) - -DEPENDENCIES = ["knx"] - -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_entities, discovery_info=None): - """Create and add an entity based on the configuration.""" - add_entities([ - KNXThermostat(hass, KNXConfig(config)) - ]) - - -class KNXThermostat(KNXMultiAddressDevice, ThermostatDevice): - """Representation of a KNX thermostat. - - A KNX thermostat will has the following parameters: - - temperature (current temperature) - - setpoint (target temperature in HASS terms) - - hvac mode selection (comfort/night/frost protection) - - This version supports only polling. Messages from the KNX bus do not - automatically update the state of the thermostat (to be implemented - in future releases) - """ - - def __init__(self, hass, config): - """Initialize the thermostat based on the given configuration.""" - KNXMultiAddressDevice.__init__(self, hass, config, - ["temperature", "setpoint"], - ["mode"]) - - self._unit_of_measurement = TEMP_CELSIUS # KNX always used celsius - self._away = False # not yet supported - self._is_fan_on = False # not yet supported - - @property - def should_poll(self): - """Polling is needed for the KNX thermostat.""" - return True - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return self._unit_of_measurement - - @property - def current_temperature(self): - """Return the current temperature.""" - from knxip.conversion import knx2_to_float - - return knx2_to_float(self.value("temperature")) - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - from knxip.conversion import knx2_to_float - - return knx2_to_float(self.value("setpoint")) - - def set_temperature(self, temperature): - """Set new target temperature.""" - from knxip.conversion import float_to_knx2 - - self.set_value("setpoint", float_to_knx2(temperature)) - _LOGGER.debug("Set target temperature to %s", temperature) - - def set_hvac_mode(self, hvac_mode): - """Set hvac mode.""" - raise NotImplementedError() diff --git a/homeassistant/components/thermostat/nest.py b/homeassistant/components/thermostat/nest.py deleted file mode 100644 index 2e0a8c058883e..0000000000000 --- a/homeassistant/components/thermostat/nest.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Support for Nest thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.nest/ -""" -import voluptuous as vol - -import homeassistant.components.nest as nest -from homeassistant.components.thermostat import ( - STATE_COOL, STATE_HEAT, STATE_IDLE, ThermostatDevice) -from homeassistant.const import TEMP_CELSIUS, CONF_PLATFORM, CONF_SCAN_INTERVAL - -DEPENDENCIES = ['nest'] - -PLATFORM_SCHEMA = vol.Schema({ - vol.Required(CONF_PLATFORM): nest.DOMAIN, - vol.Optional(CONF_SCAN_INTERVAL): - vol.All(vol.Coerce(int), vol.Range(min=1)), -}) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Nest thermostat.""" - add_devices([NestThermostat(structure, device) - for structure, device in nest.devices()]) - - -# pylint: disable=abstract-method -class NestThermostat(ThermostatDevice): - """Representation of a Nest thermostat.""" - - def __init__(self, structure, device): - """Initialize the thermostat.""" - self.structure = structure - self.device = device - - @property - def name(self): - """Return the name of the nest, if any.""" - location = self.device.where - name = self.device.name - if location is None: - return name - else: - if name == '': - return location.capitalize() - else: - return location.capitalize() + '(' + name + ')' - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - - @property - def device_state_attributes(self): - """Return the device specific state attributes.""" - # Move these to Thermostat Device and make them global - return { - "humidity": self.device.humidity, - "target_humidity": self.device.target_humidity, - "mode": self.device.mode - } - - @property - def current_temperature(self): - """Return the current temperature.""" - return self.device.temperature - - @property - def operation(self): - """Return current operation ie. heat, cool, idle.""" - if self.device.hvac_ac_state is True: - return STATE_COOL - elif self.device.hvac_heater_state is True: - return STATE_HEAT - else: - return STATE_IDLE - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - if self.device.mode == 'range': - low, high = self.target_temperature_low, \ - self.target_temperature_high - if self.operation == STATE_COOL: - temp = high - elif self.operation == STATE_HEAT: - temp = low - else: - # If the outside temp is lower than the current temp, consider - # the 'low' temp to the target, otherwise use the high temp - if (self.device.structure.weather.current.temperature < - self.current_temperature): - temp = low - else: - temp = high - else: - if self.is_away_mode_on: - # away_temperature is a low, high tuple. Only one should be set - # if not in range mode, the other will be None - temp = self.device.away_temperature[0] or \ - self.device.away_temperature[1] - else: - temp = self.device.target - - return temp - - @property - def target_temperature_low(self): - """Return the lower bound temperature we try to reach.""" - if self.is_away_mode_on and self.device.away_temperature[0]: - # away_temperature is always a low, high tuple - return self.device.away_temperature[0] - if self.device.mode == 'range': - return self.device.target[0] - return self.target_temperature - - @property - def target_temperature_high(self): - """Return the upper bound temperature we try to reach.""" - if self.is_away_mode_on and self.device.away_temperature[1]: - # away_temperature is always a low, high tuple - return self.device.away_temperature[1] - if self.device.mode == 'range': - return self.device.target[1] - return self.target_temperature - - @property - def is_away_mode_on(self): - """Return if away mode is on.""" - return self.structure.away - - def set_temperature(self, temperature): - """Set new target temperature.""" - if self.device.mode == 'range': - if self.target_temperature == self.target_temperature_low: - temperature = (temperature, self.target_temperature_high) - elif self.target_temperature == self.target_temperature_high: - temperature = (self.target_temperature_low, temperature) - self.device.target = temperature - - def set_hvac_mode(self, hvac_mode): - """Set hvac mode.""" - self.device.mode = hvac_mode - - def turn_away_mode_on(self): - """Turn away on.""" - self.structure.away = True - - def turn_away_mode_off(self): - """Turn away off.""" - self.structure.away = False - - @property - def is_fan_on(self): - """Return whether the fan is on.""" - return self.device.fan - - def turn_fan_on(self): - """Turn fan on.""" - self.device.fan = True - - def turn_fan_off(self): - """Turn fan off.""" - self.device.fan = False - - @property - def min_temp(self): - """Identify min_temp in Nest API or defaults if not available.""" - temp = self.device.away_temperature.low - if temp is None: - return super().min_temp - else: - return temp - - @property - def max_temp(self): - """Identify max_temp in Nest API or defaults if not available.""" - temp = self.device.away_temperature.high - if temp is None: - return super().max_temp - else: - return temp - - def update(self): - """Python-nest has its own mechanism for staying up to date.""" - pass diff --git a/homeassistant/components/thermostat/proliphix.py b/homeassistant/components/thermostat/proliphix.py deleted file mode 100644 index f92407b0d16da..0000000000000 --- a/homeassistant/components/thermostat/proliphix.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Support for Proliphix NT10e Thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.proliphix/ -""" -from homeassistant.components.thermostat import ( - STATE_COOL, STATE_HEAT, STATE_IDLE, ThermostatDevice) -from homeassistant.const import ( - CONF_HOST, CONF_PASSWORD, CONF_USERNAME, TEMP_FAHRENHEIT) - -REQUIREMENTS = ['proliphix==0.4.0'] - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Proliphix thermostats.""" - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - host = config.get(CONF_HOST) - - import proliphix - - pdp = proliphix.PDP(host, username, password) - - add_devices([ - ProliphixThermostat(pdp) - ]) - - -# pylint: disable=abstract-method -class ProliphixThermostat(ThermostatDevice): - """Representation a Proliphix thermostat.""" - - def __init__(self, pdp): - """Initialize the thermostat.""" - self._pdp = pdp - # initial data - self._pdp.update() - self._name = self._pdp.name - - @property - def should_poll(self): - """Polling needed for thermostat.""" - return True - - def update(self): - """Update the data from the thermostat.""" - self._pdp.update() - - @property - def name(self): - """Return the name of the thermostat.""" - return self._name - - @property - def device_state_attributes(self): - """Return the device specific state attributes.""" - return { - "fan": self._pdp.fan_state - } - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return TEMP_FAHRENHEIT - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._pdp.cur_temp - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._pdp.setback - - @property - def operation(self): - """Return the current state of the thermostat.""" - state = self._pdp.hvac_state - if state in (1, 2): - return STATE_IDLE - elif state == 3: - return STATE_HEAT - elif state == 6: - return STATE_COOL - - def set_temperature(self, temperature): - """Set new target temperature.""" - self._pdp.setback = temperature diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py deleted file mode 100644 index c4031fde940b4..0000000000000 --- a/homeassistant/components/thermostat/radiotherm.py +++ /dev/null @@ -1,136 +0,0 @@ -""" -Support for Radio Thermostat wifi-enabled home thermostats. - -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/thermostat.radiotherm/ -""" -import datetime -import logging -from urllib.error import URLError - -from homeassistant.components.thermostat import ( - STATE_AUTO, STATE_COOL, STATE_HEAT, STATE_IDLE, STATE_OFF, - ThermostatDevice) -from homeassistant.const import CONF_HOST, TEMP_FAHRENHEIT - -REQUIREMENTS = ['radiotherm==1.2'] -HOLD_TEMP = 'hold_temp' -_LOGGER = logging.getLogger(__name__) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Radio Thermostat.""" - import radiotherm - - hosts = [] - if CONF_HOST in config: - hosts = config[CONF_HOST] - else: - hosts.append(radiotherm.discover.discover_address()) - - if hosts is None: - _LOGGER.error("No radiotherm thermostats detected.") - return False - - hold_temp = config.get(HOLD_TEMP, False) - tstats = [] - - for host in hosts: - try: - tstat = radiotherm.get_thermostat(host) - tstats.append(RadioThermostat(tstat, hold_temp)) - except (URLError, OSError): - _LOGGER.exception("Unable to connect to Radio Thermostat: %s", - host) - - add_devices(tstats) - - -# pylint: disable=abstract-method -class RadioThermostat(ThermostatDevice): - """Representation of a Radio Thermostat.""" - - def __init__(self, device, hold_temp): - """Initialize the thermostat.""" - self.device = device - self.set_time() - self._target_temperature = None - self._current_temperature = None - self._operation = STATE_IDLE - self._name = None - self.hold_temp = hold_temp - self.update() - - @property - def name(self): - """Return the name of the Radio Thermostat.""" - return self._name - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - return TEMP_FAHRENHEIT - - @property - def device_state_attributes(self): - """Return the device specific state attributes.""" - return { - "fan": self.device.fmode['human'], - "mode": self.device.tmode['human'] - } - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._current_temperature - - @property - def operation(self): - """Return the current operation. head, cool idle.""" - return self._operation - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temperature - - def update(self): - """Update the data from the thermostat.""" - self._current_temperature = self.device.temp['raw'] - self._name = self.device.name['raw'] - if self.device.tmode['human'] == 'Cool': - self._target_temperature = self.device.t_cool['raw'] - self._operation = STATE_COOL - elif self.device.tmode['human'] == 'Heat': - self._target_temperature = self.device.t_heat['raw'] - self._operation = STATE_HEAT - else: - self._operation = STATE_IDLE - - def set_temperature(self, temperature): - """Set new target temperature.""" - if self._operation == STATE_COOL: - self.device.t_cool = temperature - elif self._operation == STATE_HEAT: - self.device.t_heat = temperature - if self.hold_temp: - self.device.hold = 1 - else: - self.device.hold = 0 - - def set_time(self): - """Set device time.""" - now = datetime.datetime.now() - self.device.time = {'day': now.weekday(), - 'hour': now.hour, 'minute': now.minute} - - def set_hvac_mode(self, mode): - """Set HVAC mode (auto, cool, heat, off).""" - if mode == STATE_OFF: - self.device.tmode = 0 - elif mode == STATE_AUTO: - self.device.tmode = 3 - elif mode == STATE_COOL: - self.device.t_cool = self._target_temperature - elif mode == STATE_HEAT: - self.device.t_heat = self._target_temperature diff --git a/homeassistant/components/thermostat/services.yaml b/homeassistant/components/thermostat/services.yaml deleted file mode 100644 index 9ce1ab704e6ab..0000000000000 --- a/homeassistant/components/thermostat/services.yaml +++ /dev/null @@ -1,48 +0,0 @@ - -set_away_mode: - description: Turn away mode on/off for a thermostat - - fields: - entity_id: - description: Name(s) of entities to change - example: 'light.kitchen' - - away_mode: - description: New value of away mode - example: true - -set_temperature: - description: Set temperature of thermostat - - fields: - entity_id: - description: Name(s) of entities to change - example: 'light.kitchen' - - temperature: - description: New target temperature for thermostat - example: 25 - -set_fan_mode: - description: Turn fan on/off for a thermostat - - fields: - entity_id: - description: Name(s) of entities to change - example: 'thermostat.nest' - - fan: - description: New value of fan mode - example: true - -ecobee_set_fan_min_on_time: - description: Set the minimum time, in minutes, to run the fan each hour - - fields: - entity_id: - descriptions: Name(s) of entities to change - example: 'thermostat.ecobee' - - fan_min_on_time: - description: New value of fan minimum on time - example: 5 diff --git a/homeassistant/components/thermostat/zwave.py b/homeassistant/components/thermostat/zwave.py deleted file mode 100644 index de1bd3bc03bd1..0000000000000 --- a/homeassistant/components/thermostat/zwave.py +++ /dev/null @@ -1,168 +0,0 @@ -"""ZWave Thermostat.""" - -# Because we do not compile openzwave on CI -# pylint: disable=import-error -import logging -from homeassistant.components.thermostat import DOMAIN -from homeassistant.components.thermostat import ( - ThermostatDevice, - STATE_IDLE) -from homeassistant.components import zwave -from homeassistant.const import TEMP_FAHRENHEIT, TEMP_CELSIUS - -_LOGGER = logging.getLogger(__name__) - -CONF_NAME = 'name' -DEFAULT_NAME = 'ZWave Thermostat' - -REMOTEC = 0x5254 -REMOTEC_ZXT_120 = 0x8377 -REMOTEC_ZXT_120_THERMOSTAT = (REMOTEC, REMOTEC_ZXT_120) - -WORKAROUND_IGNORE = 'ignore' - -DEVICE_MAPPINGS = { - REMOTEC_ZXT_120_THERMOSTAT: WORKAROUND_IGNORE -} - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the ZWave thermostats.""" - if discovery_info is None or zwave.NETWORK is None: - _LOGGER.debug("No discovery_info=%s or no NETWORK=%s", - discovery_info, zwave.NETWORK) - return - - node = zwave.NETWORK.nodes[discovery_info[zwave.const.ATTR_NODE_ID]] - value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]] - value.set_change_verified(False) - # Make sure that we have values for the key before converting to int - if (value.node.manufacturer_id.strip() and - value.node.product_id.strip()): - specific_sensor_key = (int(value.node.manufacturer_id, 16), - int(value.node.product_id, 16)) - if specific_sensor_key in DEVICE_MAPPINGS: - if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_IGNORE: - _LOGGER.debug("Remotec ZXT-120 Zwave Thermostat, ignoring") - return - if not (value.node.get_values_for_command_class( - zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL) and - value.node.get_values_for_command_class( - zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT)): - return - - if value.command_class != zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL and \ - value.command_class != zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT: - return - - add_devices([ZWaveThermostat(value)]) - _LOGGER.debug("discovery_info=%s and zwave.NETWORK=%s", - discovery_info, zwave.NETWORK) - - -# pylint: disable=too-many-arguments, too-many-instance-attributes -# pylint: disable=abstract-method -class ZWaveThermostat(zwave.ZWaveDeviceEntity, ThermostatDevice): - """Represents a HeatControl thermostat.""" - - def __init__(self, value): - """Initialize the zwave thermostat.""" - from openzwave.network import ZWaveNetwork - from pydispatch import dispatcher - zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN) - self._node = value.node - self._index = value.index - self._current_temperature = None - self._unit = None - self._current_operation_state = STATE_IDLE - self._target_temperature = None - self._current_fan_state = STATE_IDLE - self.update_properties() - # register listener - dispatcher.connect( - self.value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) - - def value_changed(self, value): - """Called when a value has changed on the network.""" - if self._value.value_id == value.value_id or \ - self._value.node == value.node: - self.update_properties() - self.update_ha_state() - - def update_properties(self): - """Callback on data change for the registered node/value pair.""" - # current Temp - for _, value in self._node.get_values_for_command_class( - zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL).items(): - if value.label == 'Temperature': - self._current_temperature = int(value.data) - self._unit = value.units - - # operation state - for _, value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE) - .items()): - self._current_operation_state = value.data_as_string - - # target temperature - temps = [] - for _, value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT) - .items()): - temps.append(int(value.data)) - if value.index == self._index: - self._target_temperature = value.data - self._target_temperature_high = max(temps) - self._target_temperature_low = min(temps) - - # fan state - for _, value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_STATE) - .items()): - self._current_fan_state = value.data_as_string - - @property - def should_poll(self): - """No polling on ZWave.""" - return False - - @property - def unit_of_measurement(self): - """Return the unit of measurement.""" - unit = self._unit - if unit == 'C': - return TEMP_CELSIUS - elif unit == 'F': - return TEMP_FAHRENHEIT - else: - return unit - - @property - def current_temperature(self): - """Return the current temperature.""" - return self._current_temperature - - @property - def operation(self): - """Return current operation ie. heat, cool, idle.""" - return self._current_operation_state - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._target_temperature - - @property - def is_fan_on(self): - """Return true if the fan is on.""" - return not (self._current_fan_state == 'Idle' or - self._current_fan_state == STATE_IDLE) - - def set_temperature(self, temperature): - """Set new target temperature.""" - # set point - for _, value in self._node.get_values_for_command_class( - zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT).items(): - if int(value.data) != 0 and value.index == self._index: - value.data = temperature - break diff --git a/homeassistant/const.py b/homeassistant/const.py index 5c9c8c88b755e..56712b9a04d6d 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -314,11 +314,6 @@ SERVICE_STOP_COVER = 'stop_cover' SERVICE_STOP_COVER_TILT = 'stop_cover_tilt' -SERVICE_MOVE_UP = 'move_up' -SERVICE_MOVE_DOWN = 'move_down' -SERVICE_MOVE_POSITION = 'move_position' -SERVICE_STOP = 'stop' - # #### API / REMOTE #### SERVER_PORT = 8123 diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index c9addefec2bb6..21c353327972b 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -14,25 +14,24 @@ STATE_ABOVE_HORIZON, STATE_BELOW_HORIZON) from homeassistant.components.switch.mysensors import ( ATTR_IR_CODE, SERVICE_SEND_IR_CODE) -from homeassistant.components.thermostat import ( - ATTR_AWAY_MODE, ATTR_FAN, SERVICE_SET_AWAY_MODE, SERVICE_SET_FAN_MODE, +from homeassistant.components.climate import ( + ATTR_AUX_HEAT, ATTR_AWAY_MODE, ATTR_FAN_MODE, ATTR_HUMIDITY, + ATTR_OPERATION_MODE, ATTR_SWING_MODE, + SERVICE_SET_AUX_HEAT, SERVICE_SET_AWAY_MODE, SERVICE_SET_FAN_MODE, + SERVICE_SET_HUMIDITY, SERVICE_SET_OPERATION_MODE, SERVICE_SET_SWING_MODE, SERVICE_SET_TEMPERATURE) -from homeassistant.components.thermostat.ecobee import ( +from homeassistant.components.climate.ecobee import ( ATTR_FAN_MIN_ON_TIME, SERVICE_SET_FAN_MIN_ON_TIME) -from homeassistant.components.hvac import ( - ATTR_HUMIDITY, ATTR_SWING_MODE, ATTR_OPERATION_MODE, ATTR_AUX_HEAT, - SERVICE_SET_HUMIDITY, SERVICE_SET_SWING_MODE, - SERVICE_SET_OPERATION_MODE, SERVICE_SET_AUX_HEAT) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_TEMPERATURE, SERVICE_ALARM_ARM_AWAY, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_DISARM, SERVICE_ALARM_TRIGGER, - SERVICE_CLOSE, SERVICE_LOCK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, - SERVICE_MEDIA_SEEK, SERVICE_MOVE_DOWN, SERVICE_MOVE_UP, SERVICE_OPEN, - SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_UNLOCK, SERVICE_VOLUME_MUTE, - SERVICE_VOLUME_SET, SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, - STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, - STATE_ALARM_TRIGGERED, STATE_CLOSED, STATE_LOCKED, STATE_OFF, STATE_ON, - STATE_OPEN, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_UNLOCKED) + SERVICE_LOCK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, + SERVICE_MEDIA_SEEK, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_UNLOCK, + SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_OPEN_COVER, + SERVICE_CLOSE_COVER, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, + STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, STATE_CLOSED, STATE_LOCKED, + STATE_OFF, STATE_ON, STATE_OPEN, STATE_PAUSED, STATE_PLAYING, + STATE_UNKNOWN, STATE_UNLOCKED) from homeassistant.core import State _LOGGER = logging.getLogger(__name__) @@ -49,7 +48,7 @@ SERVICE_VOLUME_SET: [ATTR_MEDIA_VOLUME_LEVEL], SERVICE_NOTIFY: [ATTR_MESSAGE], SERVICE_SET_AWAY_MODE: [ATTR_AWAY_MODE], - SERVICE_SET_FAN_MODE: [ATTR_FAN], + SERVICE_SET_FAN_MODE: [ATTR_FAN_MODE], SERVICE_SET_FAN_MIN_ON_TIME: [ATTR_FAN_MIN_ON_TIME], SERVICE_SET_TEMPERATURE: [ATTR_TEMPERATURE], SERVICE_SET_HUMIDITY: [ATTR_HUMIDITY], @@ -73,10 +72,6 @@ SERVICE_ALARM_TRIGGER: STATE_ALARM_TRIGGERED, SERVICE_LOCK: STATE_LOCKED, SERVICE_UNLOCK: STATE_UNLOCKED, - SERVICE_CLOSE: STATE_CLOSED, - SERVICE_OPEN: STATE_OPEN, - SERVICE_MOVE_UP: STATE_OPEN, - SERVICE_MOVE_DOWN: STATE_CLOSED, SERVICE_OPEN_COVER: STATE_OPEN, SERVICE_CLOSE_COVER: STATE_CLOSED } diff --git a/requirements_all.txt b/requirements_all.txt index e8d7a67194323..6528b07fb0877 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -55,7 +55,6 @@ blinkstick==1.1.8 blockchain==1.3.3 # homeassistant.components.climate.eq3btsmart -# homeassistant.components.thermostat.eq3btsmart # bluepy_devices==0.2.0 # homeassistant.components.notify.aws_lambda @@ -96,7 +95,6 @@ enocean==0.31 # evdev==0.6.1 # homeassistant.components.climate.honeywell -# homeassistant.components.thermostat.honeywell evohomeclient==0.2.5 # homeassistant.components.sensor.fastdotcom @@ -139,7 +137,6 @@ ha-ffmpeg==0.14 hbmqtt==0.7.1 # homeassistant.components.climate.heatmiser -# homeassistant.components.thermostat.heatmiser heatmiserV3==0.9.1 # homeassistant.components.switch.hikvisioncam @@ -308,7 +305,6 @@ plexapi==2.0.2 pmsensor==0.3 # homeassistant.components.climate.proliphix -# homeassistant.components.thermostat.proliphix proliphix==0.4.0 # homeassistant.components.sensor.systemmonitor @@ -440,7 +436,6 @@ pyvera==0.2.20 pywemo==0.4.7 # homeassistant.components.climate.radiotherm -# homeassistant.components.thermostat.radiotherm radiotherm==1.2 # homeassistant.components.switch.rpi_rf @@ -474,7 +469,6 @@ sleepyq==0.6 snapcast==1.2.2 # homeassistant.components.climate.honeywell -# homeassistant.components.thermostat.honeywell somecomfort==0.3.2 # homeassistant.components.sensor.speedtest diff --git a/tests/components/garage_door/__init__.py b/tests/components/garage_door/__init__.py deleted file mode 100644 index 0523d661222b3..0000000000000 --- a/tests/components/garage_door/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The tests for Garage door platforms.""" diff --git a/tests/components/garage_door/test_demo.py b/tests/components/garage_door/test_demo.py deleted file mode 100644 index e282d697daf69..0000000000000 --- a/tests/components/garage_door/test_demo.py +++ /dev/null @@ -1,50 +0,0 @@ -"""The tests for the Demo Garage door platform.""" -import unittest - -from homeassistant.bootstrap import setup_component -import homeassistant.components.garage_door as gd - -from tests.common import get_test_home_assistant - - -LEFT = 'garage_door.left_garage_door' -RIGHT = 'garage_door.right_garage_door' - - -class TestGarageDoorDemo(unittest.TestCase): - """Test the demo garage door.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.assertTrue(setup_component(self.hass, gd.DOMAIN, { - 'garage_door': { - 'platform': 'demo' - } - })) - - def tearDown(self): # pylint: disable=invalid-name - """Stop everything that was started.""" - self.hass.stop() - - def test_is_closed(self): - """Test if door is closed.""" - self.assertTrue(gd.is_closed(self.hass, LEFT)) - self.hass.states.is_state(LEFT, 'close') - - self.assertFalse(gd.is_closed(self.hass, RIGHT)) - self.hass.states.is_state(RIGHT, 'open') - - def test_open_door(self): - """Test opeing of the door.""" - gd.open_door(self.hass, LEFT) - self.hass.block_till_done() - - self.assertFalse(gd.is_closed(self.hass, LEFT)) - - def test_close_door(self): - """Test closing ot the door.""" - gd.close_door(self.hass, RIGHT) - self.hass.block_till_done() - - self.assertTrue(gd.is_closed(self.hass, RIGHT)) diff --git a/tests/components/garage_door/test_mqtt.py b/tests/components/garage_door/test_mqtt.py deleted file mode 100644 index c46befe6f1bed..0000000000000 --- a/tests/components/garage_door/test_mqtt.py +++ /dev/null @@ -1,138 +0,0 @@ -"""The tests for the MQTT Garge door platform.""" -import unittest - -from homeassistant.bootstrap import setup_component -from homeassistant.const import STATE_OPEN, STATE_CLOSED, ATTR_ASSUMED_STATE - -import homeassistant.components.garage_door as garage_door -from tests.common import ( - mock_mqtt_component, fire_mqtt_message, get_test_home_assistant, - assert_setup_component) - - -class TestGarageDoorMQTT(unittest.TestCase): - """Test the MQTT Garage door.""" - - # pylint: disable=invalid-name - - def setUp(self): - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.mock_publish = mock_mqtt_component(self.hass) - - def tearDown(self): # pylint: disable=invalid-name - """"Stop everything that was started.""" - self.hass.stop() - - def test_fail_setup_if_no_command_topic(self): - """Test if command fails with command topic.""" - self.hass.config.components = ['mqtt'] - with assert_setup_component(0): - assert setup_component(self.hass, garage_door.DOMAIN, { - garage_door.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': '/home/garage_door/door' - } - }) - self.assertIsNone(self.hass.states.get('garage_door.test')) - - def test_controlling_state_via_topic(self): - """Test the controlling state via topic.""" - with assert_setup_component(1): - assert setup_component(self.hass, garage_door.DOMAIN, { - garage_door.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'state_open': 1, - 'state_closed': 0, - 'service_open': 1, - 'service_close': 0 - } - }) - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_CLOSED, state.state) - self.assertIsNone(state.attributes.get(ATTR_ASSUMED_STATE)) - - fire_mqtt_message(self.hass, 'state-topic', '1') - self.hass.block_till_done() - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_OPEN, state.state) - - fire_mqtt_message(self.hass, 'state-topic', '0') - self.hass.block_till_done() - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_CLOSED, state.state) - - def test_sending_mqtt_commands_and_optimistic(self): - """Test the sending MQTT commands in optimistic mode.""" - with assert_setup_component(1): - assert setup_component(self.hass, garage_door.DOMAIN, { - garage_door.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'command_topic': 'command-topic', - 'state_open': 'beer state open', - 'state_closed': 'beer state closed', - 'service_open': 'beer open', - 'service_close': 'beer close', - 'qos': '2' - } - }) - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_CLOSED, state.state) - self.assertTrue(state.attributes.get(ATTR_ASSUMED_STATE)) - - garage_door.open_door(self.hass, 'garage_door.test') - self.hass.block_till_done() - - self.assertEqual(('command-topic', 'beer open', 2, False), - self.mock_publish.mock_calls[-1][1]) - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_OPEN, state.state) - - garage_door.close_door(self.hass, 'garage_door.test') - self.hass.block_till_done() - - self.assertEqual(('command-topic', 'beer close', 2, False), - self.mock_publish.mock_calls[-1][1]) - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_CLOSED, state.state) - - def test_controlling_state_via_topic_and_json_message(self): - """Test the controlling state via topic and JSON message.""" - with assert_setup_component(1): - assert setup_component(self.hass, garage_door.DOMAIN, { - garage_door.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'state_open': 'beer open', - 'state_closed': 'beer closed', - 'service_open': 'beer service open', - 'service_close': 'beer service close', - 'value_template': '{{ value_json.val }}' - } - }) - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_CLOSED, state.state) - - fire_mqtt_message(self.hass, 'state-topic', '{"val":"beer open"}') - self.hass.block_till_done() - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_OPEN, state.state) - - fire_mqtt_message(self.hass, 'state-topic', '{"val":"beer closed"}') - self.hass.block_till_done() - - state = self.hass.states.get('garage_door.test') - self.assertEqual(STATE_CLOSED, state.state) diff --git a/tests/components/hvac/__init__.py b/tests/components/hvac/__init__.py deleted file mode 100644 index 6a5696cfb629b..0000000000000 --- a/tests/components/hvac/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The tests for hvac component.""" diff --git a/tests/components/hvac/test_demo.py b/tests/components/hvac/test_demo.py deleted file mode 100644 index b033b89f17314..0000000000000 --- a/tests/components/hvac/test_demo.py +++ /dev/null @@ -1,167 +0,0 @@ -"""The tests for the demo hvac.""" -import unittest - -from homeassistant.bootstrap import setup_component -from homeassistant.components import hvac -from homeassistant.util.unit_system import ( - METRIC_SYSTEM, -) - -from tests.common import get_test_home_assistant - - -ENTITY_HVAC = 'hvac.hvac' - - -class TestDemoHvac(unittest.TestCase): - """Test the demo hvac.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.units = METRIC_SYSTEM - self.assertTrue(setup_component(self.hass, hvac.DOMAIN, {'hvac': { - 'platform': 'demo', - }})) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_setup_params(self): - """Test the inititial parameters.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual(21, state.attributes.get('temperature')) - self.assertEqual('on', state.attributes.get('away_mode')) - self.assertEqual(22, state.attributes.get('current_temperature')) - self.assertEqual("On High", state.attributes.get('fan_mode')) - self.assertEqual(67, state.attributes.get('humidity')) - self.assertEqual(54, state.attributes.get('current_humidity')) - self.assertEqual("Off", state.attributes.get('swing_mode')) - self.assertEqual("Cool", state.attributes.get('operation_mode')) - self.assertEqual('off', state.attributes.get('aux_heat')) - - def test_default_setup_params(self): - """Test the setup with default parameters.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual(19, state.attributes.get('min_temp')) - self.assertEqual(30, state.attributes.get('max_temp')) - self.assertEqual(30, state.attributes.get('min_humidity')) - self.assertEqual(99, state.attributes.get('max_humidity')) - - def test_set_target_temp_bad_attr(self): - """Test setting the target temperature without required attribute.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual(21, state.attributes.get('temperature')) - hvac.set_temperature(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual(21, state.attributes.get('temperature')) - - def test_set_target_temp(self): - """Test the setting of the target temperature.""" - hvac.set_temperature(self.hass, 30, ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual(30.0, state.attributes.get('temperature')) - - def test_set_target_humidity_bad_attr(self): - """Test setting the target humidity without required attribute.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual(67, state.attributes.get('humidity')) - hvac.set_humidity(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual(67, state.attributes.get('humidity')) - - def test_set_target_humidity(self): - """Test the setting of the target humidity.""" - hvac.set_humidity(self.hass, 64, ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual(64.0, state.attributes.get('humidity')) - - def test_set_fan_mode_bad_attr(self): - """Test setting fan mode without required attribute.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual("On High", state.attributes.get('fan_mode')) - hvac.set_fan_mode(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual("On High", state.attributes.get('fan_mode')) - - def test_set_fan_mode(self): - """Test setting of new fan mode.""" - hvac.set_fan_mode(self.hass, "On Low", ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual("On Low", state.attributes.get('fan_mode')) - - def test_set_swing_mode_bad_attr(self): - """Test setting swing mode without required attribute.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual("Off", state.attributes.get('swing_mode')) - hvac.set_swing_mode(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual("Off", state.attributes.get('swing_mode')) - - def test_set_swing(self): - """Test setting of new swing mode.""" - hvac.set_swing_mode(self.hass, "Auto", ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual("Auto", state.attributes.get('swing_mode')) - - def test_set_operation_bad_attr(self): - """Test setting operation mode without required attribute.""" - self.assertEqual("Cool", self.hass.states.get(ENTITY_HVAC).state) - hvac.set_operation_mode(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual("Cool", self.hass.states.get(ENTITY_HVAC).state) - - def test_set_operation(self): - """Test setting of new operation mode.""" - hvac.set_operation_mode(self.hass, "Heat", ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual("Heat", self.hass.states.get(ENTITY_HVAC).state) - - def test_set_away_mode_bad_attr(self): - """Test setting the away mode without required attribute.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual('on', state.attributes.get('away_mode')) - hvac.set_away_mode(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual('on', state.attributes.get('away_mode')) - - def test_set_away_mode_on(self): - """Test setting the away mode on/true.""" - hvac.set_away_mode(self.hass, True, ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual('on', state.attributes.get('away_mode')) - - def test_set_away_mode_off(self): - """Test setting the away mode off/false.""" - hvac.set_away_mode(self.hass, False, ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual('off', state.attributes.get('away_mode')) - - def test_set_aux_heat_bad_attr(self): - """Test setting the auxillary heater without required attribute.""" - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual('off', state.attributes.get('aux_heat')) - hvac.set_aux_heat(self.hass, None, ENTITY_HVAC) - self.hass.block_till_done() - self.assertEqual('off', state.attributes.get('aux_heat')) - - def test_set_aux_heat_on(self): - """Test setting the axillary heater on/true.""" - hvac.set_aux_heat(self.hass, True, ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual('on', state.attributes.get('aux_heat')) - - def test_set_aux_heat_off(self): - """Test setting the auxillary heater off/false.""" - hvac.set_aux_heat(self.hass, False, ENTITY_HVAC) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_HVAC) - self.assertEqual('off', state.attributes.get('aux_heat')) diff --git a/tests/components/rollershutter/__init__.py b/tests/components/rollershutter/__init__.py deleted file mode 100644 index 4fc6ddee8a9e6..0000000000000 --- a/tests/components/rollershutter/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The tests for Roller shutter platforms.""" diff --git a/tests/components/rollershutter/test_command_line.py b/tests/components/rollershutter/test_command_line.py deleted file mode 100644 index d8b5110578cf7..0000000000000 --- a/tests/components/rollershutter/test_command_line.py +++ /dev/null @@ -1,88 +0,0 @@ -"""The tests the Roller shutter command line platform.""" - -import os -import tempfile -import unittest -from unittest import mock - -from homeassistant.bootstrap import setup_component -import homeassistant.components.rollershutter as rollershutter -from homeassistant.components.rollershutter import ( - command_line as cmd_rs) -from tests.common import get_test_home_assistant - - -class TestCommandRollerShutter(unittest.TestCase): - """Test the Roller shutter command line platform.""" - - def setup_method(self, method): - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.latitude = 32.87336 - self.hass.config.longitude = 117.22743 - self.rs = cmd_rs.CommandRollershutter(self.hass, 'foo', - 'cmd_up', 'cmd_dn', - 'cmd_stop', 'cmd_state', - None) # FIXME - - def teardown_method(self, method): - """Stop down everything that was started.""" - self.hass.stop() - - def test_should_poll(self): - """Test the setting of polling.""" - self.assertTrue(self.rs.should_poll) - self.rs._command_state = None - self.assertFalse(self.rs.should_poll) - - def test_query_state_value(self): - """Test with state value.""" - with mock.patch('subprocess.check_output') as mock_run: - mock_run.return_value = b' foo bar ' - result = self.rs._query_state_value('runme') - self.assertEqual('foo bar', result) - self.assertEqual(mock_run.call_count, 1) - self.assertEqual( - mock_run.call_args, mock.call('runme', shell=True) - ) - - def test_state_value(self): - """Test with state value.""" - with tempfile.TemporaryDirectory() as tempdirname: - path = os.path.join(tempdirname, 'rollershutter_status') - test_rollershutter = { - 'statecmd': 'cat {}'.format(path), - 'upcmd': 'echo 1 > {}'.format(path), - 'downcmd': 'echo 1 > {}'.format(path), - 'stopcmd': 'echo 0 > {}'.format(path), - 'value_template': '{{ value }}' - } - self.assertTrue(setup_component(self.hass, rollershutter.DOMAIN, { - 'rollershutter': { - 'platform': 'command_line', - 'rollershutters': { - 'test': test_rollershutter - } - } - })) - - state = self.hass.states.get('rollershutter.test') - self.assertEqual('unknown', state.state) - - rollershutter.move_up(self.hass, 'rollershutter.test') - self.hass.block_till_done() - - state = self.hass.states.get('rollershutter.test') - self.assertEqual('open', state.state) - - rollershutter.move_down(self.hass, 'rollershutter.test') - self.hass.block_till_done() - - state = self.hass.states.get('rollershutter.test') - self.assertEqual('open', state.state) - - rollershutter.stop(self.hass, 'rollershutter.test') - self.hass.block_till_done() - - state = self.hass.states.get('rollershutter.test') - self.assertEqual('closed', state.state) diff --git a/tests/components/rollershutter/test_demo.py b/tests/components/rollershutter/test_demo.py deleted file mode 100644 index 4740845adcc00..0000000000000 --- a/tests/components/rollershutter/test_demo.py +++ /dev/null @@ -1,55 +0,0 @@ -"""The tests for the Demo roller shutter platform.""" -import unittest -import homeassistant.util.dt as dt_util - -from homeassistant.components.rollershutter import demo -from tests.common import fire_time_changed, get_test_home_assistant - - -class TestRollershutterDemo(unittest.TestCase): - """Test the Demo roller shutter.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_move_up(self): - """Test moving the rollershutter up.""" - entity = demo.DemoRollershutter(self.hass, 'test', 100) - entity.move_up() - - fire_time_changed(self.hass, dt_util.utcnow()) - self.hass.block_till_done() - self.assertEqual(90, entity.current_position) - - def test_move_down(self): - """Test moving the rollershutter down.""" - entity = demo.DemoRollershutter(self.hass, 'test', 0) - entity.move_down() - - fire_time_changed(self.hass, dt_util.utcnow()) - self.hass.block_till_done() - self.assertEqual(10, entity.current_position) - - def test_move_position(self): - """Test moving the rollershutter to a specific position.""" - entity = demo.DemoRollershutter(self.hass, 'test', 0) - entity.move_position(10) - - fire_time_changed(self.hass, dt_util.utcnow()) - self.hass.block_till_done() - self.assertEqual(10, entity.current_position) - - def test_stop(self): - """Test stopping the rollershutter.""" - entity = demo.DemoRollershutter(self.hass, 'test', 0) - entity.move_down() - entity.stop() - - fire_time_changed(self.hass, dt_util.utcnow()) - self.hass.block_till_done() - self.assertEqual(0, entity.current_position) diff --git a/tests/components/rollershutter/test_mqtt.py b/tests/components/rollershutter/test_mqtt.py deleted file mode 100644 index eaff07d061b96..0000000000000 --- a/tests/components/rollershutter/test_mqtt.py +++ /dev/null @@ -1,174 +0,0 @@ -"""The tests for the MQTT roller shutter platform.""" -import unittest - -from homeassistant.bootstrap import _setup_component -from homeassistant.const import STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN -import homeassistant.components.rollershutter as rollershutter -from tests.common import mock_mqtt_component, fire_mqtt_message - -from tests.common import get_test_home_assistant - - -class TestRollershutterMQTT(unittest.TestCase): - """Test the MQTT roller shutter.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.mock_publish = mock_mqtt_component(self.hass) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_controlling_state_via_topic(self): - """Test the controlling state via topic.""" - self.hass.config.components = ['mqtt'] - assert _setup_component(self.hass, rollershutter.DOMAIN, { - rollershutter.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'qos': 0, - 'payload_up': 'UP', - 'payload_down': 'DOWN', - 'payload_stop': 'STOP' - } - }) - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - fire_mqtt_message(self.hass, 'state-topic', '0') - self.hass.block_till_done() - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_CLOSED, state.state) - - fire_mqtt_message(self.hass, 'state-topic', '50') - self.hass.block_till_done() - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_OPEN, state.state) - - fire_mqtt_message(self.hass, 'state-topic', '100') - self.hass.block_till_done() - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_OPEN, state.state) - - def test_send_move_up_command(self): - """Test the sending of move_up.""" - self.hass.config.components = ['mqtt'] - assert _setup_component(self.hass, rollershutter.DOMAIN, { - rollershutter.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'qos': 2 - } - }) - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - rollershutter.move_up(self.hass, 'rollershutter.test') - self.hass.block_till_done() - - self.assertEqual(('command-topic', 'UP', 2, False), - self.mock_publish.mock_calls[-1][1]) - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - def test_send_move_down_command(self): - """Test the sending of move_down.""" - self.hass.config.components = ['mqtt'] - assert _setup_component(self.hass, rollershutter.DOMAIN, { - rollershutter.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'qos': 2 - } - }) - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - rollershutter.move_down(self.hass, 'rollershutter.test') - self.hass.block_till_done() - - self.assertEqual(('command-topic', 'DOWN', 2, False), - self.mock_publish.mock_calls[-1][1]) - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - def test_send_stop_command(self): - """Test the sending of stop.""" - self.hass.config.components = ['mqtt'] - assert _setup_component(self.hass, rollershutter.DOMAIN, { - rollershutter.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'qos': 2 - } - }) - - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - rollershutter.stop(self.hass, 'rollershutter.test') - self.hass.block_till_done() - - self.assertEqual(('command-topic', 'STOP', 2, False), - self.mock_publish.mock_calls[-1][1]) - state = self.hass.states.get('rollershutter.test') - self.assertEqual(STATE_UNKNOWN, state.state) - - def test_state_attributes_current_position(self): - """Test the current position.""" - self.hass.config.components = ['mqtt'] - assert _setup_component(self.hass, rollershutter.DOMAIN, { - rollershutter.DOMAIN: { - 'platform': 'mqtt', - 'name': 'test', - 'state_topic': 'state-topic', - 'command_topic': 'command-topic', - 'payload_up': 'UP', - 'payload_down': 'DOWN', - 'payload_stop': 'STOP' - } - }) - - state_attributes_dict = self.hass.states.get( - 'rollershutter.test').attributes - self.assertFalse('current_position' in state_attributes_dict) - - fire_mqtt_message(self.hass, 'state-topic', '0') - self.hass.block_till_done() - current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] - self.assertEqual(0, current_position) - - fire_mqtt_message(self.hass, 'state-topic', '50') - self.hass.block_till_done() - current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] - self.assertEqual(50, current_position) - - fire_mqtt_message(self.hass, 'state-topic', '101') - self.hass.block_till_done() - current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] - self.assertEqual(50, current_position) - - fire_mqtt_message(self.hass, 'state-topic', 'non-numeric') - self.hass.block_till_done() - current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] - self.assertEqual(50, current_position) diff --git a/tests/components/rollershutter/test_rfxtrx.py b/tests/components/rollershutter/test_rfxtrx.py deleted file mode 100644 index e16f841c3fef5..0000000000000 --- a/tests/components/rollershutter/test_rfxtrx.py +++ /dev/null @@ -1,219 +0,0 @@ -"""The tests for the Rfxtrx roller shutter platform.""" -import unittest - -import pytest - -from homeassistant.bootstrap import _setup_component -from homeassistant.components import rfxtrx as rfxtrx_core - -from tests.common import get_test_home_assistant - - -@pytest.mark.skipif("os.environ.get('RFXTRX') != 'RUN'") -class TestRollershutterRfxtrx(unittest.TestCase): - """Test the Rfxtrx roller shutter platform.""" - - def setUp(self): - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant(0) - self.hass.config.components = ['rfxtrx'] - - def tearDown(self): - """Stop everything that was started.""" - rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS = [] - rfxtrx_core.RFX_DEVICES = {} - if rfxtrx_core.RFXOBJECT: - rfxtrx_core.RFXOBJECT.close_connection() - self.hass.stop() - - def test_valid_config(self): - """Test configuration.""" - self.assertTrue(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': True, - 'devices': - {'0b1100cd0213c7f210010f51': { - 'name': 'Test', - rfxtrx_core.ATTR_FIREEVENT: True} - }}})) - - def test_invalid_config1(self): - """Test configuration.""" - self.assertFalse(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': True, - 'devices': - {'2FF7f216': { - 'name': 'Test', - 'packetid': '0b1100cd0213c7f210010f51', - 'signal_repetitions': 3} - }}})) - - def test_invalid_config2(self): - """Test configuration.""" - self.assertFalse(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': True, - 'invalid_key': 'afda', - 'devices': - {'213c7f216': { - 'name': 'Test', - 'packetid': '0b1100cd0213c7f210010f51', - rfxtrx_core.ATTR_FIREEVENT: True} - }}})) - - def test_invalid_config3(self): - """Test configuration.""" - self.assertFalse(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': True, - 'devices': - {'213c7f216': { - 'name': 'Test', - 'packetid': 'AA1100cd0213c7f210010f51', - rfxtrx_core.ATTR_FIREEVENT: True} - }}})) - - def test_invalid_config4(self): - """Test configuration.""" - self.assertFalse(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': True, - 'devices': - {'213c7f216': { - 'name': 'Test', - rfxtrx_core.ATTR_FIREEVENT: True} - }}})) - - def test_default_config(self): - """Test with 0 roller shutter.""" - self.assertTrue(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'devices': {}}})) - self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) - - def test_one_rollershutter(self): - """Test with 1 roller shutter.""" - self.assertTrue(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'devices': - {'0b1400cd0213c7f210010f51': { - 'name': 'Test' - }}}})) - - import RFXtrx as rfxtrxmod - rfxtrx_core.RFXOBJECT =\ - rfxtrxmod.Core("", transport_protocol=rfxtrxmod.DummyTransport) - - self.assertEqual(1, len(rfxtrx_core.RFX_DEVICES)) - for id in rfxtrx_core.RFX_DEVICES: - entity = rfxtrx_core.RFX_DEVICES[id] - self.assertEqual(entity.signal_repetitions, 1) - self.assertFalse(entity.should_fire_event) - self.assertFalse(entity.should_poll) - entity.move_up() - entity.move_down() - entity.stop() - - def test_several_rollershutters(self): - """Test with 3 roller shutters.""" - self.assertTrue(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'signal_repetitions': 3, - 'devices': - {'0b1100cd0213c7f230010f71': { - 'name': 'Test'}, - '0b1100100118cdea02010f70': { - 'name': 'Bath'}, - '0b1100101118cdea02010f70': { - 'name': 'Living'} - }}})) - - self.assertEqual(3, len(rfxtrx_core.RFX_DEVICES)) - device_num = 0 - for id in rfxtrx_core.RFX_DEVICES: - entity = rfxtrx_core.RFX_DEVICES[id] - self.assertEqual(entity.signal_repetitions, 3) - if entity.name == 'Living': - device_num = device_num + 1 - elif entity.name == 'Bath': - device_num = device_num + 1 - elif entity.name == 'Test': - device_num = device_num + 1 - - self.assertEqual(3, device_num) - - def test_discover_rollershutter(self): - """Test with discovery of roller shutters.""" - self.assertTrue(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': True, - 'devices': {}}})) - - event = rfxtrx_core.get_rfx_object('0a140002f38cae010f0070') - event.data = bytearray([0x0A, 0x14, 0x00, 0x02, 0xF3, 0x8C, - 0xAE, 0x01, 0x0F, 0x00, 0x70]) - - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(1, len(rfxtrx_core.RFX_DEVICES)) - - event = rfxtrx_core.get_rfx_object('0a1400adf394ab020e0060') - event.data = bytearray([0x0A, 0x14, 0x00, 0xAD, 0xF3, 0x94, - 0xAB, 0x02, 0x0E, 0x00, 0x60]) - - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(2, len(rfxtrx_core.RFX_DEVICES)) - - # Trying to add a sensor - event = rfxtrx_core.get_rfx_object('0a52085e070100b31b0279') - event.data = bytearray(b'\nR\x08^\x07\x01\x00\xb3\x1b\x02y') - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(2, len(rfxtrx_core.RFX_DEVICES)) - - # Trying to add a light - event = rfxtrx_core.get_rfx_object('0b1100100118cdea02010f70') - event.data = bytearray([0x0b, 0x11, 0x11, 0x10, 0x01, 0x18, - 0xcd, 0xea, 0x01, 0x02, 0x0f, 0x70]) - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(2, len(rfxtrx_core.RFX_DEVICES)) - - def test_discover_rollershutter_noautoadd(self): - """Test with discovery of roller shutter when auto add is False.""" - self.assertTrue(_setup_component(self.hass, 'rollershutter', { - 'rollershutter': {'platform': 'rfxtrx', - 'automatic_add': False, - 'devices': {}}})) - - event = rfxtrx_core.get_rfx_object('0a1400adf394ab010d0060') - event.data = bytearray([0x0A, 0x14, 0x00, 0xAD, 0xF3, 0x94, - 0xAB, 0x01, 0x0D, 0x00, 0x60]) - - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) - - event = rfxtrx_core.get_rfx_object('0a1400adf394ab020e0060') - event.data = bytearray([0x0A, 0x14, 0x00, 0xAD, 0xF3, 0x94, - 0xAB, 0x02, 0x0E, 0x00, 0x60]) - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) - - # Trying to add a sensor - event = rfxtrx_core.get_rfx_object('0a52085e070100b31b0279') - event.data = bytearray(b'\nR\x08^\x07\x01\x00\xb3\x1b\x02y') - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) - - # Trying to add a light - event = rfxtrx_core.get_rfx_object('0b1100100118cdea02010f70') - event.data = bytearray([0x0b, 0x11, 0x11, 0x10, 0x01, - 0x18, 0xcd, 0xea, 0x01, 0x02, 0x0f, 0x70]) - for evt_sub in rfxtrx_core.RECEIVED_EVT_SUBSCRIBERS: - evt_sub(event) - self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) diff --git a/tests/components/thermostat/__init__.py b/tests/components/thermostat/__init__.py deleted file mode 100644 index 9a15198ecb45a..0000000000000 --- a/tests/components/thermostat/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The tests for Thermostat platforms.""" diff --git a/tests/components/thermostat/test_demo.py b/tests/components/thermostat/test_demo.py deleted file mode 100644 index 2d564e971037f..0000000000000 --- a/tests/components/thermostat/test_demo.py +++ /dev/null @@ -1,101 +0,0 @@ -"""The tests for the demo thermostat.""" -import unittest - -from homeassistant.util.unit_system import ( - METRIC_SYSTEM, -) -from homeassistant.components import thermostat - -from tests.common import get_test_home_assistant - - -ENTITY_NEST = 'thermostat.nest' - - -class TestDemoThermostat(unittest.TestCase): - """Test the Heat Control thermostat.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.units = METRIC_SYSTEM - self.assertTrue(thermostat.setup(self.hass, {'thermostat': { - 'platform': 'demo', - }})) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_setup_params(self): - """Test the inititial parameters.""" - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual(21, state.attributes.get('temperature')) - self.assertEqual('off', state.attributes.get('away_mode')) - self.assertEqual(19, state.attributes.get('current_temperature')) - self.assertEqual('off', state.attributes.get('fan')) - - def test_default_setup_params(self): - """Test the setup with default parameters.""" - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual(7, state.attributes.get('min_temp')) - self.assertEqual(35, state.attributes.get('max_temp')) - - def test_set_target_temp_bad_attr(self): - """Test setting the target temperature without required attribute.""" - self.assertEqual('21.0', self.hass.states.get(ENTITY_NEST).state) - thermostat.set_temperature(self.hass, None, ENTITY_NEST) - self.hass.block_till_done() - self.assertEqual('21.0', self.hass.states.get(ENTITY_NEST).state) - - def test_set_target_temp(self): - """Test the setting of the target temperature.""" - thermostat.set_temperature(self.hass, 30, ENTITY_NEST) - self.hass.block_till_done() - self.assertEqual('30.0', self.hass.states.get(ENTITY_NEST).state) - - def test_set_away_mode_bad_attr(self): - """Test setting the away mode without required attribute.""" - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('off', state.attributes.get('away_mode')) - thermostat.set_away_mode(self.hass, None, ENTITY_NEST) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('off', state.attributes.get('away_mode')) - - def test_set_away_mode_on(self): - """Test setting the away mode on/true.""" - thermostat.set_away_mode(self.hass, True, ENTITY_NEST) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('on', state.attributes.get('away_mode')) - - def test_set_away_mode_off(self): - """Test setting the away mode off/false.""" - thermostat.set_away_mode(self.hass, False, ENTITY_NEST) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('off', state.attributes.get('away_mode')) - - def test_set_fan_mode_on_bad_attr(self): - """Test setting the fan mode on/true without required attribute.""" - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('off', state.attributes.get('fan')) - thermostat.set_fan_mode(self.hass, None, ENTITY_NEST) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('off', state.attributes.get('fan')) - - def test_set_fan_mode_on(self): - """Test setting the fan mode on/true.""" - thermostat.set_fan_mode(self.hass, True, ENTITY_NEST) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('on', state.attributes.get('fan')) - - def test_set_fan_mode_off(self): - """Test setting the fan mode off/false.""" - thermostat.set_fan_mode(self.hass, False, ENTITY_NEST) - self.hass.block_till_done() - state = self.hass.states.get(ENTITY_NEST) - self.assertEqual('off', state.attributes.get('fan')) diff --git a/tests/components/thermostat/test_heat_control.py b/tests/components/thermostat/test_heat_control.py deleted file mode 100644 index 300bfd6cc4a67..0000000000000 --- a/tests/components/thermostat/test_heat_control.py +++ /dev/null @@ -1,494 +0,0 @@ -"""The tests for the heat control thermostat.""" -import datetime -import unittest -from unittest import mock - - -from homeassistant.bootstrap import setup_component -from homeassistant.const import ( - ATTR_UNIT_OF_MEASUREMENT, - SERVICE_TURN_OFF, - SERVICE_TURN_ON, - STATE_ON, - STATE_OFF, - TEMP_CELSIUS, -) -from homeassistant.util.unit_system import METRIC_SYSTEM -from homeassistant.components import thermostat - -from tests.common import assert_setup_component, get_test_home_assistant - - -ENTITY = 'thermostat.test' -ENT_SENSOR = 'sensor.test' -ENT_SWITCH = 'switch.test' -MIN_TEMP = 3.0 -MAX_TEMP = 65.0 -TARGET_TEMP = 42.0 - - -class TestSetupThermostatHeatControl(unittest.TestCase): - """Test the Heat Control thermostat with custom config.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_setup_missing_conf(self): - """Test set up heat_control with missing config values.""" - config = { - 'name': 'test', - 'target_sensor': ENT_SENSOR - } - with assert_setup_component(0): - setup_component(self.hass, 'thermostat', { - 'thermostat': config}) - - def test_valid_conf(self): - """Test set up heat_control with valid config values.""" - self.assertTrue(setup_component(self.hass, 'thermostat', - {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR}})) - - def test_setup_with_sensor(self): - """Test set up heat_control with sensor to trigger update at init.""" - self.hass.states.set(ENT_SENSOR, 22.0, { - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS - }) - thermostat.setup(self.hass, {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR - }}) - state = self.hass.states.get(ENTITY) - self.assertEqual( - TEMP_CELSIUS, state.attributes.get('unit_of_measurement')) - self.assertEqual(22.0, state.attributes.get('current_temperature')) - - -class TestThermostatHeatControl(unittest.TestCase): - """Test the Heat Control thermostat.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.units = METRIC_SYSTEM - thermostat.setup(self.hass, {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR - }}) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_setup_defaults_to_unknown(self): - """Test the setting of defaults to unknown.""" - self.assertEqual('unknown', self.hass.states.get(ENTITY).state) - - def test_default_setup_params(self): - """Test the setup with default parameters.""" - state = self.hass.states.get(ENTITY) - self.assertEqual(7, state.attributes.get('min_temp')) - self.assertEqual(35, state.attributes.get('max_temp')) - self.assertEqual(None, state.attributes.get('temperature')) - - def test_custom_setup_params(self): - """Test the setup with custom parameters.""" - thermostat.setup(self.hass, {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR, - 'min_temp': MIN_TEMP, - 'max_temp': MAX_TEMP, - 'target_temp': TARGET_TEMP - }}) - state = self.hass.states.get(ENTITY) - self.assertEqual(MIN_TEMP, state.attributes.get('min_temp')) - self.assertEqual(MAX_TEMP, state.attributes.get('max_temp')) - self.assertEqual(TARGET_TEMP, state.attributes.get('temperature')) - self.assertEqual(str(TARGET_TEMP), self.hass.states.get(ENTITY).state) - - def test_set_target_temp(self): - """Test the setting of the target temperature.""" - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self.assertEqual('30.0', self.hass.states.get(ENTITY).state) - - def test_sensor_bad_unit(self): - """Test sensor that have bad unit.""" - state = self.hass.states.get(ENTITY) - temp = state.attributes.get('current_temperature') - unit = state.attributes.get('unit_of_measurement') - - self._setup_sensor(22.0, unit='bad_unit') - self.hass.block_till_done() - - state = self.hass.states.get(ENTITY) - self.assertEqual(unit, state.attributes.get('unit_of_measurement')) - self.assertEqual(temp, state.attributes.get('current_temperature')) - - def test_sensor_bad_value(self): - """Test sensor that have None as state.""" - state = self.hass.states.get(ENTITY) - temp = state.attributes.get('current_temperature') - unit = state.attributes.get('unit_of_measurement') - - self._setup_sensor(None) - self.hass.block_till_done() - - state = self.hass.states.get(ENTITY) - self.assertEqual(unit, state.attributes.get('unit_of_measurement')) - self.assertEqual(temp, state.attributes.get('current_temperature')) - - def test_set_target_temp_heater_on(self): - """Test if target temperature turn heater on.""" - self._setup_switch(False) - self._setup_sensor(25) - self.hass.block_till_done() - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_set_target_temp_heater_off(self): - """Test if target temperature turn heater off.""" - self._setup_switch(True) - self._setup_sensor(30) - self.hass.block_till_done() - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_set_temp_change_heater_on(self): - """Test if temperature change turn heater on.""" - self._setup_switch(False) - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_temp_change_heater_off(self): - """Test if temperature change turn heater off.""" - self._setup_switch(True) - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) - - def _setup_switch(self, is_on): - """Setup the test switch.""" - self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) - self.calls = [] - - def log_call(call): - """Log service calls.""" - self.calls.append(call) - - self.hass.services.register('switch', SERVICE_TURN_ON, log_call) - self.hass.services.register('switch', SERVICE_TURN_OFF, log_call) - - -class TestThermostatHeatControlACMode(unittest.TestCase): - """Test the Heat Control thermostat.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.temperature_unit = TEMP_CELSIUS - thermostat.setup(self.hass, {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR, - 'ac_mode': True - }}) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_set_target_temp_ac_off(self): - """Test if target temperature turn ac off.""" - self._setup_switch(True) - self._setup_sensor(25) - self.hass.block_till_done() - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_set_target_temp_ac_on(self): - """Test if target temperature turn ac on.""" - self._setup_switch(False) - self._setup_sensor(30) - self.hass.block_till_done() - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_set_temp_change_ac_off(self): - """Test if temperature change turn ac off.""" - self._setup_switch(True) - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_temp_change_ac_on(self): - """Test if temperature change turn ac on.""" - self._setup_switch(False) - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) - - def _setup_switch(self, is_on): - """Setup the test switch.""" - self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) - self.calls = [] - - def log_call(call): - """Log service calls.""" - self.calls.append(call) - - self.hass.services.register('switch', SERVICE_TURN_ON, log_call) - self.hass.services.register('switch', SERVICE_TURN_OFF, log_call) - - -class TestThermostatHeatControlACModeMinCycle(unittest.TestCase): - """Test the Heat Control thermostat.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.temperature_unit = TEMP_CELSIUS - thermostat.setup(self.hass, {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR, - 'ac_mode': True, - 'min_cycle_duration': datetime.timedelta(minutes=10) - }}) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_temp_change_ac_trigger_on_not_long_enough(self): - """Test if temperature change turn ac on.""" - self._setup_switch(False) - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(0, len(self.calls)) - - def test_temp_change_ac_trigger_on_long_enough(self): - """Test if temperature change turn ac on.""" - fake_changed = datetime.datetime(1918, 11, 11, 11, 11, 11, - tzinfo=datetime.timezone.utc) - with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', - return_value=fake_changed): - self._setup_switch(False) - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_temp_change_ac_trigger_off_not_long_enough(self): - """Test if temperature change turn ac on.""" - self._setup_switch(True) - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(0, len(self.calls)) - - def test_temp_change_ac_trigger_off_long_enough(self): - """Test if temperature change turn ac on.""" - fake_changed = datetime.datetime(1918, 11, 11, 11, 11, 11, - tzinfo=datetime.timezone.utc) - with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', - return_value=fake_changed): - self._setup_switch(True) - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) - - def _setup_switch(self, is_on): - """Setup the test switch.""" - self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) - self.calls = [] - - def log_call(call): - """Log service calls.""" - self.calls.append(call) - - self.hass.services.register('switch', SERVICE_TURN_ON, log_call) - self.hass.services.register('switch', SERVICE_TURN_OFF, log_call) - - -class TestThermostatHeatControlMinCycle(unittest.TestCase): - """Test the Heat Control thermostat.""" - - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.hass.config.temperature_unit = TEMP_CELSIUS - thermostat.setup(self.hass, {'thermostat': { - 'platform': 'heat_control', - 'name': 'test', - 'heater': ENT_SWITCH, - 'target_sensor': ENT_SENSOR, - 'min_cycle_duration': datetime.timedelta(minutes=10) - }}) - - def tearDown(self): # pylint: disable=invalid-name - """Stop down everything that was started.""" - self.hass.stop() - - def test_temp_change_heater_trigger_off_not_long_enough(self): - """Test if temp change doesn't turn heater off because of time.""" - self._setup_switch(True) - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(0, len(self.calls)) - - def test_temp_change_heater_trigger_on_not_long_enough(self): - """Test if temp change doesn't turn heater on because of time.""" - self._setup_switch(False) - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(0, len(self.calls)) - - def test_temp_change_heater_trigger_on_long_enough(self): - """Test if temperature change turn heater on after min cycle.""" - fake_changed = datetime.datetime(1918, 11, 11, 11, 11, 11, - tzinfo=datetime.timezone.utc) - with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', - return_value=fake_changed): - self._setup_switch(False) - thermostat.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_temp_change_heater_trigger_off_long_enough(self): - """Test if temperature change turn heater off after min cycle.""" - fake_changed = datetime.datetime(1918, 11, 11, 11, 11, 11, - tzinfo=datetime.timezone.utc) - with mock.patch('homeassistant.helpers.condition.dt_util.utcnow', - return_value=fake_changed): - self._setup_switch(True) - thermostat.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) - - def _setup_switch(self, is_on): - """Setup the test switch.""" - self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) - self.calls = [] - - def log_call(call): - """Log service calls.""" - self.calls.append(call) - - self.hass.services.register('switch', SERVICE_TURN_ON, log_call) - self.hass.services.register('switch', SERVICE_TURN_OFF, log_call) diff --git a/tests/components/thermostat/test_honeywell.py b/tests/components/thermostat/test_honeywell.py deleted file mode 100644 index b95cede77b31b..0000000000000 --- a/tests/components/thermostat/test_honeywell.py +++ /dev/null @@ -1,391 +0,0 @@ -"""The test the Honeywell thermostat module.""" -import socket -import unittest -from unittest import mock - -import somecomfort - -from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, - TEMP_CELSIUS, TEMP_FAHRENHEIT) -import homeassistant.components.thermostat.honeywell as honeywell - - -class TestHoneywell(unittest.TestCase): - """A test class for Honeywell themostats.""" - - @mock.patch('somecomfort.SomeComfort') - @mock.patch('homeassistant.components.thermostat.' - 'honeywell.HoneywellUSThermostat') - def test_setup_us(self, mock_ht, mock_sc): - """Test for the US setup.""" - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - 'region': 'us', - } - bad_pass_config = { - CONF_USERNAME: 'user', - 'region': 'us', - } - bad_region_config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - 'region': 'un', - } - hass = mock.MagicMock() - add_devices = mock.MagicMock() - - locations = [ - mock.MagicMock(), - mock.MagicMock(), - ] - devices_1 = [mock.MagicMock()] - devices_2 = [mock.MagicMock(), mock.MagicMock] - mock_sc.return_value.locations_by_id.values.return_value = \ - locations - locations[0].devices_by_id.values.return_value = devices_1 - locations[1].devices_by_id.values.return_value = devices_2 - - result = honeywell.setup_platform(hass, bad_pass_config, add_devices) - self.assertFalse(result) - result = honeywell.setup_platform(hass, bad_region_config, add_devices) - self.assertFalse(result) - result = honeywell.setup_platform(hass, config, add_devices) - self.assertTrue(result) - self.assertEqual(mock_sc.call_count, 1) - self.assertEqual(mock_sc.call_args, mock.call('user', 'pass')) - mock_ht.assert_has_calls([ - mock.call(mock_sc.return_value, devices_1[0]), - mock.call(mock_sc.return_value, devices_2[0]), - mock.call(mock_sc.return_value, devices_2[1]), - ]) - - @mock.patch('somecomfort.SomeComfort') - def test_setup_us_failures(self, mock_sc): - """Test the US setup.""" - hass = mock.MagicMock() - add_devices = mock.MagicMock() - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - 'region': 'us', - } - - mock_sc.side_effect = somecomfort.AuthError - result = honeywell.setup_platform(hass, config, add_devices) - self.assertFalse(result) - self.assertFalse(add_devices.called) - - mock_sc.side_effect = somecomfort.SomeComfortError - result = honeywell.setup_platform(hass, config, add_devices) - self.assertFalse(result) - self.assertFalse(add_devices.called) - - @mock.patch('somecomfort.SomeComfort') - @mock.patch('homeassistant.components.thermostat.' - 'honeywell.HoneywellUSThermostat') - def _test_us_filtered_devices(self, mock_ht, mock_sc, loc=None, dev=None): - """Test for US filtered thermostats.""" - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - 'region': 'us', - 'location': loc, - 'thermostat': dev, - } - locations = { - 1: mock.MagicMock(locationid=mock.sentinel.loc1, - devices_by_id={ - 11: mock.MagicMock( - deviceid=mock.sentinel.loc1dev1), - 12: mock.MagicMock( - deviceid=mock.sentinel.loc1dev2), - }), - 2: mock.MagicMock(locationid=mock.sentinel.loc2, - devices_by_id={ - 21: mock.MagicMock( - deviceid=mock.sentinel.loc2dev1), - }), - 3: mock.MagicMock(locationid=mock.sentinel.loc3, - devices_by_id={ - 31: mock.MagicMock( - deviceid=mock.sentinel.loc3dev1), - }), - } - mock_sc.return_value = mock.MagicMock(locations_by_id=locations) - hass = mock.MagicMock() - add_devices = mock.MagicMock() - self.assertEqual(True, - honeywell.setup_platform(hass, config, add_devices)) - - return mock_ht.call_args_list, mock_sc - - def test_us_filtered_thermostat_1(self): - """Test for US filtered thermostats.""" - result, client = self._test_us_filtered_devices( - dev=mock.sentinel.loc1dev1) - devices = [x[0][1].deviceid for x in result] - self.assertEqual([mock.sentinel.loc1dev1], devices) - - def test_us_filtered_thermostat_2(self): - """Test for US filtered location.""" - result, client = self._test_us_filtered_devices( - dev=mock.sentinel.loc2dev1) - devices = [x[0][1].deviceid for x in result] - self.assertEqual([mock.sentinel.loc2dev1], devices) - - def test_us_filtered_location_1(self): - """Test for US filtered locations.""" - result, client = self._test_us_filtered_devices( - loc=mock.sentinel.loc1) - devices = [x[0][1].deviceid for x in result] - self.assertEqual([mock.sentinel.loc1dev1, - mock.sentinel.loc1dev2], devices) - - def test_us_filtered_location_2(self): - """Test for US filtered locations.""" - result, client = self._test_us_filtered_devices( - loc=mock.sentinel.loc2) - devices = [x[0][1].deviceid for x in result] - self.assertEqual([mock.sentinel.loc2dev1], devices) - - @mock.patch('evohomeclient.EvohomeClient') - @mock.patch('homeassistant.components.thermostat.honeywell.' - 'RoundThermostat') - def test_eu_setup_full_config(self, mock_round, mock_evo): - """Test the EU setup wwith complete configuration.""" - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - honeywell.CONF_AWAY_TEMP: 20, - 'region': 'eu', - } - mock_evo.return_value.temperatures.return_value = [ - {'id': 'foo'}, {'id': 'bar'}] - hass = mock.MagicMock() - add_devices = mock.MagicMock() - self.assertTrue(honeywell.setup_platform(hass, config, add_devices)) - self.assertEqual(mock_evo.call_count, 1) - self.assertEqual(mock_evo.call_args, mock.call('user', 'pass')) - self.assertEqual(mock_evo.return_value.temperatures.call_count, 1) - self.assertEqual( - mock_evo.return_value.temperatures.call_args, - mock.call(force_refresh=True) - ) - mock_round.assert_has_calls([ - mock.call(mock_evo.return_value, 'foo', True, 20), - mock.call(mock_evo.return_value, 'bar', False, 20), - ]) - self.assertEqual(2, add_devices.call_count) - - @mock.patch('evohomeclient.EvohomeClient') - @mock.patch('homeassistant.components.thermostat.honeywell.' - 'RoundThermostat') - def test_eu_setup_partial_config(self, mock_round, mock_evo): - """Test the EU setup with partial configuration.""" - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - 'region': 'eu', - } - mock_evo.return_value.temperatures.return_value = [ - {'id': 'foo'}, {'id': 'bar'}] - hass = mock.MagicMock() - add_devices = mock.MagicMock() - self.assertTrue(honeywell.setup_platform(hass, config, add_devices)) - default = honeywell.DEFAULT_AWAY_TEMP - mock_round.assert_has_calls([ - mock.call(mock_evo.return_value, 'foo', True, default), - mock.call(mock_evo.return_value, 'bar', False, default), - ]) - - @mock.patch('evohomeclient.EvohomeClient') - @mock.patch('homeassistant.components.thermostat.honeywell.' - 'RoundThermostat') - def test_eu_setup_bad_temp(self, mock_round, mock_evo): - """Test the EU setup with invalid temperature.""" - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - honeywell.CONF_AWAY_TEMP: 'ponies', - 'region': 'eu', - } - self.assertFalse(honeywell.setup_platform(None, config, None)) - - @mock.patch('evohomeclient.EvohomeClient') - @mock.patch('homeassistant.components.thermostat.honeywell.' - 'RoundThermostat') - def test_eu_setup_error(self, mock_round, mock_evo): - """Test the EU setup with errors.""" - config = { - CONF_USERNAME: 'user', - CONF_PASSWORD: 'pass', - honeywell.CONF_AWAY_TEMP: 20, - 'region': 'eu', - } - mock_evo.return_value.temperatures.side_effect = socket.error - add_devices = mock.MagicMock() - hass = mock.MagicMock() - self.assertFalse(honeywell.setup_platform(hass, config, add_devices)) - - -class TestHoneywellRound(unittest.TestCase): - """A test class for Honeywell Round thermostats.""" - - def setup_method(self, method): - """Test the setup method.""" - def fake_temperatures(force_refresh=None): - """Create fake temperatures.""" - temps = [ - {'id': '1', 'temp': 20, 'setpoint': 21, - 'thermostat': 'main', 'name': 'House'}, - {'id': '2', 'temp': 21, 'setpoint': 22, - 'thermostat': 'DOMESTIC_HOT_WATER'}, - ] - return temps - - self.device = mock.MagicMock() - self.device.temperatures.side_effect = fake_temperatures - self.round1 = honeywell.RoundThermostat(self.device, '1', - True, 16) - self.round2 = honeywell.RoundThermostat(self.device, '2', - False, 17) - - def test_attributes(self): - """Test the attributes.""" - self.assertEqual('House', self.round1.name) - self.assertEqual(TEMP_CELSIUS, self.round1.unit_of_measurement) - self.assertEqual(20, self.round1.current_temperature) - self.assertEqual(21, self.round1.target_temperature) - self.assertFalse(self.round1.is_away_mode_on) - - self.assertEqual('Hot Water', self.round2.name) - self.assertEqual(TEMP_CELSIUS, self.round2.unit_of_measurement) - self.assertEqual(21, self.round2.current_temperature) - self.assertEqual(None, self.round2.target_temperature) - self.assertFalse(self.round2.is_away_mode_on) - - def test_away_mode(self): - """Test setting the away mode.""" - self.assertFalse(self.round1.is_away_mode_on) - self.round1.turn_away_mode_on() - self.assertTrue(self.round1.is_away_mode_on) - self.assertEqual(self.device.set_temperature.call_count, 1) - self.assertEqual( - self.device.set_temperature.call_args, mock.call('House', 16) - ) - - self.device.set_temperature.reset_mock() - self.round1.turn_away_mode_off() - self.assertFalse(self.round1.is_away_mode_on) - self.assertEqual(self.device.cancel_temp_override.call_count, 1) - self.assertEqual( - self.device.cancel_temp_override.call_args, mock.call('House') - ) - - def test_set_temperature(self): - """Test setting the temperature.""" - self.round1.set_temperature(25) - self.assertEqual(self.device.set_temperature.call_count, 1) - self.assertEqual( - self.device.set_temperature.call_args, mock.call('House', 25) - ) - - def test_set_hvac_mode(self: unittest.TestCase) -> None: - """Test setting the system operation.""" - self.round1.set_hvac_mode('cool') - self.assertEqual('cool', self.round1.operation) - self.assertEqual('cool', self.device.system_mode) - - self.round1.set_hvac_mode('heat') - self.assertEqual('heat', self.round1.operation) - self.assertEqual('heat', self.device.system_mode) - - -class TestHoneywellUS(unittest.TestCase): - """A test class for Honeywell US thermostats.""" - - def setup_method(self, method): - """Test the setup method.""" - self.client = mock.MagicMock() - self.device = mock.MagicMock() - self.honeywell = honeywell.HoneywellUSThermostat( - self.client, self.device) - - self.device.fan_running = True - self.device.name = 'test' - self.device.temperature_unit = 'F' - self.device.current_temperature = 72 - self.device.setpoint_cool = 78 - self.device.setpoint_heat = 65 - self.device.system_mode = 'heat' - self.device.fan_mode = 'auto' - - def test_properties(self): - """Test the properties.""" - self.assertTrue(self.honeywell.is_fan_on) - self.assertEqual('test', self.honeywell.name) - self.assertEqual(72, self.honeywell.current_temperature) - - def test_unit_of_measurement(self): - """Test the unit of measurement.""" - self.assertEqual(TEMP_FAHRENHEIT, self.honeywell.unit_of_measurement) - self.device.temperature_unit = 'C' - self.assertEqual(TEMP_CELSIUS, self.honeywell.unit_of_measurement) - - def test_target_temp(self): - """Test the target temperature.""" - self.assertEqual(65, self.honeywell.target_temperature) - self.device.system_mode = 'cool' - self.assertEqual(78, self.honeywell.target_temperature) - - def test_set_temp(self): - """Test setting the temperature.""" - self.honeywell.set_temperature(70) - self.assertEqual(70, self.device.setpoint_heat) - self.assertEqual(70, self.honeywell.target_temperature) - - self.device.system_mode = 'cool' - self.assertEqual(78, self.honeywell.target_temperature) - self.honeywell.set_temperature(74) - self.assertEqual(74, self.device.setpoint_cool) - self.assertEqual(74, self.honeywell.target_temperature) - - def test_set_hvac_mode(self: unittest.TestCase) -> None: - """Test setting the HVAC mode.""" - self.honeywell.set_hvac_mode('cool') - self.assertEqual('cool', self.honeywell.operation) - self.assertEqual('cool', self.device.system_mode) - - self.honeywell.set_hvac_mode('heat') - self.assertEqual('heat', self.honeywell.operation) - self.assertEqual('heat', self.device.system_mode) - - def test_set_temp_fail(self): - """Test if setting the temperature fails.""" - self.device.setpoint_heat = mock.MagicMock( - side_effect=somecomfort.SomeComfortError) - self.honeywell.set_temperature(123) - - def test_attributes(self): - """Test the attributes.""" - expected = { - 'fan': 'running', - 'fanmode': 'auto', - 'system_mode': 'heat', - } - self.assertEqual(expected, self.honeywell.device_state_attributes) - expected['fan'] = 'idle' - self.device.fan_running = False - self.assertEqual(expected, self.honeywell.device_state_attributes) - - def test_with_no_fan(self): - """Test if there is on fan.""" - self.device.fan_running = False - self.device.fan_mode = None - expected = { - 'fan': 'idle', - 'fanmode': None, - 'system_mode': 'heat', - } - self.assertEqual(expected, self.honeywell.device_state_attributes)