* Add MySensors ACK The addition of the ACK will ask sensors to respond to commands sent to them which will update the MySensors device in Home Assistant. Currently, if a default MySensors sketch is used the device will update but Home Assistant does not reflect the update and custom code has to be added to tell Home Assistant the command was received. With the ACK set to 1 in the message all this is taken care of by MySensors. * Run black
195 lines
6.7 KiB
Python
195 lines
6.7 KiB
Python
"""MySensors platform that offers a Climate (MySensors-HVAC) component."""
|
|
from homeassistant.components import mysensors
|
|
from homeassistant.components.climate import ClimateDevice
|
|
from homeassistant.components.climate.const import (
|
|
ATTR_TARGET_TEMP_HIGH,
|
|
ATTR_TARGET_TEMP_LOW,
|
|
DOMAIN,
|
|
HVAC_MODE_AUTO,
|
|
HVAC_MODE_COOL,
|
|
HVAC_MODE_HEAT,
|
|
SUPPORT_FAN_MODE,
|
|
SUPPORT_TARGET_TEMPERATURE,
|
|
SUPPORT_TARGET_TEMPERATURE_RANGE,
|
|
HVAC_MODE_OFF,
|
|
)
|
|
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
|
|
|
DICT_HA_TO_MYS = {
|
|
HVAC_MODE_AUTO: "AutoChangeOver",
|
|
HVAC_MODE_COOL: "CoolOn",
|
|
HVAC_MODE_HEAT: "HeatOn",
|
|
HVAC_MODE_OFF: "Off",
|
|
}
|
|
DICT_MYS_TO_HA = {
|
|
"AutoChangeOver": HVAC_MODE_AUTO,
|
|
"CoolOn": HVAC_MODE_COOL,
|
|
"HeatOn": HVAC_MODE_HEAT,
|
|
"Off": HVAC_MODE_OFF,
|
|
}
|
|
|
|
FAN_LIST = ["Auto", "Min", "Normal", "Max"]
|
|
OPERATION_LIST = [HVAC_MODE_OFF, HVAC_MODE_AUTO, HVAC_MODE_COOL, HVAC_MODE_HEAT]
|
|
|
|
|
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
|
"""Set up the mysensors climate."""
|
|
mysensors.setup_mysensors_platform(
|
|
hass,
|
|
DOMAIN,
|
|
discovery_info,
|
|
MySensorsHVAC,
|
|
async_add_entities=async_add_entities,
|
|
)
|
|
|
|
|
|
class MySensorsHVAC(mysensors.device.MySensorsEntity, ClimateDevice):
|
|
"""Representation of a MySensors HVAC."""
|
|
|
|
@property
|
|
def supported_features(self):
|
|
"""Return the list of supported features."""
|
|
features = 0
|
|
set_req = self.gateway.const.SetReq
|
|
if set_req.V_HVAC_SPEED in self._values:
|
|
features = features | SUPPORT_FAN_MODE
|
|
if (
|
|
set_req.V_HVAC_SETPOINT_COOL in self._values
|
|
and set_req.V_HVAC_SETPOINT_HEAT in self._values
|
|
):
|
|
features = features | SUPPORT_TARGET_TEMPERATURE_RANGE
|
|
else:
|
|
features = features | SUPPORT_TARGET_TEMPERATURE
|
|
return features
|
|
|
|
@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."""
|
|
value = self._values.get(self.gateway.const.SetReq.V_TEMP)
|
|
|
|
if value is not None:
|
|
value = float(value)
|
|
|
|
return value
|
|
|
|
@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) if temp is not None else None
|
|
|
|
@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:
|
|
temp = self._values.get(set_req.V_HVAC_SETPOINT_COOL)
|
|
return float(temp) if temp is not None else None
|
|
|
|
@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:
|
|
temp = self._values.get(set_req.V_HVAC_SETPOINT_HEAT)
|
|
return float(temp) if temp is not None else None
|
|
|
|
@property
|
|
def hvac_mode(self):
|
|
"""Return current operation ie. heat, cool, idle."""
|
|
return self._values.get(self.value_type)
|
|
|
|
@property
|
|
def hvac_modes(self):
|
|
"""List of available operation modes."""
|
|
return OPERATION_LIST
|
|
|
|
@property
|
|
def fan_mode(self):
|
|
"""Return the fan setting."""
|
|
return self._values.get(self.gateway.const.SetReq.V_HVAC_SPEED)
|
|
|
|
@property
|
|
def fan_modes(self):
|
|
"""List of available fan modes."""
|
|
return FAN_LIST
|
|
|
|
async def async_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, ack=1
|
|
)
|
|
if self.gateway.optimistic:
|
|
# Optimistically assume that device has changed state
|
|
self._values[value_type] = value
|
|
self.async_schedule_update_ha_state()
|
|
|
|
async def async_set_fan_mode(self, fan_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_SPEED, fan_mode, ack=1
|
|
)
|
|
if self.gateway.optimistic:
|
|
# Optimistically assume that device has changed state
|
|
self._values[set_req.V_HVAC_SPEED] = fan_mode
|
|
self.async_schedule_update_ha_state()
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode):
|
|
"""Set new target temperature."""
|
|
self.gateway.set_child_value(
|
|
self.node_id,
|
|
self.child_id,
|
|
self.value_type,
|
|
DICT_HA_TO_MYS[hvac_mode],
|
|
ack=1,
|
|
)
|
|
if self.gateway.optimistic:
|
|
# Optimistically assume that device has changed state
|
|
self._values[self.value_type] = hvac_mode
|
|
self.async_schedule_update_ha_state()
|
|
|
|
async def async_update(self):
|
|
"""Update the controller with the latest value from a sensor."""
|
|
await super().async_update()
|
|
self._values[self.value_type] = DICT_MYS_TO_HA[self._values[self.value_type]]
|