Having an issue with a custom intent for setting thermostat temperature via assist

I’m trying to set up a custom intent so that I can use assist to set the temperature of an area. The areas have generic thermostats in them.

I have a custom_sentences/en/climate.yaml:

language: "en"
intents:
  SetTemperature:
    data:
      - sentences:
          - "(set|change) {area} temperature to {temperature} [degrees]"
          - "(set|change) [the] temperature to [the] {area} to {temperature} [degrees]"
lists:
  area:
    values:
      - in: "Family Room"
        out: "family_room"
      - in: "Main Office"
        out: "main_office"

Inside my configuration.yaml I have:

intent_script:
  SetTemperature:
    action:
      - service: "climate.set_temperature"
        data:
          temperature: "{{temperature}}"
        target:
          area_id: "{{area}}"
    speech:
      text: "Temperature of the {{area}} has been set to {{temperature}} degrees."

It is my understanding that in the custom sentences config, if area equals “Family Room”, it will replace it with “family_room”, which is the ID of my family room area. The same goes for if area equals “Main Office”.

The variables are successfully being passed to the intent_script: in configuration.yaml. However, it’s not quite working as intended. First, it’s not setting the temperature of the thermostat in that area. Second, the response text is coming back wrong.

Say I were to put in: “Set the Family Room temperature to 70 degrees”
I get the response: “Temperature of the Family Room has been set to 70 degrees.”

This tells me that the data is successfully being handed off. Both variables are getting handed off, but it’s not converting “Family Room” to “family_room” before they do (I know it doesn’t make sense to have the unfriendly area_id in the response, and I realized that after doing this. But it did help me see what was going on here.) Since it’s not converting the value to what the intent_script: is looking for (family_room), that explains why it’s not working.

For testing, I hard coded “family_room” for the area_id under intent_script and tried again. This time it did successfully set the temperature of the generic thermostat in the Family Room area. Of course, with this setup it’s going to set the temperature of the Family Room and only the Family Room no matter what I say, but it helped me confirm that it does work. I just need to figure out why it’s not converting. What am I misunderstanding here?

Don’t you need to specify list name and value like area.area. It’s been a while since I messed around with intent scripts so I might be mistaken.

Also, double check that providing family_room is actually working, services usually expect the actual area ID which can be retrieved using {{ area_id(area) }}.

I was just following the article dealing with custom sentences here for my list formatting.

In the intent_script, under the target, I did directly assign “family_room” to the area_id for testing, and it did successfully change the temperature of the thermostat in the family room.

I have also tried setting the “out” of “Family Room” in the list to the entity ID of the thermostat itself So…

In the custom sentences config.

intents:
  SetTemperature:
    data:
      - sentences:
          - "(set|change) {area} temperature to {temperature} [degrees]"
          - "(set|change) [the] temperature to [the] {area} to {temperature} [degrees]"
lists:
  area:
    values:
      - in: "Family Room"
        out: "climate.family_room"

I then had the intent_script target an entity ID instead of the area ID

intent_script:
  SetTemperature:
    action:
      - service: "climate.set_temperature"
        data:
          temperature: "{{temperature}}"
        target:
          entity_id: "{{area}}"   # this contans an entity ID now even though the variable is called "area"
    speech:
      text: "Temperature of the {{area}} has been set to {{temperature}} degrees."

Still no luck with that.

Have you tested the intent in the Assist dev tool? What does it return?

I did mess around with that a little bit. I noticed that it looks like it’s matching the family room area by its friendly name and listing all of the devices that are in the area as a match.

Since it’s detecting “Family Room” in the sentence as a match to an actual area, could that be somehow preventing the list from changing the output to “family_room”?

I think at least part of the problem is that you are using area as your variable, but there is already a shared function that dictates how to handle that variable. The following is working for me:

#climate_intent.yaml
language: "en"
intents:
  SetTemperature:
    data:
      - sentences:
          - "(set|change) [the] {area} temperature to {temperature} [degrees]"
          - "(set|change) [the] temperature [in] [the] {area} to {temperature} [degrees]"
intent_script:
  SetTemperature:
    action:
      - service: "climate.set_temperature"
        data:
          temperature: "{{temperature}}"
        target:
          area_id: "{{ area_id(area) }}"
    speech:
      text: "Temperature of the {{area}} has been set to {{temperature}} degrees."

Before the 2024.06 update, {area} returned the id value, now we get the name. Therefore, the old instructions can be misleading. Use area_id(area) as you were advised earlier.

Ah! I didn’t know that “area” was used elsewhere. I should have known that. Simply changing the variable from “area” to “room” fixed the whole thing in the state I had it currently in. In the speech text, I then replaced {{area}} with {{area_id(area)}} that that returned back the friendly name for the read back text.

I am curious how HA determines that it is to set the temperature of the thermostat in an area just by specifying the area and not the entity directly. The reason I want to know is because now I want to do another thing. HA already has a built-in intent that will tell you the temperature of a room when asked without you having to specify the device itself. I just knows the temperature because there’s a device in that area reporting it. I want to be able to ask what the “set” temperature of a room is, which it currently doesn’t do. How would I go about querying the thermostat’s target temperature without querying the device itself, but instead the area that it is in?

The generic thermostat has two attributes pertaining to temperature. “temperature”, which is what it is set to and “current_temperature” which is shockingly the current temperature it’s sensing.

When asking for the temperature of an area, HA must somehow be pulling the value of “current_temperature” of the generic thermostat in the area. I think if I knew how it pulled that, I would be able to figure out how to pull the set “temperature” attribute in my custom intent.

I was able to get it to work by changing my “area” variable to “room” without having to make any other changes other than in the response text to give the friendly name. {{area_name(room)}}

You have a slightly complicated way of solving standard tasks. But if everything works for you, then you can use your option.

Filters are used to select an entity or attributes in the area.

{{ states.sensor|selectattr('attributes.device_class', 'defined')|selectattr('attributes.device_class', 'eq', 'temperature')|selectattr('entity_id', 'in', area_entities(area))|map(attribute='state')|min }}

This is my example of finding the minimum temperature in a room. The {area} variable is used here.
You can experiment with filter values or add additional ones to get the desired result.

Now knowing that “area” is a built-in list of all areas, I might rewrite the intent for setting temperature to use that.

The filter you gave me seems to have picked up the temperature entity in the room, but not the generic thermostat. I’ll play around with that and see what I can come up with.
Thanks

The filter provided above only looks at sensor entities, you need to use something like the following to get the temperature attribute’s value from your climate entity:

{{ states.climate | selectattr('entity_id', 'in', area_entities(area))
| map(attribute='attributes.temperature') | first }}

That did it. I was able to set up the sentence and get the desired response using

text: "{{ area_name(room) }} is set to {{ states.climate | selectattr('entity_id', 'in', area_entities(room))| map(attribute='attributes.temperature') | first }} degrees."

Knowing what I know thanks the information you guys have provided, I think I am going to go back to using ‘area’ instead of ‘room’ since now I understand that ‘area’ is already an existing list of area names, and it seems there are ways reference those areas via the names rather than area_ids.