I just want to share my experience with creating custom voice commands in Home assistant.
I have two ceiling fans in my living room, that I wanted to control with voice commands, not only to turn them ON or OFF but also to set their speed. These fans can be set to: OFF, LOW, MEDIUM or HIGH speed. I searched for a pre-made solution using voice preview for this but found none that worked well, so I decided to try my hand at creating my own basic custom voice commands to accomplish just that.
My fans used to have a control module with remote but no wifi capability, so I replaced them with these:
which can be controlled in Home Assistant through the TUYA integration.
(BTW, I recommend installing the “Fan percent button row” card plugin through HACS to control these or similar fans from a dashboard as it creates a very neat and responsive interface that takes up very little screen space. KUDOS to the author!: finity69x2 · GitHub)
In order to make this work, you only need to:
- create one new file to house the voice command structure and,
- add an (intent:/intent_script) entry in your configuration.yml file.
Step by step, it looks like this:
1 - If you don’t have any custom intents already in your system, you will need to create a new directory under /config/ (i.e. the same level as your configuration.yaml file). The directory must be named “custom_sentences”. This is easily done using File Editor or Studio Code Server.
2 - under this directory, create a sub-directory named “en” so as to get the following path:/custom_sentences/en/
3 - Then, create a new yaml file in it with a name of your choosing. the name itself is not important because home assistant automatically parses the files included in this directory. In my case the name I chose is: “fan_control.yaml”
4 - Paste the following in it and save:
language: "en"
intents:
SetFanSpeed:
data:
- sentences:
- "set {fan_name} to {speed}"
- "turn {fan_name} to {speed}"
- "change {fan_name} speed to {speed}"
- "{fan_name} {speed}"
lists:
fan_name:
values:
- in: "ceiling fan 1"
out: "ceiling fan a"
- in: "fan 1"
out: "ceiling fan a"
- in: "ceiling fan a"
out: "ceiling fan a"
- in: "fan a"
out: "ceiling fan a"
- in: "ceiling fan 2"
out: "ceiling fan b"
- in: "fan 2"
out: "ceiling fan b"
- in: "ceiling fan b"
out: "ceiling fan b"
- in: "fan 2"
out: "ceiling fan b"
speed:
values:
- in: "off"
out: "off"
- in: "low"
out: "low"
- in: "medium"
out: "medium"
- in: "high"
out: "high"
- in: "max"
out: "high"
- in: "maximum"
out: "high"
- in: "1"
out: "low"
- in: "2"
out: "medium"
- in: "3"
out: "high"
Explanation: The SetFanSpeed section defines the format of the voice commands and is pretty self-explanatory.
As for the fan name list and speed values, the “in:/out:” entries are used to map multiple potential “friendly” designations with an actual common “pseudo entity” name that will be used in the intent_script that you will create later in your configuration.yaml file.
For instance, the pseudo entity names I chose are “ceiling fan a” and “ceiling fan b”. By using the “in:” entries, I am defining the “friendly” names that voice assistant will understand and map correctly to the corresponding pseudo fan entities (specified by “out:”). As a result, when receiving a voice command, voice assistant will understand that “ceiling fan 1”, “fan 1”, “ceiling fan a” and “fan a” all point to “ceiling fan a” and the same goes for “ceiling fan b”.
It will also understand and correctly map spoken speed values: [“off”, “low”, “medium”, “high”, “max”, “maximum”, “1”, “2”, and “3”] to the four available speed choices: [off, low, medium, high]
Once this is done, you need to add a section to your configuration.yaml file. If there is no “intent:” entry already present, you need to create one and add a “intent_script:” entry underneath like so:
# Enable custom intents and sentences
intent:
intent_script:
SetFanSpeed:
speech:
text: "Setting {{ fan_name }} to {{ speed }} speed"
action:
- variables:
fan_entities:
"ceiling fan b": "fan.ceiling_fan_light"
"ceiling fan a": "fan.ceiling_fan_light_2"
speed_levels:
"off": 0
"low": 33
"medium": 66
"high": 100
- choose:
- conditions:
- condition: template
value_template: "{{ speed == 'off' }}"
sequence:
- action: fan.turn_off
target:
entity_id: "{{ fan_entities[fan_name] }}"
default:
- action: fan.set_percentage
target:
entity_id: "{{ fan_entities[fan_name] }}"
data:
percentage: "{{ speed_levels[speed] }}"
Explanation: This script is the “handler” if you want of the voice command received and parsed in “fan_control.yaml”. It starts by speaking out acknowledging and summarizing the voice command. For instance, if the command was “fan a low”, the spoken response will be: “Setting fan a to low speed”.
Then, the action is executed on the correct entity by matching the pseudo entity name defined in “fan_control.yaml” with the actual entity name in Home Assistant. In this case, the pseudo entity: “ceiling fan a” corresponds to the actual entity: “fan.ceiling_fan_light_2” and “ceiling fan b” corresponds to: “fan.ceiling_fan_light”
The “choose:” section handles the case where the speed is set to “off”, by calling “action: fan.turn_off” because “action: fan.set_percentage” does not actually turn the fan off if you pass the “off” parameter to it.
And that’s it…