2019-02-14 04:35:12 +00:00
|
|
|
"""Support for MAX! Thermostats via MAX! Cube."""
|
2017-02-27 05:35:33 +00:00
|
|
|
import logging
|
2019-03-21 05:56:46 +00:00
|
|
|
import socket
|
2017-02-27 05:35:33 +00:00
|
|
|
|
2019-02-14 19:34:43 +00:00
|
|
|
from homeassistant.components.climate import ClimateDevice
|
|
|
|
from homeassistant.components.climate.const import (
|
2019-03-21 05:56:46 +00:00
|
|
|
STATE_AUTO, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE)
|
|
|
|
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
|
|
|
|
|
|
|
from . import DATA_KEY
|
2017-02-27 05:35:33 +00:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2017-04-22 19:13:04 +00:00
|
|
|
STATE_MANUAL = 'manual'
|
|
|
|
STATE_BOOST = 'boost'
|
|
|
|
STATE_VACATION = 'vacation'
|
2017-02-27 05:35:33 +00:00
|
|
|
|
2017-11-29 10:01:28 +00:00
|
|
|
SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE
|
|
|
|
|
2017-02-27 05:35:33 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Iterate through all MAX! Devices and add thermostats."""
|
2017-02-27 05:35:33 +00:00
|
|
|
devices = []
|
2018-04-19 07:11:38 +00:00
|
|
|
for handler in hass.data[DATA_KEY].values():
|
|
|
|
cube = handler.cube
|
|
|
|
for device in cube.devices:
|
|
|
|
name = '{} {}'.format(
|
|
|
|
cube.room_by_id(device.room_id).name, device.name)
|
2017-02-27 05:35:33 +00:00
|
|
|
|
2018-04-19 07:11:38 +00:00
|
|
|
if cube.is_thermostat(device) or cube.is_wallthermostat(device):
|
|
|
|
devices.append(
|
|
|
|
MaxCubeClimate(handler, name, device.rf_address))
|
2017-02-27 05:35:33 +00:00
|
|
|
|
2017-04-24 03:41:09 +00:00
|
|
|
if devices:
|
2018-08-24 14:37:30 +00:00
|
|
|
add_entities(devices)
|
2017-02-27 05:35:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
class MaxCubeClimate(ClimateDevice):
|
|
|
|
"""MAX! Cube ClimateDevice."""
|
|
|
|
|
2018-04-19 07:11:38 +00:00
|
|
|
def __init__(self, handler, name, rf_address):
|
2017-02-27 05:35:33 +00:00
|
|
|
"""Initialize MAX! Cube ClimateDevice."""
|
|
|
|
self._name = name
|
|
|
|
self._operation_list = [STATE_AUTO, STATE_MANUAL, STATE_BOOST,
|
|
|
|
STATE_VACATION]
|
|
|
|
self._rf_address = rf_address
|
2018-04-19 07:11:38 +00:00
|
|
|
self._cubehandle = handler
|
2017-02-27 05:35:33 +00:00
|
|
|
|
2017-11-29 10:01:28 +00:00
|
|
|
@property
|
|
|
|
def supported_features(self):
|
|
|
|
"""Return the list of supported features."""
|
|
|
|
return SUPPORT_FLAGS
|
|
|
|
|
2017-02-27 05:35:33 +00:00
|
|
|
@property
|
|
|
|
def should_poll(self):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Return the polling state."""
|
2017-02-27 05:35:33 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Return the name of the climate device."""
|
2017-02-27 05:35:33 +00:00
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def min_temp(self):
|
|
|
|
"""Return the minimum temperature."""
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
return self.map_temperature_max_hass(device.min_temperature)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def max_temp(self):
|
|
|
|
"""Return the maximum temperature."""
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
return self.map_temperature_max_hass(device.max_temperature)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def temperature_unit(self):
|
|
|
|
"""Return the unit of measurement."""
|
2018-08-22 07:17:29 +00:00
|
|
|
return TEMP_CELSIUS
|
2017-02-27 05:35:33 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def current_temperature(self):
|
|
|
|
"""Return the current temperature."""
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
|
|
|
|
# Map and return current temperature
|
|
|
|
return self.map_temperature_max_hass(device.actual_temperature)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def current_operation(self):
|
|
|
|
"""Return current operation (auto, manual, boost, vacation)."""
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
return self.map_mode_max_hass(device.mode)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def operation_list(self):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Return the list of available operation modes."""
|
2017-02-27 05:35:33 +00:00
|
|
|
return self._operation_list
|
|
|
|
|
|
|
|
@property
|
|
|
|
def target_temperature(self):
|
|
|
|
"""Return the temperature we try to reach."""
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
return self.map_temperature_max_hass(device.target_temperature)
|
|
|
|
|
|
|
|
def set_temperature(self, **kwargs):
|
|
|
|
"""Set new target temperatures."""
|
|
|
|
if kwargs.get(ATTR_TEMPERATURE) is None:
|
|
|
|
return False
|
|
|
|
|
|
|
|
target_temperature = kwargs.get(ATTR_TEMPERATURE)
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
|
|
|
|
cube = self._cubehandle.cube
|
|
|
|
|
|
|
|
with self._cubehandle.mutex:
|
|
|
|
try:
|
|
|
|
cube.set_target_temperature(device, target_temperature)
|
|
|
|
except (socket.timeout, socket.error):
|
|
|
|
_LOGGER.error("Setting target temperature failed")
|
|
|
|
return False
|
|
|
|
|
|
|
|
def set_operation_mode(self, operation_mode):
|
|
|
|
"""Set new operation mode."""
|
|
|
|
device = self._cubehandle.cube.device_by_rf(self._rf_address)
|
|
|
|
mode = self.map_mode_hass_max(operation_mode)
|
|
|
|
|
|
|
|
if mode is None:
|
|
|
|
return False
|
|
|
|
|
|
|
|
with self._cubehandle.mutex:
|
|
|
|
try:
|
|
|
|
self._cubehandle.cube.set_mode(device, mode)
|
|
|
|
except (socket.timeout, socket.error):
|
|
|
|
_LOGGER.error("Setting operation mode failed")
|
|
|
|
return False
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
"""Get latest data from MAX! Cube."""
|
|
|
|
self._cubehandle.update()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def map_temperature_max_hass(temperature):
|
|
|
|
"""Map Temperature from MAX! to HASS."""
|
|
|
|
if temperature is None:
|
2017-07-17 21:34:38 +00:00
|
|
|
return 0.0
|
2017-02-27 05:35:33 +00:00
|
|
|
|
|
|
|
return temperature
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def map_mode_hass_max(operation_mode):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Map Home Assistant Operation Modes to MAX! Operation Modes."""
|
2017-02-27 05:35:33 +00:00
|
|
|
from maxcube.device import \
|
|
|
|
MAX_DEVICE_MODE_AUTOMATIC, \
|
|
|
|
MAX_DEVICE_MODE_MANUAL, \
|
|
|
|
MAX_DEVICE_MODE_VACATION, \
|
|
|
|
MAX_DEVICE_MODE_BOOST
|
|
|
|
|
|
|
|
if operation_mode == STATE_AUTO:
|
|
|
|
mode = MAX_DEVICE_MODE_AUTOMATIC
|
|
|
|
elif operation_mode == STATE_MANUAL:
|
|
|
|
mode = MAX_DEVICE_MODE_MANUAL
|
|
|
|
elif operation_mode == STATE_VACATION:
|
|
|
|
mode = MAX_DEVICE_MODE_VACATION
|
|
|
|
elif operation_mode == STATE_BOOST:
|
|
|
|
mode = MAX_DEVICE_MODE_BOOST
|
|
|
|
else:
|
|
|
|
mode = None
|
|
|
|
|
|
|
|
return mode
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def map_mode_max_hass(mode):
|
2017-04-30 05:04:49 +00:00
|
|
|
"""Map MAX! Operation Modes to Home Assistant Operation Modes."""
|
2017-02-27 05:35:33 +00:00
|
|
|
from maxcube.device import \
|
|
|
|
MAX_DEVICE_MODE_AUTOMATIC, \
|
|
|
|
MAX_DEVICE_MODE_MANUAL, \
|
|
|
|
MAX_DEVICE_MODE_VACATION, \
|
|
|
|
MAX_DEVICE_MODE_BOOST
|
|
|
|
|
|
|
|
if mode == MAX_DEVICE_MODE_AUTOMATIC:
|
|
|
|
operation_mode = STATE_AUTO
|
|
|
|
elif mode == MAX_DEVICE_MODE_MANUAL:
|
|
|
|
operation_mode = STATE_MANUAL
|
|
|
|
elif mode == MAX_DEVICE_MODE_VACATION:
|
|
|
|
operation_mode = STATE_VACATION
|
|
|
|
elif mode == MAX_DEVICE_MODE_BOOST:
|
|
|
|
operation_mode = STATE_BOOST
|
|
|
|
else:
|
|
|
|
operation_mode = None
|
|
|
|
|
|
|
|
return operation_mode
|