Template Fan shows always shows as "On" in Google Home, behaves correctly in HA. What am I missing?

Tags: #<Tag:0x00007fc3deb4dee0> #<Tag:0x00007fc3deb4dd78>

Currently running 0.113.2 HA core in a 3.7 venv on Ubuntu with NabuCasa, however this issue appeared for me in 0.112.5 and is logged as: Github issue

In the meantime I’m working on the assumption that I may need to change something in my configuration to permanently resolve the issue.

However despite reading multiple threads and endless tinkering around I’m getting nowhere fast - I’d really appreciate some community input at this point from those more familiar with template fans just for my own sanity.

Summary
Each fan is a 5 speed ceiling fan controlled via (individual) Broadlink 3 RM minis.
As noted on the Github issue, Google Assistant (now) always reports the fans as on regardless of their actual state, seemingly due to the speed_template having a value. If I remove the value from the speed_template in HA, Google Assistant reports the fan status correctly but HA logs ‘received invalid speed’.
It’s important to note that with my current configuration everything works correctly in HA - it’s the Google Assistant element I’m struggling to resolve.

Configuration.yaml
Fans are identically configured, so here is the relevant configuration.yaml entries for one fan.

# fans controlled by Broadlink remote
fan:
  - platform: template
    fans:
      living_room_fan:
        friendly_name: "Living Room Fan"
        value_template: "{{ states('input_boolean.living_room_fan_power') }}"
        speed_template: "{{ states('input_text.living_room_fan_speed') }}"
        turn_on: 
          - service: script.living_room_fan_on
        turn_off:
          - service: script.living_room_fan_off
        set_speed:
          - service: script.living_room_fan_set_speed
            data_template:
              speed: "{{ speed }}"
        set_direction:
          - service: script.living_room_fan_reverse
        speeds:
          - '0'
          - '1'
          - '2'
          - '3'
          - '4'
          - '5'
          
input_boolean:
   living_room_fan_power:
     name: "Living Room Fan Power"

input_text:
  living_room_fan_speed:
    name: "Living Room Fan Speed"

Control Scripts

# control ceiling fans using broadlink remotes
# depends on learnt commands held under .storage folder
#------------------------------------------
#   LIVING ROOM FAN
#-----------------------------------------
# turn the fan on, defaulting to speed 2.
living_room_fan_on:
  mode: single
  sequence:
    - service: remote.send_command
      data:
        entity_id: remote.living_room
        device: fan
        command: "Speed 2"
    - service: input_boolean.turn_on
      data:
        entity_id: input_boolean.living_room_fan_power
    - service: input_text.set_value
      data:
        entity_id: input_text.living_room_fan_speed
        value: "2"

# turn off the fan, resetting boolean
# if we don't set the speed input_text to 0 then system thinks it is on regardless of power flag
living_room_fan_off:
  mode: single
  sequence:
    - service: remote.send_command
      data:
        entity_id: remote.living_room
        device: fan
        command: "Turn off"
    - service: input_boolean.turn_off
      data:
        entity_id: input_boolean.living_room_fan_power
    - service: input_text.set_value
      data:
        entity_id: input_text.living_room_fan_speed
        value: "0"

# set the fan speed by parameter
living_room_fan_set_speed:
  fields:
    speed:
      description: "The required fan speed"
      example: "2"
  mode: single
  sequence:
    - service: remote.send_command
      data_template:
        entity_id: remote.living_room
        device: fan
        command: "Speed {{ speed }}"
    - service: input_text.set_value
      data_template:
        entity_id: input_text.living_room_fan_speed
        value: "{{ speed }}"
    - condition: state
      entity_id: input_boolean.living_room_fan_power
      state: "off"
    - service: input_boolean.turn_on
      data:
        entity_id: input_boolean.living_room_fan_power   

# reverse the current direction of the fan.
living_room_fan_reverse:
  alias: "Living room fan reverse"
  mode: single
  sequence:
    - service: remote.send_command
      data:
        entity_id: remote.living_room
        device: fan
        command: "Reverse"

