Skip to content

Commit

Permalink
Migrate to voluptuous (#3298)
Browse files Browse the repository at this point in the history
  • Loading branch information
fabaff authored Sep 11, 2016
1 parent 3f4d30c commit 78313c7
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 77 deletions.
97 changes: 51 additions & 46 deletions homeassistant/components/climate/honeywell.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,67 @@
import logging
import socket

from homeassistant.components.climate import ClimateDevice
import voluptuous as vol

from homeassistant.components.climate import (ClimateDevice, PLATFORM_SCHEMA)
from homeassistant.const import (
CONF_PASSWORD, CONF_USERNAME, TEMP_CELSIUS, TEMP_FAHRENHEIT,
ATTR_TEMPERATURE)
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['evohomeclient==0.2.5',
'somecomfort==0.2.1']

_LOGGER = logging.getLogger(__name__)

CONF_AWAY_TEMP = "away_temperature"
DEFAULT_AWAY_TEMP = 16
ATTR_FAN = 'fan'
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):
"""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

away_temp = config.get(CONF_AWAY_TEMPERATURE)
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)])
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"
)
"Connection error logging into the honeywell evohome web service")
return False
return True

Expand Down Expand Up @@ -74,26 +97,6 @@ def _setup_us(username, password, config, add_devices):
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):
"""Representation of a Honeywell Round Connected thermostat."""

Expand All @@ -103,7 +106,7 @@ def __init__(self, device, zone_id, master, away_temp):
self.device = device
self._current_temperature = None
self._target_temperature = None
self._name = "round connected"
self._name = 'round connected'
self._id = zone_id
self._master = master
self._is_dhw = False
Expand Down Expand Up @@ -143,7 +146,7 @@ def set_temperature(self, **kwargs):
@property
def current_operation(self: ClimateDevice) -> str:
"""Get the current operation of the system."""
return getattr(self.device, 'system_mode', None)
return getattr(self.device, ATTR_SYSTEM_MODE, None)

@property
def is_away_mode_on(self):
Expand All @@ -152,7 +155,7 @@ def is_away_mode_on(self):

def set_operation_mode(self: ClimateDevice, operation_mode: str) -> None:
"""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

def turn_away_mode_on(self):
Expand Down Expand Up @@ -186,8 +189,8 @@ def update(self):

self._current_temperature = data['temp']
self._target_temperature = data['setpoint']
if data['thermostat'] == "DOMESTIC_HOT_WATER":
self._name = "Hot Water"
if data['thermostat'] == 'DOMESTIC_HOT_WATER':
self._name = 'Hot Water'
self._is_dhw = True
else:
self._name = data['name']
Expand Down Expand Up @@ -236,7 +239,7 @@ def target_temperature(self):
@property
def current_operation(self: ClimateDevice) -> str:
"""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):
"""Set target temperature."""
Expand All @@ -255,9 +258,11 @@ def set_temperature(self, **kwargs):
@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}
return {
ATTR_FAN: (self.is_fan_on and 'running' or 'idle'),
ATTR_FANMODE: self._device.fan_mode,
ATTR_SYSTEM_MODE: self._device.system_mode,
}

def turn_away_mode_on(self):
"""Turn away on."""
Expand All @@ -269,5 +274,5 @@ def turn_away_mode_off(self):

def set_operation_mode(self: ClimateDevice, operation_mode: str) -> None:
"""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
77 changes: 46 additions & 31 deletions tests/components/climate/test_honeywell.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import unittest
from unittest import mock

import voluptuous as vol
import somecomfort

from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD,
TEMP_CELSIUS, TEMP_FAHRENHEIT)
from homeassistant.const import (
CONF_USERNAME, CONF_PASSWORD, TEMP_CELSIUS, TEMP_FAHRENHEIT)
import homeassistant.components.climate.honeywell as honeywell


