mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Migrate to voluptuous (#3298)
This commit is contained in:
parent
3f4d30c8da
commit
78313c793c
@ -7,44 +7,67 @@ https://home-assistant.io/components/climate.honeywell/
|
|||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from homeassistant.components.climate import ClimateDevice
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.climate import (ClimateDevice, PLATFORM_SCHEMA)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_PASSWORD, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
CONF_PASSWORD, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||||
ATTR_TEMPERATURE)
|
ATTR_TEMPERATURE)
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
|
||||||
REQUIREMENTS = ['evohomeclient==0.2.5',
|
REQUIREMENTS = ['evohomeclient==0.2.5',
|
||||||
'somecomfort==0.2.1']
|
'somecomfort==0.2.1']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONF_AWAY_TEMP = "away_temperature"
|
ATTR_FAN = 'fan'
|
||||||
DEFAULT_AWAY_TEMP = 16
|
ATTR_FANMODE = 'fanmode'
|
||||||
|
ATTR_SYSTEM_MODE = 'system_mode'
|
||||||
|
|
||||||
|
CONF_AWAY_TEMPERATURE = 'away_temperature'
|
||||||
|
CONF_REGION = 'region'
|
||||||
|
|
||||||
|
DEFAULT_AWAY_TEMPERATURE = 16
|
||||||
|
DEFAULT_REGION = 'eu'
|
||||||
|
REGIONS = ['eu', 'us']
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
|
vol.Required(CONF_USERNAME): cv.string,
|
||||||
|
vol.Required(CONF_PASSWORD): cv.string,
|
||||||
|
vol.Optional(CONF_AWAY_TEMPERATURE, default=DEFAULT_AWAY_TEMPERATURE):
|
||||||
|
vol.Coerce(float),
|
||||||
|
vol.Optional(CONF_REGION, default=DEFAULT_REGION): vol.In(REGIONS),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
|
"""Setup the HoneywelL thermostat."""
|
||||||
|
username = config.get(CONF_USERNAME)
|
||||||
|
password = config.get(CONF_PASSWORD)
|
||||||
|
region = config.get(CONF_REGION)
|
||||||
|
|
||||||
|
if region == 'us':
|
||||||
|
return _setup_us(username, password, config, add_devices)
|
||||||
|
else:
|
||||||
|
return _setup_round(username, password, config, add_devices)
|
||||||
|
|
||||||
|
|
||||||
def _setup_round(username, password, config, add_devices):
|
def _setup_round(username, password, config, add_devices):
|
||||||
"""Setup rounding function."""
|
"""Setup rounding function."""
|
||||||
from evohomeclient import EvohomeClient
|
from evohomeclient import EvohomeClient
|
||||||
|
|
||||||
try:
|
away_temp = config.get(CONF_AWAY_TEMPERATURE)
|
||||||
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)
|
evo_api = EvohomeClient(username, password)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
zones = evo_api.temperatures(force_refresh=True)
|
zones = evo_api.temperatures(force_refresh=True)
|
||||||
for i, zone in enumerate(zones):
|
for i, zone in enumerate(zones):
|
||||||
add_devices([RoundThermostat(evo_api,
|
add_devices(
|
||||||
zone['id'],
|
[RoundThermostat(evo_api, zone['id'], i == 0, away_temp)]
|
||||||
i == 0,
|
)
|
||||||
away_temp)])
|
|
||||||
except socket.error:
|
except socket.error:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Connection error logging into the honeywell evohome web service"
|
"Connection error logging into the honeywell evohome web service")
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -74,26 +97,6 @@ def _setup_us(username, password, config, add_devices):
|
|||||||
return True
|
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(ClimateDevice):
|
class RoundThermostat(ClimateDevice):
|
||||||
"""Representation of a Honeywell Round Connected thermostat."""
|
"""Representation of a Honeywell Round Connected thermostat."""
|
||||||
|
|
||||||
@ -103,7 +106,7 @@ class RoundThermostat(ClimateDevice):
|
|||||||
self.device = device
|
self.device = device
|
||||||
self._current_temperature = None
|
self._current_temperature = None
|
||||||
self._target_temperature = None
|
self._target_temperature = None
|
||||||
self._name = "round connected"
|
self._name = 'round connected'
|
||||||
self._id = zone_id
|
self._id = zone_id
|
||||||
self._master = master
|
self._master = master
|
||||||
self._is_dhw = False
|
self._is_dhw = False
|
||||||
@ -143,7 +146,7 @@ class RoundThermostat(ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def current_operation(self: ClimateDevice) -> str:
|
def current_operation(self: ClimateDevice) -> str:
|
||||||
"""Get the current operation of the system."""
|
"""Get the current operation of the system."""
|
||||||
return getattr(self.device, 'system_mode', None)
|
return getattr(self.device, ATTR_SYSTEM_MODE, None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_away_mode_on(self):
|
def is_away_mode_on(self):
|
||||||
@ -152,7 +155,7 @@ class RoundThermostat(ClimateDevice):
|
|||||||
|
|
||||||
def set_operation_mode(self: ClimateDevice, operation_mode: str) -> None:
|
def set_operation_mode(self: ClimateDevice, operation_mode: str) -> None:
|
||||||
"""Set the HVAC mode for the thermostat."""
|
"""Set the HVAC mode for the thermostat."""
|
||||||
if hasattr(self.device, 'system_mode'):
|
if hasattr(self.device, ATTR_SYSTEM_MODE):
|
||||||
self.device.system_mode = operation_mode
|
self.device.system_mode = operation_mode
|
||||||
|
|
||||||
def turn_away_mode_on(self):
|
def turn_away_mode_on(self):
|
||||||
@ -186,8 +189,8 @@ class RoundThermostat(ClimateDevice):
|
|||||||
|
|
||||||
self._current_temperature = data['temp']
|
self._current_temperature = data['temp']
|
||||||
self._target_temperature = data['setpoint']
|
self._target_temperature = data['setpoint']
|
||||||
if data['thermostat'] == "DOMESTIC_HOT_WATER":
|
if data['thermostat'] == 'DOMESTIC_HOT_WATER':
|
||||||
self._name = "Hot Water"
|
self._name = 'Hot Water'
|
||||||
self._is_dhw = True
|
self._is_dhw = True
|
||||||
else:
|
else:
|
||||||
self._name = data['name']
|
self._name = data['name']
|
||||||
@ -236,7 +239,7 @@ class HoneywellUSThermostat(ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def current_operation(self: ClimateDevice) -> str:
|
def current_operation(self: ClimateDevice) -> str:
|
||||||
"""Return current operation ie. heat, cool, idle."""
|
"""Return current operation ie. heat, cool, idle."""
|
||||||
return getattr(self._device, 'system_mode', None)
|
return getattr(self._device, ATTR_SYSTEM_MODE, None)
|
||||||
|
|
||||||
def set_temperature(self, **kwargs):
|
def set_temperature(self, **kwargs):
|
||||||
"""Set target temperature."""
|
"""Set target temperature."""
|
||||||
@ -255,9 +258,11 @@ class HoneywellUSThermostat(ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the device specific state attributes."""
|
"""Return the device specific state attributes."""
|
||||||
return {'fan': (self.is_fan_on and 'running' or 'idle'),
|
return {
|
||||||
'fanmode': self._device.fan_mode,
|
ATTR_FAN: (self.is_fan_on and 'running' or 'idle'),
|
||||||
'system_mode': self._device.system_mode}
|
ATTR_FANMODE: self._device.fan_mode,
|
||||||
|
ATTR_SYSTEM_MODE: self._device.system_mode,
|
||||||
|
}
|
||||||
|
|
||||||
def turn_away_mode_on(self):
|
def turn_away_mode_on(self):
|
||||||
"""Turn away on."""
|
"""Turn away on."""
|
||||||
@ -269,5 +274,5 @@ class HoneywellUSThermostat(ClimateDevice):
|
|||||||
|
|
||||||
def set_operation_mode(self: ClimateDevice, operation_mode: str) -> None:
|
def set_operation_mode(self: ClimateDevice, operation_mode: str) -> None:
|
||||||
"""Set the system mode (Cool, Heat, etc)."""
|
"""Set the system mode (Cool, Heat, etc)."""
|
||||||
if hasattr(self._device, 'system_mode'):
|
if hasattr(self._device, ATTR_SYSTEM_MODE):
|
||||||
self._device.system_mode = operation_mode
|
self._device.system_mode = operation_mode
|
||||||
|
@ -3,10 +3,11 @@ import socket
|
|||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
import somecomfort
|
import somecomfort
|
||||||
|
|
||||||
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD,
|
from homeassistant.const import (
|
||||||
TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
CONF_USERNAME, CONF_PASSWORD, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||||
import homeassistant.components.climate.honeywell as honeywell
|
import homeassistant.components.climate.honeywell as honeywell
|
||||||
|
|
||||||
|
|
||||||
@ -21,17 +22,30 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
'region': 'us',
|
honeywell.CONF_REGION: 'us',
|
||||||
}
|
}
|
||||||
bad_pass_config = {
|
bad_pass_config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
'region': 'us',
|
honeywell.CONF_REGION: 'us',
|
||||||
}
|
}
|
||||||
bad_region_config = {
|
bad_region_config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
'region': 'un',
|
honeywell.CONF_REGION: 'un',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with self.assertRaises(vol.Invalid):
|
||||||
|
honeywell.PLATFORM_SCHEMA(None)
|
||||||
|
|
||||||
|
with self.assertRaises(vol.Invalid):
|
||||||
|
honeywell.PLATFORM_SCHEMA({})
|
||||||
|
|
||||||
|
with self.assertRaises(vol.Invalid):
|
||||||
|
honeywell.PLATFORM_SCHEMA(bad_pass_config)
|
||||||
|
|
||||||
|
with self.assertRaises(vol.Invalid):
|
||||||
|
honeywell.PLATFORM_SCHEMA(bad_region_config)
|
||||||
|
|
||||||
hass = mock.MagicMock()
|
hass = mock.MagicMock()
|
||||||
add_devices = mock.MagicMock()
|
add_devices = mock.MagicMock()
|
||||||
|
|
||||||
@ -46,10 +60,6 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
locations[0].devices_by_id.values.return_value = devices_1
|
locations[0].devices_by_id.values.return_value = devices_1
|
||||||
locations[1].devices_by_id.values.return_value = devices_2
|
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)
|
result = honeywell.setup_platform(hass, config, add_devices)
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
mock_sc.assert_called_once_with('user', 'pass')
|
mock_sc.assert_called_once_with('user', 'pass')
|
||||||
@ -67,7 +77,7 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
'region': 'us',
|
honeywell.CONF_REGION: 'us',
|
||||||
}
|
}
|
||||||
|
|
||||||
mock_sc.side_effect = somecomfort.AuthError
|
mock_sc.side_effect = somecomfort.AuthError
|
||||||
@ -88,7 +98,7 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
'region': 'us',
|
honeywell.CONF_REGION: 'us',
|
||||||
'location': loc,
|
'location': loc,
|
||||||
'thermostat': dev,
|
'thermostat': dev,
|
||||||
}
|
}
|
||||||
@ -152,12 +162,12 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
@mock.patch('homeassistant.components.climate.honeywell.'
|
@mock.patch('homeassistant.components.climate.honeywell.'
|
||||||
'RoundThermostat')
|
'RoundThermostat')
|
||||||
def test_eu_setup_full_config(self, mock_round, mock_evo):
|
def test_eu_setup_full_config(self, mock_round, mock_evo):
|
||||||
"""Test the EU setup wwith complete configuration."""
|
"""Test the EU setup with complete configuration."""
|
||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
honeywell.CONF_AWAY_TEMP: 20,
|
honeywell.CONF_AWAY_TEMPERATURE: 20.0,
|
||||||
'region': 'eu',
|
honeywell.CONF_REGION: 'eu',
|
||||||
}
|
}
|
||||||
mock_evo.return_value.temperatures.return_value = [
|
mock_evo.return_value.temperatures.return_value = [
|
||||||
{'id': 'foo'}, {'id': 'bar'}]
|
{'id': 'foo'}, {'id': 'bar'}]
|
||||||
@ -168,8 +178,8 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
mock_evo.return_value.temperatures.assert_called_once_with(
|
mock_evo.return_value.temperatures.assert_called_once_with(
|
||||||
force_refresh=True)
|
force_refresh=True)
|
||||||
mock_round.assert_has_calls([
|
mock_round.assert_has_calls([
|
||||||
mock.call(mock_evo.return_value, 'foo', True, 20),
|
mock.call(mock_evo.return_value, 'foo', True, 20.0),
|
||||||
mock.call(mock_evo.return_value, 'bar', False, 20),
|
mock.call(mock_evo.return_value, 'bar', False, 20.0),
|
||||||
])
|
])
|
||||||
self.assertEqual(2, add_devices.call_count)
|
self.assertEqual(2, add_devices.call_count)
|
||||||
|
|
||||||
@ -181,17 +191,20 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
'region': 'eu',
|
honeywell.CONF_REGION: 'eu',
|
||||||
}
|
}
|
||||||
|
|
||||||
mock_evo.return_value.temperatures.return_value = [
|
mock_evo.return_value.temperatures.return_value = [
|
||||||
{'id': 'foo'}, {'id': 'bar'}]
|
{'id': 'foo'}, {'id': 'bar'}]
|
||||||
|
config[honeywell.CONF_AWAY_TEMPERATURE] = \
|
||||||
|
honeywell.DEFAULT_AWAY_TEMPERATURE
|
||||||
|
|
||||||
hass = mock.MagicMock()
|
hass = mock.MagicMock()
|
||||||
add_devices = mock.MagicMock()
|
add_devices = mock.MagicMock()
|
||||||
self.assertTrue(honeywell.setup_platform(hass, config, add_devices))
|
self.assertTrue(honeywell.setup_platform(hass, config, add_devices))
|
||||||
default = honeywell.DEFAULT_AWAY_TEMP
|
|
||||||
mock_round.assert_has_calls([
|
mock_round.assert_has_calls([
|
||||||
mock.call(mock_evo.return_value, 'foo', True, default),
|
mock.call(mock_evo.return_value, 'foo', True, 16),
|
||||||
mock.call(mock_evo.return_value, 'bar', False, default),
|
mock.call(mock_evo.return_value, 'bar', False, 16),
|
||||||
])
|
])
|
||||||
|
|
||||||
@mock.patch('evohomeclient.EvohomeClient')
|
@mock.patch('evohomeclient.EvohomeClient')
|
||||||
@ -202,10 +215,12 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
honeywell.CONF_AWAY_TEMP: 'ponies',
|
honeywell.CONF_AWAY_TEMPERATURE: 'ponies',
|
||||||
'region': 'eu',
|
honeywell.CONF_REGION: 'eu',
|
||||||
}
|
}
|
||||||
self.assertFalse(honeywell.setup_platform(None, config, None))
|
|
||||||
|
with self.assertRaises(vol.Invalid):
|
||||||
|
honeywell.PLATFORM_SCHEMA(config)
|
||||||
|
|
||||||
@mock.patch('evohomeclient.EvohomeClient')
|
@mock.patch('evohomeclient.EvohomeClient')
|
||||||
@mock.patch('homeassistant.components.climate.honeywell.'
|
@mock.patch('homeassistant.components.climate.honeywell.'
|
||||||
@ -215,8 +230,8 @@ class TestHoneywell(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
CONF_USERNAME: 'user',
|
CONF_USERNAME: 'user',
|
||||||
CONF_PASSWORD: 'pass',
|
CONF_PASSWORD: 'pass',
|
||||||
honeywell.CONF_AWAY_TEMP: 20,
|
honeywell.CONF_AWAY_TEMPERATURE: 20,
|
||||||
'region': 'eu',
|
honeywell.CONF_REGION: 'eu',
|
||||||
}
|
}
|
||||||
mock_evo.return_value.temperatures.side_effect = socket.error
|
mock_evo.return_value.temperatures.side_effect = socket.error
|
||||||
add_devices = mock.MagicMock()
|
add_devices = mock.MagicMock()
|
||||||
@ -356,9 +371,9 @@ class TestHoneywellUS(unittest.TestCase):
|
|||||||
def test_attributes(self):
|
def test_attributes(self):
|
||||||
"""Test the attributes."""
|
"""Test the attributes."""
|
||||||
expected = {
|
expected = {
|
||||||
'fan': 'running',
|
honeywell.ATTR_FAN: 'running',
|
||||||
'fanmode': 'auto',
|
honeywell.ATTR_FANMODE: 'auto',
|
||||||
'system_mode': 'heat',
|
honeywell.ATTR_SYSTEM_MODE: 'heat',
|
||||||
}
|
}
|
||||||
self.assertEqual(expected, self.honeywell.device_state_attributes)
|
self.assertEqual(expected, self.honeywell.device_state_attributes)
|
||||||
expected['fan'] = 'idle'
|
expected['fan'] = 'idle'
|
||||||
@ -370,8 +385,8 @@ class TestHoneywellUS(unittest.TestCase):
|
|||||||
self.device.fan_running = False
|
self.device.fan_running = False
|
||||||
self.device.fan_mode = None
|
self.device.fan_mode = None
|
||||||
expected = {
|
expected = {
|
||||||
'fan': 'idle',
|
honeywell.ATTR_FAN: 'idle',
|
||||||
'fanmode': None,
|
honeywell.ATTR_FANMODE: None,
|
||||||
'system_mode': 'heat',
|
honeywell.ATTR_SYSTEM_MODE: 'heat',
|
||||||
}
|
}
|
||||||
self.assertEqual(expected, self.honeywell.device_state_attributes)
|
self.assertEqual(expected, self.honeywell.device_state_attributes)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user