Template Fan broke with update to 2022.7

Just updated to 2022.7.2 from 2022.6.x. My template fan broke.
I get these error messages in the log:

Logger: homeassistant.components.template.fan
Source: components/template/fan.py:433
Integration: Template (documentation, issues)
First occurred: 12:28:10 (3 occurrences)
Last logged: 12:39:03

Received invalid preset_mode: None for entity fan.mechanische_ventilatie. Expected: Non

&

Logger: homeassistant.helpers.event
Source: components/template/fan.py:398
First occurred: 12:37:53 (2 occurrences)
Last logged: 12:39:03

Error while processing state change for sensor.mechanische_ventilatie_status
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 282, in _async_state_change_dispatcher
    hass.async_run_hass_job(job, event)
  File "/usr/src/homeassistant/homeassistant/core.py", line 546, in async_run_hass_job
    hassjob.target(*args)
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 1109, in _refresh
    self.hass.async_run_hass_job(self._job, event, updates)
  File "/usr/src/homeassistant/homeassistant/core.py", line 546, in async_run_hass_job
    hassjob.target(*args)
  File "/usr/src/homeassistant/homeassistant/helpers/template_entity.py", line 321, in _handle_results
    attr.handle_result(
  File "/usr/src/homeassistant/homeassistant/helpers/template_entity.py", line 126, in handle_result
    self.on_update(result)
  File "/usr/src/homeassistant/homeassistant/components/template/fan.py", line 398, in _update_percentage
    percentage = int(float(percentage))
TypeError: float() argument must be a string or a real number, not 'NoneType'

I believe there were some updates regarding invalid/unavailable states etc in recent releases. But honestly I don’t know where to start looking.

Show your template fan config.

Oh yeah, I was planning to do that, but forgot. Here you go.

The template:

fan:
  - platform: template
    fans:
      mechanische_ventilatie:
        friendly_name: Mechanische ventilatie
        value_template: >
          {{ states('switch.on_off_plug_ventilatie') and states('switch.on_off_plug_zender_ventilatie') }}
        percentage_template: >
          {{ state_attr('sensor.mechanische_ventilatie_status', 'percentage') }}
        preset_mode_template: >
          {{ state_attr('sensor.mechanische_ventilatie_status', 'speed') }}
        turn_on:
          service: script.ventilation_turn_on
        turn_off:
          service: script.ventilation_turn_off
        set_percentage:
          service: script.ventilation_set_voltage
          data:
            voltage: "{{ percentage / 10 }}"
        set_preset_mode:
          service: script.ventilation_set_preset_mode
          data:
            preset_mode: "{{ preset_mode }}"
        preset_modes:
          - low
          - medium
          - high
          - max

The related scripts:

# Mechanische ventilatie scripts

ventilation_turn_on:
  mode: single
  sequence:
    - service: switch.turn_on
      target:
        entity_id: switch.on_off_plug_ventilatie
    - delay: 20
    - service: switch.turn_on
      target:
        entity_id: switch.on_off_plug_zender_ventilatie

ventilation_turn_off:
  mode: single
  sequence:
    - service: switch.turn_off
      target:
        entity_id: switch.on_off_plug_ventilatie
    - delay: 1
    - service: switch.turn_off
      target:
        entity_id: switch.on_off_plug_zender_ventilatie        

ventilation_set_preset_mode:
  mode: single
  fields:
    host:
      description: Hostname or ip
    preset_mode:
      description: Set the fan preset mode (low/medium/high/max)
  sequence:
    - service: rest_command.ventilation_preset_mode
      data:
        host: !secret nrf905_host
        preset_mode: "{{ preset_mode }}"
    - service: input_text.set_value
      target:
        entity_id: input_text.mechanische_ventilatie_preset_mode
      data:
        value: "{{ preset_mode }}"
    - delay: 1
    - service: homeassistant.update_entity
      data:
        entity_id: sensor.mechanische_ventilatie_status

ventilation_set_speed_timer:
  mode: single
  fields:
    host:
      description: Hostname or ip
    speed:
      description: Set the fan speed (low/medium/high/max)
    timer:
      description: Set the fan timer (number of minutes)
  sequence:
    - service: rest_command.ventilation_set_speed_timer
      data:
        host: !secret nrf905_host
        speed: "{{ speed }}"
        timer: "{{ timer }}"
    - delay: 1
    - service: homeassistant.update_entity
      data:
        entity_id: sensor.mechanische_ventilatie_status

ventilation_set_voltage:
  mode: single
  fields:
    host:
      description: Hostname or ip
    voltage:
      description: Set the fan voltage, between 0.0 and 10.0
  sequence:
    - service: rest_command.ventilation_set_voltage
      data:
        host: !secret nrf905_host
        voltage: "{{ voltage }}"
    - delay: 1
    - service: homeassistant.update_entity
      data:
        entity_id: sensor.mechanische_ventilatie_status

The APIs that are called (towards an ESP32 + nrf905 device)

rest_command:
  # Mechanische ventilatie API calls naar ESP
  ventilation_preset_mode:
    url: http://{{ host }}/api/v2/fan/setspeed.json?speed={{ preset_mode }}
    username: !secret nrf905_username
    password: !secret nrf905_password
  ventilation_set_speed_timer:
    url: http://{{ host }}/api/v2/fan/setspeed.json?speed={{ speed }}&timer={{ timer }}
    username: !secret nrf905_username
    password: !secret nrf905_password
  ventilation_set_voltage:
    url: http://{{ host }}/api/v2/fan/setvoltage.json?voltage={{ voltage }}
    username: !secret nrf905_username
    password: !secret nrf905_password

So, you have two separate error messages - one regarding updating preset_mode and the other one regarding percentage.
In your template fan configuration I can see that both are determined from sensor sensor.mechanische_ventilatie_status, so that’s where I would assume that something goes wrong. Does that sensor have those two attributes and do they have valid values?

1 Like

It has been working fine for at least a year. It broke with the update to 2022.7. So it should be something in Hass. Have there been some breaking changes in REST or in sensor (apart from mqtt)?

You haven’t shared the configuration of that sensor sensor.mechanische_ventilatie_status so I cannot tell you if a change in 2022.7 may have changes its behaviour - that’s why I pointed that one out in particular, and you should look for breaking changes in whatever integration you are using for this sensor.

For example, there have been changes how certain default values in templates are handled (2022.6). Maybe that’s how your sensor has been tripped up now?

I’m sorry, I thought I had copied everything. This was missing indeed.

- platform: rest
  name: Mechanische ventilatie status
  resource: !secret nrf905_status_url
  username: !secret nrf905_username
  password: !secret nrf905_password
  value_template: >
    {% if value_json['result'] == 'ok' %} 
      on 
    {% else %} 
      off 
    {% endif %}
  json_attributes_path: $.devices.D2 # This will be different for each fan.
  json_attributes:
    - voltage
    - percentage
    - speed
    - timer

It might be related to these default values indeed, but weird I didn’t have the issues in 2022.6 already.

Thanks for sharing that bit of the configuation. Is there a chance that this issue only occurs in the rare event that your fan tries to update its percentage and preset_mode values before this rest sensor has successfully updated its state and attributes?
Maybe you could look at the update time of this rest sensor and compare it with the time that error message occurs.

If this is actually the case, then you could change the templates like:

        percentage_template: >
          {% if not is_state('sensor.mechanische_ventilatie_status', 'unavailable') %}
          {{ state_attr('sensor.mechanische_ventilatie_status', 'percentage') }}
          {% else %}0{% endif %}

Or, another alternative is to define an availability_template for the fan which includes the availability of all the entities you depend on (you might need to check for values unavailable and unknown):

    value_template: "{{ not is_state('sensor.mechanische_ventilatie_status', 'unavailable') and not is_state('switch.on_off_plug_ventilatie', 'unavailable') and ... }}"