Expand All @@ -21,17 +22,30 @@ def test_setup_us(self, mock_ht, mock_sc):
config = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
'region': 'us',
honeywell.CONF_REGION: 'us',
}
bad_pass_config = {
CONF_USERNAME: 'user',
'region': 'us',
honeywell.CONF_REGION: 'us',
}
bad_region_config = {
CONF_USERNAME: 'user',
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()
add_devices = mock.MagicMock()

Expand All @@ -46,10 +60,6 @@ def test_setup_us(self, mock_ht, mock_sc):
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)
mock_sc.assert_called_once_with('user', 'pass')
Expand All @@ -67,7 +77,7 @@ def test_setup_us_failures(self, mock_sc):
config = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
'region': 'us',
honeywell.CONF_REGION: 'us',
}

mock_sc.side_effect = somecomfort.AuthError
Expand All @@ -88,7 +98,7 @@ def _test_us_filtered_devices(self, mock_ht, mock_sc, loc=None, dev=None):
config = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
'region': 'us',
honeywell.CONF_REGION: 'us',
'location': loc,
'thermostat': dev,
}
Expand Down Expand Up @@ -152,12 +162,12 @@ def test_us_filtered_location_2(self):
@mock.patch('homeassistant.components.climate.honeywell.'
'RoundThermostat')
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 = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
honeywell.CONF_AWAY_TEMP: 20,
'region': 'eu',
honeywell.CONF_AWAY_TEMPERATURE: 20.0,
honeywell.CONF_REGION: 'eu',
}
mock_evo.return_value.temperatures.return_value = [
{'id': 'foo'}, {'id': 'bar'}]
Expand All @@ -168,8 +178,8 @@ def test_eu_setup_full_config(self, mock_round, mock_evo):
mock_evo.return_value.temperatures.assert_called_once_with(
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),
mock.call(mock_evo.return_value, 'foo', True, 20.0),
mock.call(mock_evo.return_value, 'bar', False, 20.0),
])
self.assertEqual(2, add_devices.call_count)

Expand All @@ -181,17 +191,20 @@ def test_eu_setup_partial_config(self, mock_round, mock_evo):
config = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
'region': 'eu',
honeywell.CONF_REGION: 'eu',
}

mock_evo.return_value.temperatures.return_value = [
{'id': 'foo'}, {'id': 'bar'}]
config[honeywell.CONF_AWAY_TEMPERATURE] = \
honeywell.DEFAULT_AWAY_TEMPERATURE

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.call(mock_evo.return_value, 'foo', True, 16),
mock.call(mock_evo.return_value, 'bar', False, 16),
])

@mock.patch('evohomeclient.EvohomeClient')
Expand All @@ -202,10 +215,12 @@ def test_eu_setup_bad_temp(self, mock_round, mock_evo):
config = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
honeywell.CONF_AWAY_TEMP: 'ponies',
'region': 'eu',
honeywell.CONF_AWAY_TEMPERATURE: 'ponies',
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('homeassistant.components.climate.honeywell.'
Expand All @@ -215,8 +230,8 @@ def test_eu_setup_error(self, mock_round, mock_evo):
config = {
CONF_USERNAME: 'user',
CONF_PASSWORD: 'pass',
honeywell.CONF_AWAY_TEMP: 20,
'region': 'eu',
honeywell.CONF_AWAY_TEMPERATURE: 20,
honeywell.CONF_REGION: 'eu',
}
mock_evo.return_value.temperatures.side_effect = socket.error
add_devices = mock.MagicMock()
Expand Down Expand Up @@ -356,9 +371,9 @@ def test_set_temp_fail(self):
def test_attributes(self):
"""Test the attributes."""
expected = {
'fan': 'running',
'fanmode': 'auto',
'system_mode': 'heat',
honeywell.ATTR_FAN: 'running',
honeywell.ATTR_FANMODE: 'auto',
honeywell.ATTR_SYSTEM_MODE: 'heat',
}
self.assertEqual(expected, self.honeywell.device_state_attributes)
expected['fan'] = 'idle'
Expand All @@ -370,8 +385,8 @@ def test_with_no_fan(self):
self.device.fan_running = False
self.device.fan_mode = None
expected = {
'fan': 'idle',
'fanmode': None,
'system_mode': 'heat',
honeywell.ATTR_FAN: 'idle',
honeywell.ATTR_FANMODE: None,
honeywell.ATTR_SYSTEM_MODE: 'heat',
}
self.assertEqual(expected, self.honeywell.device_state_attributes)

0 comments on commit 78313c7

Please sign in to comment.