# sleep sets to speed 3 for 1 hour then down to 2.
living_room_fan_sleep:
  alias: "Living room fan sleep mode"
  mode: single
  sequence:
    - service: remote.send_command
      data:
        entity_id: remote.living_room
        device: fan
        command: "Sleep"
    - service: input_boolean.turn_on
      data:
        entity_id: input_boolean.living_room_fan_power
    - service: input_text.set_value
      data_template:
        entity_id: input_text.living_room_fan_speed
        value: "2"

# reset the fan power state to on
living_room_fan_reset_as_on:
  alias: "Living room fan reset as on"
  mode: single
  sequence:
    - condition: state
      entity_id: input_boolean.living_room_fan_power
      state: "off"
    - service: script.turn_on
      data:
        entity_id: script.living_room_fan_on

# reset the fan power state to off
living_room_fan_reset_as_off:
  alias: "Living room fan reset as off"
  mode: single
  sequence:
    - condition: state
      entity_id: input_boolean.living_room_fan_power
      state: "on"
    - service: script.turn_on
      data:
        entity_id: script.living_room_fan_off

Thanks in advance.

The only thing that strikes me as odd is the fact that your speeds are all strings. But that could work. Also, it’s possible that google home simply doesn’t support fans with speeds 0 to 6. It may only support off low medium and high.

And, I just checked the code. Looks like numbers aren’t supported from HA to Google home:

speed_synonyms = {
    fan.SPEED_OFF: ["stop", "off"],
    fan.SPEED_LOW: ["slow", "low", "slowest", "lowest"],
    fan.SPEED_MEDIUM: ["medium", "mid", "middle"],
    fan.SPEED_HIGH: ["high", "max", "fast", "highest", "fastest", "maximum"],
}

Basically you want to have your fan speeds be ‘off’, ‘low’, ‘medium’, or ‘high’. Then it should work properly in google home.

Thanks for responding.

Yeah I was wondering myself why I’d done that as I was posting the configuration :man_facepalming:

If I understand the speed_synonyms correctly, I would need to translate them within my control scripts (from the 5 supported speeds on the hardware to the 3 supported by Google), e.g.

fan.SPEED_OFF -> returns speed_template as "off"
fan.SPEED_LOW -> 1 -> returns speed_template as "low"
fan.SPEED_MEDIUM -> 2 -> returns speed_template as "medium"
fan.SPEED_HIGH -> 3 -> returns speed_template as "high"

and ignore speed 4 and 5 unless Google expands the available synonyms.

I’ll have to get a consensus agreement on which fan speeds to utilise and give this a whirl - thank you.

I’d go 1 = low, 3 = medium, 5 = high. Then, just make sure your value template supports 2 and 4 as well, probably lump 2 in low and 4 in medium.

I can help with the templates if need be.

Also, how are the states of your fan read if you turn on the hardware itself?

Yes that makes more sense (my wife was unimpressed with my suggestion of dropping 2 speed options).
Thanks for the offer on the templates - I’ll have a crack at it tomorrow and post in this thread if I struggle.

Unfortunately there’s nothing in place for that, so I cobbled together a set of scripts to move HA’s knowledge of the fan power state between on and off:

# reset the fan power state to on
living_room_fan_reset_as_on:
  alias: "Living room fan reset as on"
  mode: single
  sequence:
    - condition: state
      entity_id: input_boolean.living_room_fan_power
      state: "off"
    - service: script.turn_on
      data:
        entity_id: script.living_room_fan_on

# reset the fan power state to off
living_room_fan_reset_as_off:
  alias: "Living room fan reset as off"
  mode: single
  sequence:
    - condition: state
      entity_id: input_boolean.living_room_fan_power
      state: "on"
    - service: script.turn_on
      data:
        entity_id: script.living_room_fan_off

Not the most elegant way of doing things I’m sure, but they are rather expensive units and I have a bit of a habit of electrocuting myself while doing DIY so wasn’t involved in the fitting at all.
In practice my wife prefers using HA / Google Assistant to use the fans rather than the supplied remote controls so I’m hoping real knowledge of the fans’ current power states won’t be an issue long term.

It turns out my day has finished sooner than expected (read-only Friday and all that) so while I monitor a couple of work jobs I’ve been thinking about the changes to make:

I’ve looked at a few threads where you’ve helped others with template fans, and can see how to change the main configuration to give Google the expected synonym (I think) to:

fan:
  - platform: template
    fans:
      living_room_fan:
        friendly_name: "Living Room Fan"
        value_template: "{{ states('input_boolean.living_room_fan_power') }}"
        speed_template: "????"
        turn_on: 
          - service: script.living_room_fan_on
        turn_off:
          - service: script.living_room_fan_off
        set_speed:
          - service: script.living_room_fan_set_speed
            data_template:
              speed: "{{ speed }}"
        set_direction:
          - service: script.living_room_fan_reverse
        speeds:
          - "off"
          - "low"
          - "medium"
          - "high"

However I’m wondering how to best handle the speed template for both Google and HA usage.
We currently use a slider to set / change fan speed, which I could best reflect in an input_number I guess (getting rid of the input_text I was using)

That would then leave speed_template as something like:

speed_template: >
    {% if input_number.living_room_fan_speed == 0 %}off
    {% elif input_number.living_room_fan_speed == 1 %}low
    {% elif input_number.living_room_fan_speed in [2,3] %}medium
    {% else %}high
    {% endif %}

What I’m really not sure of is how to elegantly handle synonyms and numeric values in the set_speed control script?

So, that will be super goofy to use. I suggest 2 entities. 1 fan for Google Assistant, and 1 for your use in HA.

For HA use

# fans controlled by Broadlink remote
fan:
  - platform: template
    fans:
      living_room_fan:
        friendly_name: "Living Room Fan"
        value_template: "{{ states('input_boolean.living_room_fan_power') }}"
        speed_template: "{{ states('input_text.living_room_fan_speed') }}"
        turn_on: 
          - service: script.living_room_fan_on
        turn_off:
          - service: script.living_room_fan_off
        set_speed:
          - service: script.living_room_fan_set_speed
            data_template:
              speed: "{{ speed }}"
        set_direction:
          - service: script.living_room_fan_reverse
        speeds:
          - '0'
          - '1'
          - '2'
          - '3'
          - '4'
          - '5'

For Google Home Use

# fans controlled by Broadlink remote
fan:
  - platform: template
    fans:
      living_room_fan:
        friendly_name: "Living Room Fan"
        value_template: "{{ states('input_boolean.living_room_fan_power') }}"
        speed_template: >
          {% set current = states('input_text.living_room_fan_speed') %}
          {% set speeds = {
            '0': 'low'
            '1': 'low',
            '2': 'low',
            '3': 'medium',
            '4': 'medium',
            '5': 'high',
            } %}
         {{ speeds[current] if current in speeds else 'low' }}
        turn_on: 
          - service: script.living_room_fan_on
        turn_off:
          - service: script.living_room_fan_off
        set_speed:
          - service: script.living_room_fan_set_speed
            data_template:
              speed: >
                {% set speeds = {
                  'low': '1',
                  'medium': '3',
                  'high': '5'
                  } %}
                {{ speeds[speed] if speed in speeds else '0' }}
        set_direction:
          - service: script.living_room_fan_reverse

Ah okay - so basically wrapping the existing template fan attributes inside a Google-Friendly second entity and syncing that one only with Google Assistant, so that HA and GA act on different entities with the same attributes?
I wouldn’t have thought of that solution myself, but it makes far more sense and should be much easier to maintain - both present and future me thank you.

Yeah, I’ve had to do it for a few items to make it work with Alexa. Hopefully support for other fans will be added in the future. I’m not sure google assistant can handle different fan speed names. Looking at the API, it suggests it can. I could be completely wrong with my interpretation though.

In an effort to avoid doing any coding for home this weekend (I’ve worked the last 14 days straight through) I’ve implemented your suggested solution this evening.

It’s worked a treat, both for specifying fan speed via Google Assistant and for resolving the On / Off issue.

Can’t thank you enough (and my wife says thank you as well) - not least because it’s currently 35C in the UK and we’re just not used to it.

1 Like

