mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
Merge pull request #1241 from kk7ds/update-honeywell-somecomfort
Update honeywell somecomfort
This commit is contained in:
commit
9204c44eec
@ -149,7 +149,6 @@ omit =
|
|||||||
homeassistant/components/switch/wemo.py
|
homeassistant/components/switch/wemo.py
|
||||||
homeassistant/components/thermostat/heatmiser.py
|
homeassistant/components/thermostat/heatmiser.py
|
||||||
homeassistant/components/thermostat/homematic.py
|
homeassistant/components/thermostat/homematic.py
|
||||||
homeassistant/components/thermostat/honeywell.py
|
|
||||||
homeassistant/components/thermostat/proliphix.py
|
homeassistant/components/thermostat/proliphix.py
|
||||||
homeassistant/components/thermostat/radiotherm.py
|
homeassistant/components/thermostat/radiotherm.py
|
||||||
|
|
||||||
|
@ -9,28 +9,24 @@ https://home-assistant.io/components/thermostat.honeywell/
|
|||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from homeassistant.components.thermostat import ThermostatDevice
|
from homeassistant.components.thermostat import ThermostatDevice
|
||||||
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, TEMP_CELCIUS,
|
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, TEMP_CELCIUS,
|
||||||
TEMP_FAHRENHEIT)
|
TEMP_FAHRENHEIT)
|
||||||
|
|
||||||
REQUIREMENTS = ['evohomeclient==0.2.4']
|
REQUIREMENTS = ['evohomeclient==0.2.4',
|
||||||
|
'somecomfort==0.2.0']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONF_AWAY_TEMP = "away_temperature"
|
CONF_AWAY_TEMP = "away_temperature"
|
||||||
US_SYSTEM_SWITCH_POSITIONS = {1: 'Heat',
|
DEFAULT_AWAY_TEMP = 16
|
||||||
2: 'Off',
|
|
||||||
3: 'Cool'}
|
|
||||||
US_BASEURL = 'https://mytotalconnectcomfort.com/portal'
|
|
||||||
|
|
||||||
|
|
||||||
def _setup_round(username, password, config, add_devices):
|
def _setup_round(username, password, config, add_devices):
|
||||||
from evohomeclient import EvohomeClient
|
from evohomeclient import EvohomeClient
|
||||||
|
|
||||||
try:
|
try:
|
||||||
away_temp = float(config.get(CONF_AWAY_TEMP, 16))
|
away_temp = float(config.get(CONF_AWAY_TEMP, DEFAULT_AWAY_TEMP))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
_LOGGER.error("value entered for item %s should convert to a number",
|
_LOGGER.error("value entered for item %s should convert to a number",
|
||||||
CONF_AWAY_TEMP)
|
CONF_AWAY_TEMP)
|
||||||
@ -50,25 +46,32 @@ def _setup_round(username, password, config, add_devices):
|
|||||||
"Connection error logging into the honeywell evohome web service"
|
"Connection error logging into the honeywell evohome web service"
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
# config will be used later
|
# config will be used later
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def _setup_us(username, password, config, add_devices):
|
def _setup_us(username, password, config, add_devices):
|
||||||
session = requests.Session()
|
import somecomfort
|
||||||
if not HoneywellUSThermostat.do_login(session, username, password):
|
|
||||||
|
try:
|
||||||
|
client = somecomfort.SomeComfort(username, password)
|
||||||
|
except somecomfort.AuthError:
|
||||||
_LOGGER.error('Failed to login to honeywell account %s', username)
|
_LOGGER.error('Failed to login to honeywell account %s', username)
|
||||||
return False
|
return False
|
||||||
|
except somecomfort.SomeComfortError as ex:
|
||||||
thermostats = HoneywellUSThermostat.get_devices(session)
|
_LOGGER.error('Failed to initialize honeywell client: %s', str(ex))
|
||||||
if not thermostats:
|
|
||||||
_LOGGER.error('No thermostats found in account %s', username)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
add_devices([HoneywellUSThermostat(id_, username, password,
|
dev_id = config.get('thermostat')
|
||||||
name=name,
|
loc_id = config.get('location')
|
||||||
session=session)
|
|
||||||
for id_, name in thermostats.items()])
|
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
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
@ -179,157 +182,52 @@ class RoundThermostat(ThermostatDevice):
|
|||||||
class HoneywellUSThermostat(ThermostatDevice):
|
class HoneywellUSThermostat(ThermostatDevice):
|
||||||
""" Represents a Honeywell US Thermostat. """
|
""" Represents a Honeywell US Thermostat. """
|
||||||
|
|
||||||
# pylint: disable=too-many-arguments
|
def __init__(self, client, device):
|
||||||
def __init__(self, ident, username, password, name='honeywell',
|
self._client = client
|
||||||
session=None):
|
self._device = device
|
||||||
self._ident = ident
|
|
||||||
self._username = username
|
|
||||||
self._password = password
|
|
||||||
self._name = name
|
|
||||||
if not session:
|
|
||||||
self._session = requests.Session()
|
|
||||||
self._login()
|
|
||||||
self._session = session
|
|
||||||
# Maybe this should be configurable?
|
|
||||||
self._timeout = 30
|
|
||||||
# Yeah, really.
|
|
||||||
self._session.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
||||||
self._update()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_devices(session):
|
|
||||||
""" Return a dict of devices.
|
|
||||||
|
|
||||||
:param session: A session already primed from do_login
|
|
||||||
:returns: A dict of devices like: device_id=name
|
|
||||||
"""
|
|
||||||
url = '%s/Location/GetLocationListData' % US_BASEURL
|
|
||||||
resp = session.post(url, params={'page': 1, 'filter': ''})
|
|
||||||
if resp.status_code == 200:
|
|
||||||
return {device['DeviceID']: device['Name']
|
|
||||||
for device in resp.json()[0]['Devices']}
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def do_login(session, username, password, timeout=30):
|
|
||||||
""" Log into mytotalcomfort.com
|
|
||||||
|
|
||||||
:param session: A requests.Session object to use
|
|
||||||
:param username: Account username
|
|
||||||
:param password: Account password
|
|
||||||
:param timeout: Timeout to use with requests
|
|
||||||
:returns: A boolean indicating success
|
|
||||||
"""
|
|
||||||
session.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
||||||
session.get(US_BASEURL, timeout=timeout)
|
|
||||||
params = {'UserName': username,
|
|
||||||
'Password': password,
|
|
||||||
'RememberMe': 'false',
|
|
||||||
'timeOffset': 480}
|
|
||||||
resp = session.post(US_BASEURL, params=params,
|
|
||||||
timeout=timeout)
|
|
||||||
if resp.status_code != 200:
|
|
||||||
_LOGGER('Login failed for user %s', username)
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _login(self):
|
|
||||||
return self.do_login(self._session, self._username, self._password,
|
|
||||||
timeout=self._timeout)
|
|
||||||
|
|
||||||
def _keepalive(self):
|
|
||||||
resp = self._session.get('%s/Account/KeepAlive')
|
|
||||||
if resp.status_code != 200:
|
|
||||||
if self._login():
|
|
||||||
_LOGGER.info('Re-logged into honeywell account')
|
|
||||||
else:
|
|
||||||
_LOGGER.error('Failed to re-login to honeywell account')
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
_LOGGER.debug('Keepalive succeeded')
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _get_data(self):
|
|
||||||
if not self._keepalive:
|
|
||||||
return {'error': 'not logged in'}
|
|
||||||
url = '%s/Device/CheckDataSession/%s' % (US_BASEURL, self._ident)
|
|
||||||
resp = self._session.get(url, timeout=self._timeout)
|
|
||||||
if resp.status_code < 300:
|
|
||||||
return resp.json()
|
|
||||||
else:
|
|
||||||
return {'error': resp.status_code}
|
|
||||||
|
|
||||||
def _set_data(self, data):
|
|
||||||
if not self._keepalive:
|
|
||||||
return {'error': 'not logged in'}
|
|
||||||
url = '%s/Device/SubmitControlScreenChanges' % US_BASEURL
|
|
||||||
data['DeviceID'] = self._ident
|
|
||||||
resp = self._session.post(url, data=data, timeout=self._timeout)
|
|
||||||
if resp.status_code < 300:
|
|
||||||
return resp.json()
|
|
||||||
else:
|
|
||||||
return {'error': resp.status_code}
|
|
||||||
|
|
||||||
def _update(self):
|
|
||||||
data = self._get_data()['latestData']
|
|
||||||
if 'error' not in data:
|
|
||||||
self._data = data
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_fan_on(self):
|
def is_fan_on(self):
|
||||||
return self._data['fanData']['fanIsRunning']
|
return self._device.fan_running
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name
|
return self._device.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
unit = self._data['uiData']['DisplayUnits']
|
return (TEMP_CELCIUS if self._device.temperature_unit == 'C'
|
||||||
if unit == 'F':
|
else TEMP_FAHRENHEIT)
|
||||||
return TEMP_FAHRENHEIT
|
|
||||||
else:
|
|
||||||
return TEMP_CELCIUS
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_temperature(self):
|
def current_temperature(self):
|
||||||
self._update()
|
self._device.refresh()
|
||||||
return self._data['uiData']['DispTemperature']
|
return self._device.current_temperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self):
|
def target_temperature(self):
|
||||||
setpoint = US_SYSTEM_SWITCH_POSITIONS.get(
|
if self._device.system_mode == 'cool':
|
||||||
self._data['uiData']['SystemSwitchPosition'],
|
return self._device.setpoint_cool
|
||||||
'Off')
|
else:
|
||||||
return self._data['uiData']['%sSetpoint' % setpoint]
|
return self._device.setpoint_heat
|
||||||
|
|
||||||
def set_temperature(self, temperature):
|
def set_temperature(self, temperature):
|
||||||
""" Set target temperature. """
|
""" Set target temperature. """
|
||||||
data = {'SystemSwitch': None,
|
import somecomfort
|
||||||
'HeatSetpoint': None,
|
try:
|
||||||
'CoolSetpoint': None,
|
if self._device.system_mode == 'cool':
|
||||||
'HeatNextPeriod': None,
|
self._device.setpoint_cool = temperature
|
||||||
'CoolNextPeriod': None,
|
else:
|
||||||
'StatusHeat': None,
|
self._device.setpoint_heat = temperature
|
||||||
'StatusCool': None,
|
except somecomfort.SomeComfortError:
|
||||||
'FanMode': None}
|
_LOGGER.error('Temperature %.1f out of range', temperature)
|
||||||
setpoint = US_SYSTEM_SWITCH_POSITIONS.get(
|
|
||||||
self._data['uiData']['SystemSwitchPosition'],
|
|
||||||
'Off')
|
|
||||||
data['%sSetpoint' % setpoint] = temperature
|
|
||||||
self._set_data(data)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
""" Return device specific state attributes. """
|
""" Return device specific state attributes. """
|
||||||
fanmodes = {0: "auto",
|
return {'fan': (self.is_fan_on and 'running' or 'idle'),
|
||||||
1: "on",
|
'fanmode': self._device.fan_mode,
|
||||||
2: "circulate"}
|
'system_mode': self._device.system_mode}
|
||||||
return {"fan": (self._data['fanData']['fanIsRunning'] and
|
|
||||||
'running' or 'idle'),
|
|
||||||
"fanmode": fanmodes[self._data['fanData']['fanMode']]}
|
|
||||||
|
|
||||||
def turn_away_mode_on(self):
|
def turn_away_mode_on(self):
|
||||||
pass
|
pass
|
||||||
|
@ -230,6 +230,9 @@ sleekxmpp==1.3.1
|
|||||||
# homeassistant.components.media_player.snapcast
|
# homeassistant.components.media_player.snapcast
|
||||||
snapcast==1.1.1
|
snapcast==1.1.1
|
||||||
|
|
||||||
|
# homeassistant.components.thermostat.honeywell
|
||||||
|
somecomfort==0.2.0
|
||||||
|
|
||||||
# homeassistant.components.sensor.speedtest
|
# homeassistant.components.sensor.speedtest
|
||||||
speedtest-cli==0.3.4
|
speedtest-cli==0.3.4
|
||||||
|
|
||||||
|
310
tests/components/thermostat/test_honeywell.py
Normal file
310
tests/components/thermostat/test_honeywell.py
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
"""
|
||||||
|
tests.components.thermostat.honeywell
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests the Honeywell thermostat module.
|
||||||
|
"""
|
||||||
|
import socket
|
||||||
|
import unittest
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import somecomfort
|
||||||
|
|
||||||
|
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD,
|
||||||
|
TEMP_CELCIUS, TEMP_FAHRENHEIT)
|
||||||
|
import homeassistant.components.thermostat.honeywell as honeywell
|
||||||
|
|
||||||
|
|
||||||
|
class TestHoneywell(unittest.TestCase):
|
||||||
|
@mock.patch('somecomfort.SomeComfort')
|
||||||
|
@mock.patch('homeassistant.components.thermostat.'
|
||||||
|
'honeywell.HoneywellUSThermostat')
|
||||||
|
def test_setup_us(self, mock_ht, mock_sc):
|
||||||
|
config = {
|
||||||
|
CONF_USERNAME: 'user',
|
||||||
|
CONF_PASSWORD: 'pass',
|
||||||
|
'region': 'us',
|
||||||
|
}
|
||||||
|
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, config, add_devices)
|
||||||
|
self.assertTrue(result)
|
||||||
|
mock_sc.assert_called_once_with('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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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))
|
||||||
|
mock_evo.assert_called_once_with('user', 'pass')
|
||||||
|
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),
|
||||||
|
])
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
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):
|
||||||
|
def setup_method(self, method):
|
||||||
|
def fake_temperatures(force_refresh=None):
|
||||||
|
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):
|
||||||
|
self.assertEqual('House', self.round1.name)
|
||||||
|
self.assertEqual(TEMP_CELCIUS, 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_CELCIUS, 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):
|
||||||
|
self.assertFalse(self.round1.is_away_mode_on)
|
||||||
|
self.round1.turn_away_mode_on()
|
||||||
|
self.assertTrue(self.round1.is_away_mode_on)
|
||||||
|
self.device.set_temperature.assert_called_once_with('House', 16)
|
||||||
|
|
||||||
|
self.device.set_temperature.reset_mock()
|
||||||
|
self.round1.turn_away_mode_off()
|
||||||
|
self.assertFalse(self.round1.is_away_mode_on)
|
||||||
|
self.device.cancel_temp_override.assert_called_once_with('House')
|
||||||
|
|
||||||
|
def test_set_temperature(self):
|
||||||
|
self.round1.set_temperature(25)
|
||||||
|
self.device.set_temperature.assert_called_once_with('House', 25)
|
||||||
|
|
||||||
|
|
||||||
|
class TestHoneywellUS(unittest.TestCase):
|
||||||
|
def setup_method(self, 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):
|
||||||
|
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):
|
||||||
|
self.assertEqual(TEMP_FAHRENHEIT, self.honeywell.unit_of_measurement)
|
||||||
|
self.device.temperature_unit = 'C'
|
||||||
|
self.assertEqual(TEMP_CELCIUS, self.honeywell.unit_of_measurement)
|
||||||
|
|
||||||
|
def test_target_temp(self):
|
||||||
|
self.assertEqual(65, self.honeywell.target_temperature)
|
||||||
|
self.device.system_mode = 'cool'
|
||||||
|
self.assertEqual(78, self.honeywell.target_temperature)
|
||||||
|
|
||||||
|
def test_set_temp(self):
|
||||||
|
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_temp_fail(self):
|
||||||
|
self.device.setpoint_heat = mock.MagicMock(
|
||||||
|
side_effect=somecomfort.SomeComfortError)
|
||||||
|
self.honeywell.set_temperature(123)
|
||||||
|
|
||||||
|
def test_attributes(self):
|
||||||
|
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)
|
Loading…
x
Reference in New Issue
Block a user