Remove garage_door, hvac, rollershutter and thermostat components/platforms
parent
4c86721e70
commit
044b9caa76
|
@ -160,8 +160,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
|
||||
|
@ -308,11 +306,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
|
||||
|
|
|
@ -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
|
|
@ -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()
|
|
@ -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()
|
|
@ -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()
|
|
@ -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'
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
|
@ -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()
|
|
@ -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)
|
|
@ -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")
|
|
@ -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)
|
|
@ -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'
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -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()
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
"""The tests for Garage door platforms."""
|
|
@ -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))
|
|
@ -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)
|
|
@ -1 +0,0 @@
|
|||
"""The tests for hvac component."""
|
|
@ -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'))
|
|
@ -1 +0,0 @@
|
|||
"""The tests for Roller shutter platforms."""
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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))
|
|
@ -1 +0,0 @@
|
|||
"""The tests for Thermostat platforms."""
|
|
@ -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'))
|
|
@ -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)
|
|
@ -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)
|
Loading…
Reference in New Issue