For others reading this thread, I had to explicitly add ‘off’ to the speeds on the Googley version to ensure no logged errors in HA and that Google viewed the fan as off.
I’ll add an update to the Github issue as well to clarify - thanks again @petro.

      living_room_fan_google:
        friendly_name: "Living Room Fan"
        value_template: "{{ states('input_boolean.living_room_fan_power') }}"
        speed_template: >
          {% set current = states('input_text.living_room_fan_speed') %}
          {% set speeds = { '0': 'off','1': 'low', '2': 'low', '3': 'medium', '4': 'medium', '5': 'high'} %}
          {{ speeds[current] if current in speeds else 'low' }}
        turn_on:
          - service: script.living_room_fan_on
        turn_off:
          - service: script.living_room_fan_off
        set_speed:
          - service: script.living_room_fan_set_speed
            data_template:
              speed: >
                {% set speeds = {'off': '0', 'low': '1', 'medium': '3', 'high': '5'} %}
                {{ speeds[speed] if speed in speeds else '0' }}
        set_direction:
          - service: script.living_room_fan_reverse
        speeds:
          - 'off'
          - 'low'
          - 'medium'
          - 'high'
1 Like

Thanks for this. Have you managed to modify this to work with the new ‘percentage’ requirement?

Pretty much, and it no longer requires a “Google flavoured” version. Note that this is for a 5 speed fan controlled via Broadlink and that I’m not sure the “Speeds” section would function correctly as my lovelace uses individual buttons to increase and decrease fan speed, toggle state, etc.

config:

fan:
  - platform: template
    fans:
      living_room_fan:
        friendly_name: "Living Room Fan"
        value_template: "{{ states('input_boolean.living_room_fan_power') }}"
        percentage_template: "{{ states('input_number.living_room_fan_speed') }}"
        preset_mode_template: >
          {% set current = states('input_number.living_room_fan_speed') | round %}
          {% set speeds = { 0: 'off', 20: 'silent', 40: 'low', 60: 'medium', 80: 'high', 100: 'maximum'} %}
          {{ speeds[current] if current in speeds else 'low' }}
        turn_on: 
          - service: script.living_room_fan_on
        turn_off:
          - service: script.living_room_fan_off
        set_percentage:
          - service: script.living_room_fan_set_speed
            data:
              percentage: "{{ percentage }}"
        set_preset_mode:
          - service: script.living_room_fan_set_speed
            data:
              percentage: >
                {% set preset = state_attr('fan.living_room_fan', 'preset_mode') %}
                {% set speeds = { 'off': 0, 'silent': 20, 'low': 40, 'medium': 60, 'high': 80, 'maximum': 100 } %}
                {{ speeds[preset] if preset in speeds else 40 }}
        set_direction:
          - service: script.living_room_fan_reverse
        speed_count: 5
        preset_modes:
          - 'off'
          - 'silent'
          - 'low'
          - 'medium'
          - 'high'
          - 'maximum'

Speed script:

# set the fan speed by parameter
living_room_fan_set_speed:
  fields:
    percentage:
      description: "The required fan speed as a percentage"
      example: "40"
  mode: queued
  sequence:
    - variables:
        speed: "{{ (percentage // 20) if (percentage > 0) else 0}}"
    - service: remote.send_command
      data:
        entity_id: remote.living_room
        device: fan
        command: "Speed {{ speed }}"
    - service: input_number.set_value
      data:
        entity_id: input_number.living_room_fan_speed
        value: "{{ percentage }}"
    - choose:
        - conditions:
            - condition: and 
              conditions:
                - condition: state
                  entity_id: input_boolean.living_room_fan_power
                  state: "off" 
                - condition: numeric_state
                  entity_id: input_number.living_room_fan_speed 
                  above: 0
          sequence:
            - service: input_boolean.turn_on
              data:
                entity_id: input_boolean.living_room_fan_power
        - conditions:
            - condition: and 
              conditions:
                - condition: state
                  entity_id: input_boolean.living_room_fan_power
                  state: "on" 
                - condition: numeric_state
                  entity_id: input_number.living_room_fan_speed 
                  below: 1
          sequence: 
            - service: input_boolean.turn_off
              data:
                entity_id: input_boolean.living_room_fan_power

Well thank you Sir. Really appreciate you sharing your full code. :grin: How do you measure the fan speed? I’m using power monitoring Shellies but I don’t see anything like that in your amended code.

Blind faith - this is a ceiling fan controlled through a Broadlink RM-Mini3. I’ve catered for someone using the provided remote using a “reset” script but at the moment HA cannot determine any information about the fan state.