Skip to content

Commit

Permalink
Add HassClimateSetTemperature (home-assistant#136484)
Browse files Browse the repository at this point in the history
* Add HassClimateSetTemperature

* Use single target constraint
  • Loading branch information
synesthesiam authored Jan 27, 2025
1 parent 58b4556 commit b633a04
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 3 deletions.
1 change: 1 addition & 0 deletions homeassistant/components/climate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
FAN_TOP,
HVAC_MODES,
INTENT_GET_TEMPERATURE,
INTENT_SET_TEMPERATURE,
PRESET_ACTIVITY,
PRESET_AWAY,
PRESET_BOOST,
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/climate/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class HVACAction(StrEnum):
DOMAIN = "climate"

INTENT_GET_TEMPERATURE = "HassClimateGetTemperature"
INTENT_SET_TEMPERATURE = "HassClimateSetTemperature"

SERVICE_SET_AUX_HEAT = "set_aux_heat"
SERVICE_SET_FAN_MODE = "set_fan_mode"
Expand Down
94 changes: 92 additions & 2 deletions homeassistant/components/climate/intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@

import voluptuous as vol

from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import intent
from homeassistant.helpers import config_validation as cv, intent

from . import DOMAIN, INTENT_GET_TEMPERATURE
from . import (
ATTR_TEMPERATURE,
DOMAIN,
INTENT_GET_TEMPERATURE,
INTENT_SET_TEMPERATURE,
SERVICE_SET_TEMPERATURE,
ClimateEntityFeature,
)


async def async_setup_intents(hass: HomeAssistant) -> None:
"""Set up the climate intents."""
intent.async_register(hass, GetTemperatureIntent())
intent.async_register(hass, SetTemperatureIntent())


class GetTemperatureIntent(intent.IntentHandler):
Expand Down Expand Up @@ -52,3 +61,84 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse
response.response_type = intent.IntentResponseType.QUERY_ANSWER
response.async_set_states(matched_states=match_result.states)
return response


class SetTemperatureIntent(intent.IntentHandler):
"""Handle SetTemperature intents."""

intent_type = INTENT_SET_TEMPERATURE
description = "Sets the target temperature of a climate device or entity"
slot_schema = {
vol.Required("temperature"): vol.Coerce(float),
vol.Optional("area"): intent.non_empty_string,
vol.Optional("name"): intent.non_empty_string,
vol.Optional("floor"): intent.non_empty_string,
vol.Optional("preferred_area_id"): cv.string,
vol.Optional("preferred_floor_id"): cv.string,
}
platforms = {DOMAIN}

async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
"""Handle the intent."""
hass = intent_obj.hass
slots = self.async_validate_slots(intent_obj.slots)

temperature: float = slots["temperature"]["value"]

name: str | None = None
if "name" in slots:
name = slots["name"]["value"]

area_name: str | None = None
if "area" in slots:
area_name = slots["area"]["value"]

floor_name: str | None = None
if "floor" in slots:
floor_name = slots["floor"]["value"]

match_constraints = intent.MatchTargetsConstraints(
name=name,
area_name=area_name,
floor_name=floor_name,
domains=[DOMAIN],
assistant=intent_obj.assistant,
features=ClimateEntityFeature.TARGET_TEMPERATURE,
single_target=True,
)
match_preferences = intent.MatchTargetsPreferences(
area_id=slots.get("preferred_area_id", {}).get("value"),
floor_id=slots.get("preferred_floor_id", {}).get("value"),
)
match_result = intent.async_match_targets(
hass, match_constraints, match_preferences
)
if not match_result.is_match:
raise intent.MatchFailedError(
result=match_result, constraints=match_constraints
)

assert match_result.states
climate_state = match_result.states[0]

await hass.services.async_call(
DOMAIN,
SERVICE_SET_TEMPERATURE,
service_data={ATTR_TEMPERATURE: temperature},
target={ATTR_ENTITY_ID: climate_state.entity_id},
blocking=True,
)

response = intent_obj.create_response()
response.response_type = intent.IntentResponseType.ACTION_DONE
response.async_set_results(
success_results=[
intent.IntentResponseTarget(
type=intent.IntentResponseTargetType.ENTITY,
name=climate_state.name,
id=climate_state.entity_id,
)
]
)
response.async_set_states(matched_states=[climate_state])
return response
Loading

0 comments on commit b633a04

Please sign in to comment.