mirror of
https://github.com/home-assistant/core.git
synced 2025-04-30 20:27:57 +00:00

In trying to come up for some reason behind issue #6365 (which only happens on some platforms) the best guess is that some components are managing to get a string value all the way up to the Polymer UI for temperature, which then an increment of +0.5 is treating as a string concat operation instead of addition. So 20 + 0.5 becomes 200.5 hits the max thermostat value. This will throw an exception if the climate temp value isn't a number. That's going to turn a soft fail into a hard fail on potentially a number of platforms. Mysensors is one of the platforms that was reported as having the issue. So put some explicit float casts where that might be coming from as well.
205 lines
7.3 KiB
Python
Executable File
205 lines
7.3 KiB
Python
Executable File
"""
|
|
MySensors platform that offers a Climate (MySensors-HVAC) component.
|
|
|
|
For more details about this platform, please refer to the documentation
|
|
https://home-assistant.io/components/climate.mysensors/
|
|
"""
|
|
import logging
|
|
|
|
from homeassistant.components import mysensors
|
|
from homeassistant.components.climate import (
|
|
STATE_COOL, STATE_HEAT, STATE_OFF, STATE_AUTO, ClimateDevice,
|
|
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW)
|
|
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
DICT_HA_TO_MYS = {
|
|
STATE_AUTO: 'AutoChangeOver',
|
|
STATE_COOL: 'CoolOn',
|
|
STATE_HEAT: 'HeatOn',
|
|
STATE_OFF: 'Off',
|
|
}
|
|
DICT_MYS_TO_HA = {
|
|
'AutoChangeOver': STATE_AUTO,
|
|
'CoolOn': STATE_COOL,
|
|
'HeatOn': STATE_HEAT,
|
|
'Off': STATE_OFF,
|
|
}
|
|
|
|
|
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
|
"""Set up the mysensors climate."""
|
|
if discovery_info is None:
|
|
return
|
|
|
|
gateways = hass.data.get(mysensors.MYSENSORS_GATEWAYS)
|
|
if not gateways:
|
|
return
|
|
|
|
for gateway in gateways:
|
|
if float(gateway.protocol_version) < 1.5:
|
|
continue
|
|
pres = gateway.const.Presentation
|
|
set_req = gateway.const.SetReq
|
|
map_sv_types = {
|
|
pres.S_HVAC: [set_req.V_HVAC_FLOW_STATE],
|
|
}
|
|
devices = {}
|
|
gateway.platform_callbacks.append(mysensors.pf_callback_factory(
|
|
map_sv_types, devices, MySensorsHVAC, add_devices))
|
|
|
|
|
|
class MySensorsHVAC(mysensors.MySensorsDeviceEntity, ClimateDevice):
|
|
"""Representation of a MySensors HVAC."""
|
|
|
|
@property
|
|
def assumed_state(self):
|
|
"""Return True if unable to access real state of entity."""
|
|
return self.gateway.optimistic
|
|
|
|
@property
|
|
def temperature_unit(self):
|
|
"""Return the unit of measurement."""
|
|
return (TEMP_CELSIUS
|
|
if self.gateway.metric else TEMP_FAHRENHEIT)
|
|
|
|
@property
|
|
def current_temperature(self):
|
|
"""Return the current temperature."""
|
|
return float(self._values.get(self.gateway.const.SetReq.V_TEMP))
|
|
|
|
@property
|
|
def target_temperature(self):
|
|
"""Return the temperature we try to reach."""
|
|
set_req = self.gateway.const.SetReq
|
|
if set_req.V_HVAC_SETPOINT_COOL in self._values and \
|
|
set_req.V_HVAC_SETPOINT_HEAT in self._values:
|
|
return None
|
|
temp = self._values.get(set_req.V_HVAC_SETPOINT_COOL)
|
|
if temp is None:
|
|
temp = self._values.get(set_req.V_HVAC_SETPOINT_HEAT)
|
|
return float(temp)
|
|
|
|
@property
|
|
def target_temperature_high(self):
|
|
"""Return the highbound target temperature we try to reach."""
|
|
set_req = self.gateway.const.SetReq
|
|
if set_req.V_HVAC_SETPOINT_HEAT in self._values:
|
|
return float(self._values.get(set_req.V_HVAC_SETPOINT_COOL))
|
|
|
|
@property
|
|
def target_temperature_low(self):
|
|
"""Return the lowbound target temperature we try to reach."""
|
|
set_req = self.gateway.const.SetReq
|
|
if set_req.V_HVAC_SETPOINT_COOL in self._values:
|
|
return float(self._values.get(set_req.V_HVAC_SETPOINT_HEAT))
|
|
|
|
@property
|
|
def current_operation(self):
|
|
"""Return current operation ie. heat, cool, idle."""
|
|
return self._values.get(self.gateway.const.SetReq.V_HVAC_FLOW_STATE)
|
|
|
|
@property
|
|
def operation_list(self):
|
|
"""List of available operation modes."""
|
|
return [STATE_OFF, STATE_AUTO, STATE_COOL, STATE_HEAT]
|
|
|
|
@property
|
|
def current_fan_mode(self):
|
|
"""Return the fan setting."""
|
|
return self._values.get(self.gateway.const.SetReq.V_HVAC_SPEED)
|
|
|
|
@property
|
|
def fan_list(self):
|
|
"""List of available fan modes."""
|
|
return ['Auto', 'Min', 'Normal', 'Max']
|
|
|
|
def set_temperature(self, **kwargs):
|
|
"""Set new target temperature."""
|
|
set_req = self.gateway.const.SetReq
|
|
temp = kwargs.get(ATTR_TEMPERATURE)
|
|
low = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
|
high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
|
|
heat = self._values.get(set_req.V_HVAC_SETPOINT_HEAT)
|
|
cool = self._values.get(set_req.V_HVAC_SETPOINT_COOL)
|
|
updates = ()
|
|
if temp is not None:
|
|
if heat is not None:
|
|
# Set HEAT Target temperature
|
|
value_type = set_req.V_HVAC_SETPOINT_HEAT
|
|
elif cool is not None:
|
|
# Set COOL Target temperature
|
|
value_type = set_req.V_HVAC_SETPOINT_COOL
|
|
if heat is not None or cool is not None:
|
|
updates = [(value_type, temp)]
|
|
elif all(val is not None for val in (low, high, heat, cool)):
|
|
updates = [
|
|
(set_req.V_HVAC_SETPOINT_HEAT, low),
|
|
(set_req.V_HVAC_SETPOINT_COOL, high)]
|
|
for value_type, value in updates:
|
|
self.gateway.set_child_value(
|
|
self.node_id, self.child_id, value_type, value)
|
|
if self.gateway.optimistic:
|
|
# optimistically assume that switch has changed state
|
|
self._values[value_type] = value
|
|
self.schedule_update_ha_state()
|
|
|
|
def set_fan_mode(self, fan):
|
|
"""Set new target temperature."""
|
|
set_req = self.gateway.const.SetReq
|
|
self.gateway.set_child_value(
|
|
self.node_id, self.child_id, set_req.V_HVAC_SPEED, fan)
|
|
if self.gateway.optimistic:
|
|
# optimistically assume that switch has changed state
|
|
self._values[set_req.V_HVAC_SPEED] = fan
|
|
self.schedule_update_ha_state()
|
|
|
|
def set_operation_mode(self, operation_mode):
|
|
"""Set new target temperature."""
|
|
set_req = self.gateway.const.SetReq
|
|
self.gateway.set_child_value(
|
|
self.node_id, self.child_id, set_req.V_HVAC_FLOW_STATE,
|
|
DICT_HA_TO_MYS[operation_mode])
|
|
if self.gateway.optimistic:
|
|
# optimistically assume that switch has changed state
|
|
self._values[set_req.V_HVAC_FLOW_STATE] = operation_mode
|
|
self.schedule_update_ha_state()
|
|
|
|
def update(self):
|
|
"""Update the controller with the latest value from a sensor."""
|
|
set_req = self.gateway.const.SetReq
|
|
node = self.gateway.sensors[self.node_id]
|
|
child = node.children[self.child_id]
|
|
for value_type, value in child.values.items():
|
|
_LOGGER.debug(
|
|
"%s: value_type %s, value = %s", self._name, value_type, value)
|
|
if value_type == set_req.V_HVAC_FLOW_STATE:
|
|
self._values[value_type] = DICT_MYS_TO_HA[value]
|
|
else:
|
|
self._values[value_type] = value
|
|
|
|
def set_humidity(self, humidity):
|
|
"""Set new target humidity."""
|
|
_LOGGER.error("Service Not Implemented yet")
|
|
|
|
def set_swing_mode(self, swing_mode):
|
|
"""Set new target swing operation."""
|
|
_LOGGER.error("Service Not Implemented yet")
|
|
|
|
def turn_away_mode_on(self):
|
|
"""Turn away mode on."""
|
|
_LOGGER.error("Service Not Implemented yet")
|
|
|
|
def turn_away_mode_off(self):
|
|
"""Turn away mode off."""
|
|
_LOGGER.error("Service Not Implemented yet")
|
|
|
|
def turn_aux_heat_on(self):
|
|
"""Turn auxillary heater on."""
|
|
_LOGGER.error("Service Not Implemented yet")
|
|
|
|
def turn_aux_heat_off(self):
|
|
"""Turn auxillary heater off."""
|
|
_LOGGER.error("Service Not Implemented yet")
|