Expanded homematic component with MAX! support via homegear (#1783)

* Expanded homematic component with MAX! support via homegear
Also multithreading fixes

* fixed tox errors

* incorporate changes suggested by balloob

* replaced HomematicConfig Container Class with namedtuple

* fixed lint errors
This commit is contained in:
Markus Peter 2016-04-11 01:26:08 +02:00 committed by Paulus Schoutsen
parent 769d958464
commit fec45033bc

View File

@ -7,12 +7,17 @@ https://home-assistant.io/components/thermostat.homematic/
import logging import logging
import socket import socket
from xmlrpc.client import ServerProxy from xmlrpc.client import ServerProxy
from xmlrpc.client import Error
from collections import namedtuple
from homeassistant.components.thermostat import ThermostatDevice from homeassistant.components.thermostat import ThermostatDevice
from homeassistant.const import TEMP_CELCIUS from homeassistant.const import TEMP_CELCIUS
from homeassistant.helpers.temperature import convert
REQUIREMENTS = [] REQUIREMENTS = []
_LOGGER = logging.getLogger(__name__)
CONF_ADDRESS = 'address' CONF_ADDRESS = 'address'
CONF_DEVICES = 'devices' CONF_DEVICES = 'devices'
CONF_ID = 'id' CONF_ID = 'id'
@ -20,29 +25,59 @@ PROPERTY_SET_TEMPERATURE = 'SET_TEMPERATURE'
PROPERTY_VALVE_STATE = 'VALVE_STATE' PROPERTY_VALVE_STATE = 'VALVE_STATE'
PROPERTY_ACTUAL_TEMPERATURE = 'ACTUAL_TEMPERATURE' PROPERTY_ACTUAL_TEMPERATURE = 'ACTUAL_TEMPERATURE'
PROPERTY_BATTERY_STATE = 'BATTERY_STATE' PROPERTY_BATTERY_STATE = 'BATTERY_STATE'
PROPERTY_LOWBAT = 'LOWBAT'
PROPERTY_CONTROL_MODE = 'CONTROL_MODE' PROPERTY_CONTROL_MODE = 'CONTROL_MODE'
PROPERTY_BURST_MODE = 'BURST_RX'
TYPE_HM_THERMOSTAT = 'HOMEMATIC_THERMOSTAT'
TYPE_HM_WALLTHERMOSTAT = 'HOMEMATIC_WALLTHERMOSTAT'
TYPE_MAX_THERMOSTAT = 'MAX_THERMOSTAT'
_LOGGER = logging.getLogger(__name__) HomematicConfig = namedtuple('HomematicConfig',
['device_type',
'platform_type',
'channel',
'maint_channel'])
HM_TYPE_MAPPING = {
'HM-CC-RT-DN': HomematicConfig('HM-CC-RT-DN',
TYPE_HM_THERMOSTAT,
4, 4),
'HM-CC-RT-DN-BoM': HomematicConfig('HM-CC-RT-DN-BoM',
TYPE_HM_THERMOSTAT,
4, 4),
'HM-TC-IT-WM-W-EU': HomematicConfig('HM-TC-IT-WM-W-EU',
TYPE_HM_WALLTHERMOSTAT,
2, 2),
'BC-RT-TRX-CyG': HomematicConfig('BC-RT-TRX-CyG',
TYPE_MAX_THERMOSTAT,
1, 0),
'BC-RT-TRX-CyG-2': HomematicConfig('BC-RT-TRX-CyG-2',
TYPE_MAX_THERMOSTAT,
1, 0),
'BC-RT-TRX-CyG-3': HomematicConfig('BC-RT-TRX-CyG-3',
TYPE_MAX_THERMOSTAT,
1, 0)
}
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Homematic thermostat.""" """Setup the Homematic thermostat."""
devices = [] devices = []
try: try:
homegear = ServerProxy(config[CONF_ADDRESS]) address = config[CONF_ADDRESS]
homegear = ServerProxy(address)
for name, device_cfg in config[CONF_DEVICES].items(): for name, device_cfg in config[CONF_DEVICES].items():
# get device description to detect the type # get device description to detect the type
device_type = homegear.getDeviceDescription( device_type = homegear.getDeviceDescription(
device_cfg[CONF_ID] + ':-1')['TYPE'] device_cfg[CONF_ID] + ':-1')['TYPE']
if device_type in ['HM-CC-RT-DN', 'HM-CC-RT-DN-BoM']: if device_type in HM_TYPE_MAPPING.keys():
devices.append(HomematicThermostat(homegear, devices.append(HomematicThermostat(
device_cfg[CONF_ID], HM_TYPE_MAPPING[device_type],
name, 4)) address,
elif device_type == 'HM-TC-IT-WM-W-EU': device_cfg[CONF_ID],
devices.append(HomematicThermostat(homegear, name))
device_cfg[CONF_ID],
name, 2))
else: else:
raise ValueError( raise ValueError(
"Device Type '{}' currently not supported".format( "Device Type '{}' currently not supported".format(
@ -60,14 +95,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class HomematicThermostat(ThermostatDevice): class HomematicThermostat(ThermostatDevice):
"""Representation of a Homematic thermostat.""" """Representation of a Homematic thermostat."""
def __init__(self, device, _id, name, channel): def __init__(self, hm_config, address, _id, name):
"""Initialize the thermostat.""" """Initialize the thermostat."""
self.device = device self._hm_config = hm_config
self.address = address
self._id = _id self._id = _id
self._channel = channel
self._name = name self._name = name
self._full_device_name = '{}:{}'.format(self._id, self._channel) self._full_device_name = '{}:{}'.format(self._id,
self._hm_config.channel)
self._maint_device_name = '{}:{}'.format(self._id,
self._hm_config.maint_channel)
self._current_temperature = None self._current_temperature = None
self._target_temperature = None self._target_temperature = None
self._valve = None self._valve = None
@ -97,9 +134,10 @@ class HomematicThermostat(ThermostatDevice):
def set_temperature(self, temperature): def set_temperature(self, temperature):
"""Set new target temperature.""" """Set new target temperature."""
self.device.setValue(self._full_device_name, device = ServerProxy(self.address)
PROPERTY_SET_TEMPERATURE, device.setValue(self._full_device_name,
temperature) PROPERTY_SET_TEMPERATURE,
temperature)
@property @property
def device_state_attributes(self): def device_state_attributes(self):
@ -108,21 +146,49 @@ class HomematicThermostat(ThermostatDevice):
"battery": self._battery, "battery": self._battery,
"mode": self._mode} "mode": self._mode}
@property
def min_temp(self):
"""Return the minimum temperature - 4.5 means off."""
return convert(4.5, TEMP_CELCIUS, self.unit_of_measurement)
@property
def max_temp(self):
"""Return the maximum temperature - 30.5 means on."""
return convert(30.5, TEMP_CELCIUS, self.unit_of_measurement)
def update(self): def update(self):
"""Update the data from the thermostat.""" """Update the data from the thermostat."""
try: try:
self._current_temperature = self.device.getValue( device = ServerProxy(self.address)
self._current_temperature = device.getValue(
self._full_device_name, self._full_device_name,
PROPERTY_ACTUAL_TEMPERATURE) PROPERTY_ACTUAL_TEMPERATURE)
self._target_temperature = self.device.getValue( self._target_temperature = device.getValue(
self._full_device_name, self._full_device_name,
PROPERTY_SET_TEMPERATURE) PROPERTY_SET_TEMPERATURE)
self._valve = self.device.getValue(self._full_device_name, self._valve = device.getValue(
PROPERTY_VALVE_STATE) self._full_device_name,
self._battery = self.device.getValue(self._full_device_name, PROPERTY_VALVE_STATE)
PROPERTY_BATTERY_STATE) self._mode = device.getValue(
self._mode = self.device.getValue(self._full_device_name, self._full_device_name,
PROPERTY_CONTROL_MODE) PROPERTY_CONTROL_MODE)
except socket.error:
if self._hm_config.platform_type in [TYPE_HM_THERMOSTAT,
TYPE_HM_WALLTHERMOSTAT]:
self._battery = device.getValue(self._maint_device_name,
PROPERTY_BATTERY_STATE)
elif self._hm_config.platform_type == TYPE_MAX_THERMOSTAT:
# emulate homematic battery voltage,
# max reports lowbat if voltage < 2.2V
# while homematic battery_state should
# be between 1.5V and 4.6V
lowbat = device.getValue(self._maint_device_name,
PROPERTY_LOWBAT)
if lowbat:
self._battery = 1.5
else:
self._battery = 4.6
except Error:
_LOGGER.exception("Did not receive any temperature data from the " _LOGGER.exception("Did not receive any temperature data from the "
"homematic API.") "homematic API.")