Skip to content

Commit

Permalink
add support for emergency heat mode through a climate entity preset (#27
Browse files Browse the repository at this point in the history
)
  • Loading branch information
zlangbert authored Feb 18, 2024
1 parent ee7853e commit 90eb6c2
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 2 deletions.
47 changes: 46 additions & 1 deletion custom_components/daikinone/climate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from enum import Enum
import logging
from typing import Callable

Expand Down Expand Up @@ -50,6 +51,11 @@ async def async_setup_entry(
async_add_entities(entities, True)


class DaikinOneThermostatPresetMode(Enum):
NONE = "none"
EMERGENCY_HEAT = "emergency_heat"


class DaikinOneThermostat(ClimateEntity):
"""Thermostat entity for Daikin One"""

Expand All @@ -71,6 +77,7 @@ def __init__(
self._data = data
self._thermostat = thermostat

self._attr_translation_key = "daikinone_thermostat"
self._attr_unique_id = f"{self._thermostat.id}-climate"
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_supported_features = (
Expand All @@ -79,14 +86,15 @@ def __init__(
| ClimateEntityFeature.TARGET_TEMPERATURE
| ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
self._attr_hvac_modes = self.get_hvac_modes()

self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self._thermostat.id)},
name=f"{self._thermostat.name} Thermostat",
manufacturer=MANUFACTURER,
model=self._thermostat.model,
sw_version=self._thermostat.firmware_version,
)
self._attr_hvac_modes = self.get_hvac_modes()

# These attributes must be initialized otherwise HA `CachedProperties` doesn't create a
# backing prop. If they are not initialized, climate will error during setup because we support
Expand All @@ -96,6 +104,15 @@ def __init__(
self._attr_target_temperature_low = None
self._attr_target_temperature_high = None

# Set up preset modes based on thermostat capabilities. The preset climate feature will only be
# enabled if at least one preset is detected as supported.
self._attr_preset_modes = [DaikinOneThermostatPresetMode.NONE.value]
self._attr_preset_mode = None

if DaikinThermostatCapability.EMERGENCY_HEAT in self._thermostat.capabilities:
self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE
self._attr_preset_modes += [DaikinOneThermostatPresetMode.EMERGENCY_HEAT.value]

def get_hvac_modes(self) -> list[HVACMode]:
modes: list[HVACMode] = []

Expand Down Expand Up @@ -129,6 +146,9 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
case _:
raise ValueError(f"Attempted to set unsupported HVAC mode: {hvac_mode}")

await self.set_thermostat_mode(target_mode)

async def set_thermostat_mode(self, target_mode: DaikinThermostatMode) -> None:
log.debug("Setting thermostat mode to %s", target_mode)

# update thermostat mode
Expand All @@ -143,6 +163,28 @@ def update(t: DaikinThermostat):
check=lambda t: t.mode == target_mode,
)

async def async_set_preset_mode(self, preset_mode: str):
"""Set new target preset mode."""
match preset_mode:

case DaikinOneThermostatPresetMode.EMERGENCY_HEAT.value:
await self.set_thermostat_mode(DaikinThermostatMode.AUX_HEAT)

case DaikinOneThermostatPresetMode.NONE.value:
match self._thermostat.mode:

# turning off emergency heat should set the thermostat mode to heat
case DaikinThermostatMode.AUX_HEAT:
await self.set_thermostat_mode(DaikinThermostatMode.HEAT)

# any other thermostat mode should already be "none", and if its not,
# we don't need to do anything
case _:
pass

case _:
raise ValueError(f"Attempted to set unsupported preset mode: {preset_mode}")

async def async_set_temperature(self, **kwargs: float) -> None:
"""Set new target temperature(s)."""

Expand Down Expand Up @@ -232,6 +274,8 @@ def update_entity_attributes(self) -> None:
self._attr_current_temperature = self._thermostat.indoor_temperature.celsius
self._attr_current_humidity = self._thermostat.indoor_humidity

# hvac current mode and preset
self._attr_preset_mode = DaikinOneThermostatPresetMode.NONE.value
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
self._attr_hvac_mode = HVACMode.HEAT_COOL
Expand All @@ -241,6 +285,7 @@ def update_entity_attributes(self) -> None:
self._attr_hvac_mode = HVACMode.COOL
case DaikinThermostatMode.AUX_HEAT:
self._attr_hvac_mode = HVACMode.HEAT
self._attr_preset_mode = DaikinOneThermostatPresetMode.EMERGENCY_HEAT.value
case DaikinThermostatMode.OFF:
self._attr_hvac_mode = HVACMode.OFF

Expand Down
3 changes: 3 additions & 0 deletions custom_components/daikinone/daikinone.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class DaikinEEVCoil(DaikinEquipment):
class DaikinThermostatCapability(Enum):
HEAT = auto()
COOL = auto()
EMERGENCY_HEAT = auto()


class DaikinThermostatMode(Enum):
Expand Down Expand Up @@ -252,6 +253,8 @@ def __map_thermostat(self, payload: DaikinDeviceDataResponse) -> DaikinThermosta
capabilities.add(DaikinThermostatCapability.HEAT)
if payload.data["ctSystemCapCool"]:
capabilities.add(DaikinThermostatCapability.COOL)
if payload.data["ctSystemCapEmergencyHeat"]:
capabilities.add(DaikinThermostatCapability.EMERGENCY_HEAT)

schedule = DaikinThermostatSchedule(enabled=payload.data["schedEnabled"])

Expand Down
15 changes: 14 additions & 1 deletion custom_components/daikinone/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,18 @@
"error": {
"auth_failed": "Authentication failed, please check your credentials and try again. Check the logs for more info."
}
},
"entity": {
"climate": {
"daikinone_thermostat": {
"state_attributes": {
"preset_mode": {
"state": {
"emergency_heat": "Emergency Heat"
}
}
}
}
}
}
}
}

0 comments on commit 90eb6c2

Please sign in to comment.