Lovelace: Xiaomi - Mi air purifier 3H card

I don’t think this are affecting the functionality. Most are related to no info from the purifier. For example speed is having predefined values and cannot be None and also Fan level cannot be 0. Try adding in the configuration Initial values for this input_numbers like: initial: Auto and initial: 1. Also I have nothing to do if value for pm2.5 is not reported by purifier. I noticed this after restarting the HA but it OK once first measurement is received.

Hey shilea,

thanks for your great work.

Regarding the warnings and error messages. I get the same and using initial values somehow doesn’t work.
But is it maybe possible to intercept these “wrong” value like “none” or “0.0” in the sensor configuration? e.g. if the value is 0.0 set it to 1.0 or if value is none set it to 0.

Due to the huge amount of automations I have I often loose overview in HA Webui. Therefore I removed all coverage parts from this configuration, since I don’t use it and therefore I can remove the related automations entirely.
For purifier on and off automation I created an replacement using the recently introduced choose function. This way I get rid of at least one additional automation.

Here’s the code if someone’s interested:

- id: 'xxxxxxxxxxxxxx'
  alias: Air Purifier turn toogle
  description: ''
  trigger:
  - above: '15'
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    for: 00:00:10
    platform: numeric_state
  - below: '5'
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    for: 00:05:00
    platform: numeric_state
  condition: []
  action:
  - choose:
    - conditions:
      - condition: and
        conditions:
        - above: '15'
          condition: numeric_state
          entity_id: sensor.mi_air_purifier_air_quality_pm25
        - condition: state
          entity_id: fan.mi_air_purifier_3h
          state: 'off'
      sequence:
      - data: {}
        entity_id: fan.mi_air_purifier_3h
        service: fan.turn_on
      - data_template:
          speed: Fan
        entity_id: fan.mi_air_purifier_3h
        service: fan.set_speed
    - conditions:
      - condition: and
        conditions:
        - below: '5'
          condition: numeric_state
          entity_id: sensor.mi_air_purifier_air_quality_pm25
        - condition: state
          entity_id: fan.mi_air_purifier_3h
          state: 'on'
      sequence:
      - data: {}
        entity_id: fan.mi_air_purifier_3h
        service: fan.turn_off
    default: []
  mode: single

Unfortunately for fan or mode change the chooser doesn’t work since there is no state which can use use a condition of choosing the right option - as far as I know

EDIT:
In order to get rid of the sensor.mi_air_purifier_air_quality_pm25 one can add “if else” into the value template

    mi_air_purifier_air_quality_pm25:
      friendly_name: "Air quality (AQI) PM2.5"
      value_template: >
           {% set value = state_attr('fan.mi_air_purifier_3h', 'aqi') %}
           {% if state_attr('fan.mi_air_purifier_3h', 'aqi') == None %}
            {{ 0 }}
           {%- else -%}
            {{ value }}
           {% endif %}           
      unit_of_measurement: "μg/m³"
      icon_template: "mdi:weather-fog"

Thanks Peter for your valuable comments and updates.

I used your settings and it is working great. Thanks for this automation and Lovelace plugin.

One question. I would add an automation to this for myself and mayby you can guide me in the right direction.
I have a window sensor in my room where the air purifier is located. Now i want to turn off your automation when the window sensor is open and start it again when closed. How can this be done?

Hi @sn33ky, I am having such kind of automation for my boiler, it shuts it down if a window/door is open foe 30s and starts it if all windows/doors are closed for 1 min. Try this one to turn off the purifier but before replace the sensor name with yours.

- id: b73aca069a3dcb533e9c32fac7006bdd
  alias: Turn off the purifier if a window/door is open for 30 seconds
  trigger:
  - entity_id: binary_sensor.window_door
    for: 0:00:30
    platform: state
    to: 'on'
  condition:
  - condition: state
    entity_id: fan.mi_air_purifier_3h
    state: 'on'
  action:
  - data: {}
    entity_id: fan.mi_air_purifier_3h
    service: fan.turn_off
  - service: notify.notify
    data:
      message: Mi Air Purifier 3H turn off! window/door is open for 30 seconds at {{
        states('sensor.date_time') }}

1 Like

Thanks for your information. This helped me. I also added a automation when i’m not home to turn off the air purifier.
So I did it a little different, and edited the existing automations:

In the “Air Purifier turn off” automation i added following triggers:

  • When windows sensor x is open for 30 seconds
  • When person x is leaving home area.

And in the “Air Purifier turn on” automation i added following condition:

  • Only when window sensor x is closed.
  • Only when person x is in home area.

Due to issues with Mi Air Purifier 2S and 3H sending “None” status when turned off, I’ve modified the automations to ignore it when off, along with several conditions to detect if changes were made on the device itself. All these are meant to minimize unnecessary bloating of the HA logs.

I’m using HA 0.117.6

These are fully working lovelace cards and automations for models 2S and 3H.

configuration.yaml

fan:
  # Mi Air Purifier 2S
  - platform: xiaomi_miio
    name: "Mi Air Purifier 2S"
    host: 0.0.0.0
    token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  # Mi Air Purifier 3H
  - platform: xiaomi_miio
    name: "Mi Air Purifier 3H"
    host: 0.0.0.0
    token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

switch:
  # Mi Air Purifier 2S
  - platform: template
    switches:
      mi_air_purifier_2s_led:
        friendly_name: "Display"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_2s', 'led', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_led_on
          data:
            entity_id: fan.mi_air_purifier_2s
        turn_off:
          service: xiaomi_miio.fan_set_led_off
          data:
            entity_id: fan.mi_air_purifier_2s
        icon_template: mdi:lightbulb-outline
      mi_air_purifier_2s_child_lock:
        friendly_name: "Child lock"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_2s', 'child_lock', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_child_lock_on
          data:
            entity_id: fan.mi_air_purifier_2s
        turn_off:
          service: xiaomi_miio.fan_set_child_lock_off
          data:
            entity_id: fan.mi_air_purifier_2s
        icon_template: "mdi:lock-outline"
      mi_air_purifier_2s_buzzer:
        friendly_name: "Buzzer"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_2s', 'buzzer', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_buzzer_on
          data:
            entity_id: fan.mi_air_purifier_2s
        turn_off:
          service: xiaomi_miio.fan_set_buzzer_off
          data:
            entity_id: fan.mi_air_purifier_2s
        icon_template: "mdi:volume-high"

  # Mi Air Purifier 3H
  - platform: template
    switches:
      mi_air_purifier_3h_led:
        friendly_name: "Display"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'led', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_led_on
          data:
            entity_id: fan.mi_air_purifier_3h
        turn_off:
          service: xiaomi_miio.fan_set_led_off
          data:
            entity_id: fan.mi_air_purifier_3h
        icon_template: mdi:lightbulb-outline
      mi_air_purifier_3h_child_lock:
        friendly_name: "Child lock"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'child_lock', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_child_lock_on
          data:
            entity_id: fan.mi_air_purifier_3h
        turn_off:
          service: xiaomi_miio.fan_set_child_lock_off
          data:
            entity_id: fan.mi_air_purifier_3h
        icon_template: "mdi:lock-outline"
      mi_air_purifier_3h_buzzer:
        friendly_name: "Buzzer"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'buzzer', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_buzzer_on
          data:
            entity_id: fan.mi_air_purifier_3h
        turn_off:
          service: xiaomi_miio.fan_set_buzzer_off
          data:
            entity_id: fan.mi_air_purifier_3h
        icon_template: "mdi:volume-high"

input_number:
  # Mi Air Purifier 2S
  mi_air_purifier_2s_favorite_level:
    name: "Favorite level"
    initial: 5
    min: 0
    max: 14
    step: 1
    icon: mdi:weather-windy

  # Mi Air Purifier 3H
  mi_air_purifier_3h_favorite_level:
    name: "Favorite level"
    initial: 5
    min: 0
    max: 14
    step: 1
    icon: mdi:weather-windy
  mi_air_purifier_3h_fan_level:
    name: "Fan level"
    initial: 1
    min: 0
    max: 3
    step: 1
    icon: mdi:jquery

input_boolean:
  # Mi Air Purifier 2S
  mi_air_purifier_2s_attributes:
    name: Attributes
    icon: mdi:pencil

  # Mi Air Purifier 3H
  mi_air_purifier_3h_attributes:
    name: Attributes
    icon: mdi:pencil

input_select:
  # Mi Air Purifier 2S
  mi_air_purifier_2s_mode:
    name: Mode
    options:
      - Auto
      - Silent
      - Favorite
    initial: Auto
    icon: mdi:animation-outline

  # Mi Air Purifier 3H
  mi_air_purifier_3h_mode:
    name: Mode
    options:
      - Auto
      - Silent
      - Favorite
      - Fan
    initial: Auto
    icon: mdi:animation-outline

sensor:
  # Mi Air Purifier 2S
  - platform: template
    sensors:
      mi_air_purifier_2s_temperature:
        friendly_name: "Temperature"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'temperature') }}"
        unit_of_measurement: "°C"
        device_class: "temperature"
      mi_air_purifier_2s_humidity:
        friendly_name: "Humidity"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'humidity') }}"
        unit_of_measurement: "%"
        device_class: "humidity"
      mi_air_purifier_2s_air_quality_pm25:
        friendly_name: "Air quality (AQI) PM2.5"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-fog"
      mi_air_purifier_2s_avg_air_quality_pm25:
        friendly_name: "Average air quality (AvgAQI) PM2.5"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'average_aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-hazy"
      mi_air_purifier_2s_use_time:
        friendly_name: "Time used"
        value_template: >
            {% macro phrase(value, name) %}
            {%- set value = value | int %}
            {%- set end = 's' if value > 1 else '' %}
            {{- '{} {}{}'.format(value, name, end) if value | int > 0 else '' }}
            {%- endmacro %}

            {% set weeks = (state_attr('fan.mi_air_purifier_2s', 'use_time') | int / 604800) | int %}
            {% set days = ((state_attr('fan.mi_air_purifier_2s', 'use_time') | int - (weeks * 604800)) / 86400) | int %}
            {% set hours = ((state_attr('fan.mi_air_purifier_2s', 'use_time') | int - (weeks * 604800) - (days * 86400)) / 3600) | int %}
            {% set minutes = ((state_attr('fan.mi_air_purifier_2s', 'use_time') | int - (weeks * 604800) - (days * 86400) - (hours * 3600)) / 60) | int %}
            {% set seconds = (state_attr('fan.mi_air_purifier_2s', 'use_time') | int - (weeks * 604800) - (days * 86400) - (hours * 3600) - (minutes*60)) | int %}
            {{ [ phrase(weeks, 'week'), phrase(days, 'day'), phrase(hours, 'hr'), phrase(minutes, 'min'), phrase(seconds, 'sec') ] | select('!=','') | list | join(', ') }}
        icon_template: "mdi:heart-pulse"
      mi_air_purifier_2s_filter_used:
        friendly_name: "Filter used"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'filter_hours_used') }}"
        unit_of_measurement: "hrs"
        icon_template: "mdi:heart-off"
      mi_air_purifier_2s_filter_remaining:
        friendly_name: "Filter remaining"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'filter_life_remaining') }}"
        unit_of_measurement: "%"
        icon_template: "mdi:heart-outline"
      mi_air_purifier_2s_purify_volume:
        friendly_name: "Purified volume"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'purify_volume') }}"
        unit_of_measurement: "m³"
        icon_template: "mdi:warehouse"
      mi_air_purifier_2s_speed:
        friendly_name: "Fan speed"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'motor_speed') }}"
        unit_of_measurement: "rpm"
        icon_template: "mdi:speedometer"
      mi_air_purifier_2s_filter_type:
        friendly_name: "Filter type"
        value_template: "{{ state_attr('fan.mi_air_purifier_2s', 'filter_type') }}"
        icon_template: "mdi:air-filter"

  # Mi Air Purifier 3H
  - platform: template
    sensors:
      mi_air_purifier_3h_temperature:
        friendly_name: "Temperature"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'temperature') }}"
        unit_of_measurement: "°C"
        device_class: "temperature"
      mi_air_purifier_3h_humidity:
        friendly_name: "Humidity"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'humidity') }}"
        unit_of_measurement: "%"
        device_class: "humidity"
      mi_air_purifier_3h_air_quality_pm25:
        friendly_name: "Air quality (AQI) PM2.5"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-fog"
      mi_air_purifier_3h_avg_air_quality_pm25:
        friendly_name: "Average air quality (AvgAQI) PM2.5"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'average_aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-hazy"
      mi_air_purifier_3h_use_time:
        friendly_name: "Time used"
        value_template: >
            {% macro phrase(value, name) %}
            {%- set value = value | int %}
            {%- set end = 's' if value > 1 else '' %}
            {{- '{} {}{}'.format(value, name, end) if value | int > 0 else '' }}
            {%- endmacro %}

            {% set weeks = (state_attr('fan.mi_air_purifier_3h', 'use_time') | int / 604800) | int %}
            {% set days = ((state_attr('fan.mi_air_purifier_3h', 'use_time') | int - (weeks * 604800)) / 86400) | int %}
            {% set hours = ((state_attr('fan.mi_air_purifier_3h', 'use_time') | int - (weeks * 604800) - (days * 86400)) / 3600) | int %}
            {% set minutes = ((state_attr('fan.mi_air_purifier_3h', 'use_time') | int - (weeks * 604800) - (days * 86400) - (hours * 3600)) / 60) | int %}
            {% set seconds = (state_attr('fan.mi_air_purifier_3h', 'use_time') | int - (weeks * 604800) - (days * 86400) - (hours * 3600) - (minutes*60)) | int %}
            {{ [ phrase(weeks, 'week'), phrase(days, 'day'), phrase(hours, 'hr'), phrase(minutes, 'min'), phrase(seconds, 'sec') ] | select('!=','') | list | join(', ') }}
        icon_template: "mdi:heart-pulse"
      mi_air_purifier_3h_filter_used:
        friendly_name: "Filter used"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'filter_hours_used') }}"
        unit_of_measurement: "hrs"
        icon_template: "mdi:heart-off"
      mi_air_purifier_3h_filter_remaining:
        friendly_name: "Filter remaining"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'filter_life_remaining') }}"
        unit_of_measurement: "%"
        icon_template: "mdi:heart-outline"
      mi_air_purifier_3h_purify_volume:
        friendly_name: "Purified volume"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'purify_volume') }}"
        unit_of_measurement: "m³"
        icon_template: "mdi:warehouse"
      mi_air_purifier_3h_speed:
        friendly_name: "Fan speed"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'motor_speed') }}"
        unit_of_measurement: "rpm"
        icon_template: "mdi:speedometer"
      mi_air_purifier_3h_filter_type:
        friendly_name: "Filter type"
        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'filter_type') }}"
        icon_template: "mdi:air-filter"

lovelace cards

 cards:
  - cards:
      - entity: sensor.mi_air_purifier_2s_air_quality_pm25
        max: 30
        min: 0
        name: AQI PM2.5
        severity:
          green: 0
          red: 21
          yellow: 11
        type: gauge
    type: horizontal-stack
  - entities:
      - entity: fan.mi_air_purifier_2s
      - entity: switch.mi_air_purifier_2s_led
      - entity: input_select.mi_air_purifier_2s_mode
    show_header_toggle: false
    type: entities
  - card:
      entities:
        - entity: input_number.mi_air_purifier_2s_favorite_level
      type: entities
    conditions:
      - entity: input_select.mi_air_purifier_2s_mode
        state: Favorite
    type: conditional
  - entities:
      - entity: sensor.mi_air_purifier_2s_temperature
      - entity: sensor.mi_air_purifier_2s_humidity
      - entity: sensor.mi_air_purifier_2s_air_quality_pm25
      - entity: sensor.mi_air_purifier_2s_avg_air_quality_pm25
      - type: divider
      - entity: sensor.mi_air_purifier_2s_filter_type
      - entity: sensor.mi_air_purifier_2s_filter_used
      - entity: sensor.mi_air_purifier_2s_filter_remaining
      - entity: sensor.mi_air_purifier_2s_use_time
      - entity: sensor.mi_air_purifier_2s_purify_volume
      - type: divider
      - entity: sensor.mi_air_purifier_2s_speed
      - type: divider
      - entity: switch.mi_air_purifier_2s_child_lock
      - entity: switch.mi_air_purifier_2s_buzzer
    show_header_toggle: false
    type: entities
type: vertical-stack

cards:
  - cards:
      - entity: sensor.mi_air_purifier_3h_air_quality_pm25
        max: 30
        min: 0
        name: AQI PM2.5
        severity:
          green: 0
          red: 21
          yellow: 11
        type: gauge
    type: horizontal-stack
  - entities:
      - entity: fan.mi_air_purifier_3h
      - entity: switch.mi_air_purifier_3h_led
      - entity: input_select.mi_air_purifier_3h_mode
    show_header_toggle: false
    type: entities
  - card:
      entities:
        - entity: input_number.mi_air_purifier_3h_favorite_level
      type: entities
    conditions:
      - entity: input_select.mi_air_purifier_3h_mode
        state: Favorite
    type: conditional
  - card:
      entities:
        - entity: input_number.mi_air_purifier_3h_fan_level
      type: entities
    conditions:
      - entity: input_select.mi_air_purifier_3h_mode
        state: Fan
    type: conditional
  - entities:
      - entity: sensor.mi_air_purifier_3h_temperature
      - entity: sensor.mi_air_purifier_3h_humidity
      - entity: sensor.mi_air_purifier_3h_air_quality_pm25
      - entity: sensor.mi_air_purifier_3h_avg_air_quality_pm25
      - type: divider
      - entity: sensor.mi_air_purifier_3h_filter_type
      - entity: sensor.mi_air_purifier_3h_filter_used
      - entity: sensor.mi_air_purifier_3h_filter_remaining
      - entity: sensor.mi_air_purifier_3h_use_time
      - entity: sensor.mi_air_purifier_3h_purify_volume
      - type: divider
      - entity: sensor.mi_air_purifier_3h_speed
      - type: divider
      - entity: switch.mi_air_purifier_3h_child_lock
      - entity: switch.mi_air_purifier_3h_buzzer
    show_header_toggle: false
    type: entities
type: vertical-stack

automations.yaml

# ----------------------------------------------------------------------------------------------------
# Mi Air Purifier 2S
# ----------------------------------------------------------------------------------------------------
- id: '10000000001'
  alias: Mi Air Purifier 2S mode change init
  trigger:
    platform: state
    entity_id: input_select.mi_air_purifier_2s_mode
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 2S'
        message: 'Mode change: {{ states(''input_select.mi_air_purifier_2s_mode'') }}'
    - service: fan.set_speed
      entity_id: fan.mi_air_purifier_2s
      data_template:
        speed: '{{ states(''input_select.mi_air_purifier_2s_mode'') | capitalize }}'

- id: '10000000002'
  alias: Mi Air Purifier 2S mode change update
  trigger:
    platform: state
    entity_id: fan.mi_air_purifier_2s
  condition:
    condition: and
    conditions:
      # Check if turned on
      - '{{ (state_attr(''fan.mi_air_purifier_2s'', ''speed'') | capitalize) != ''None'' }}'
      # Proceed if purifier mode is set different than HA dropdown
      - '{{ (state_attr(''fan.mi_air_purifier_2s'', ''speed'') | capitalize) != (states(''input_select.mi_air_purifier_2s_mode'') | capitalize) }}'
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 2S'
        message: 'Mode change update: {{ states(''input_select.mi_air_purifier_2s_mode'') }} > {{ state_attr(''fan.mi_air_purifier_2s'', ''speed'') }}'
    - service: input_select.select_option
      entity_id: input_select.mi_air_purifier_2s_mode
      data_template:
        option: '{{ state_attr(''fan.mi_air_purifier_2s'', ''speed'') | capitalize }}'

- id: '10000000003'
  alias: Mi Air Purifier 2S favorite level change init
  trigger:
    platform: state
    entity_id: input_number.mi_air_purifier_2s_favorite_level
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 2S'
        message: 'Favorite level change: {{ states(''input_number.mi_air_purifier_2s_favorite_level'') }}'
    - service: xiaomi_miio.fan_set_favorite_level
      entity_id: fan.mi_air_purifier_2s
      data_template:
        level: '{{ states(''input_number.mi_air_purifier_2s_favorite_level'') | int }}'

- id: '10000000004'
  alias: Mi Air Purifier 2S favorite level change update
  trigger:
    platform: state
    entity_id: fan.mi_air_purifier_2s
  condition:
    condition: and
    conditions:
      # Check if turned on
      - '{{ (state_attr(''fan.mi_air_purifier_2s'', ''favorite_level'') | int) != 0 }}'
      # Proceed only if purifier favorite level different than on HA card
      - '{{ (state_attr(''fan.mi_air_purifier_2s'', ''favorite_level'') | int) != (states(''input_number.mi_air_purifier_2s_favorite_level'') | int) }}'
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 2S'
        message: 'Favorite level change update: {{ states(''input_number.mi_air_purifier_2s_favorite_level'') }} > {{ state_attr(''fan.mi_air_purifier_2s'', ''favorite_level'') }}'
    - service: input_number.set_value
      entity_id: input_number.mi_air_purifier_2s_favorite_level
      data_template:
        value: '{{ state_attr(''fan.mi_air_purifier_2s'', ''favorite_level'') | int }}'


# ----------------------------------------------------------------------------------------------------
# Mi Air Purifier 3H
# ----------------------------------------------------------------------------------------------------
- id: '20000000001'
  alias: Mi Air Purifier 3H mode change init
  trigger:
    platform: state
    entity_id: input_select.mi_air_purifier_3h_mode
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 3H'
        message: 'Mode change: {{ states(''input_select.mi_air_purifier_3h_mode'') }}'
    - service: fan.set_speed
      entity_id: fan.mi_air_purifier_3h
      data_template:
        speed: '{{ states(''input_select.mi_air_purifier_3h_mode'') | capitalize }}'

- id: '20000000002'
  alias: Mi Air Purifier 3H mode change update
  trigger:
    platform: state
    entity_id: fan.mi_air_purifier_3h
  condition:
    condition: and
    conditions:
      # Check if turned on
      - '{{ (state_attr(''fan.mi_air_purifier_3h'', ''speed'') | capitalize) != ''None'' }}'
      # Proceed if purifier mode is set different than HA dropdown
      - '{{ (state_attr(''fan.mi_air_purifier_3h'', ''speed'') | capitalize) != (states(''input_select.mi_air_purifier_3h_mode'') | capitalize) }}'
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 3H'
        message: 'Mode change update: {{ states(''input_select.mi_air_purifier_3h_mode'') }} > {{ state_attr(''fan.mi_air_purifier_3h'', ''speed'') }}'
    - service: input_select.select_option
      entity_id: input_select.mi_air_purifier_3h_mode
      data_template:
        option: '{{ state_attr(''fan.mi_air_purifier_3h'', ''speed'') | capitalize }}'

- id: '20000000003'
  alias: Mi Air Purifier 3H favorite level change init
  trigger:
    platform: state
    entity_id: input_number.mi_air_purifier_3h_favorite_level
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 3H'
        message: 'Favorite level change: {{ states(''input_number.mi_air_purifier_3h_favorite_level'') }}'
    - service: xiaomi_miio.fan_set_favorite_level
      entity_id: fan.mi_air_purifier_3h
      data_template:
        level: '{{ states(''input_number.mi_air_purifier_3h_favorite_level'') | int }}'

- id: '20000000004'
  alias: Mi Air Purifier 3H favorite level change update
  trigger:
    platform: state
    entity_id: fan.mi_air_purifier_3h
  condition:
    condition: and
    conditions:
      # Check if turned on
      - '{{ (state_attr(''fan.mi_air_purifier_3h'', ''favorite_level'') | int) != 0 }}'
      # Proceed only if purifier favorite level is set different than on HA card
      - '{{ (state_attr(''fan.mi_air_purifier_3h'', ''favorite_level'') | int) != (states(''input_number.mi_air_purifier_3h_favorite_level'') | int) }}'
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 3H'
        message: 'Favorite level change update: {{ states(''input_number.mi_air_purifier_3h_favorite_level'') }} > {{ state_attr(''fan.mi_air_purifier_3h'', ''favorite_level'') }}'
    - service: input_number.set_value
      entity_id: input_number.mi_air_purifier_3h_favorite_level
      data_template:
        value: '{{ state_attr(''fan.mi_air_purifier_3h'', ''favorite_level'') | int }}'

- id: '20000000005'
  alias: Mi Air Purifier 3H fan level change init
  trigger:
    platform: state
    entity_id: input_number.mi_air_purifier_3h_fan_level
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 3H'
        message: 'Fan level change: {{ states(''input_number.mi_air_purifier_3h_fan_level'') }}'
    - service: xiaomi_miio.fan_set_fan_level
      entity_id: fan.mi_air_purifier_3h
      data_template:
        level: '{{ states(''input_number.mi_air_purifier_3h_fan_level'') | int }}'

- id: '20000000006'
  alias: Mi Air Purifier 3H fan level change update
  trigger:
    platform: state
    entity_id: fan.mi_air_purifier_3h
  condition:
    condition: and
    conditions:
      # Check if turned on
      - '{{ (state_attr(''fan.mi_air_purifier_3h'', ''fan_level'') | int) != 0 }}'
      # Proceed only if purifier fan level different than on HA card
      - '{{ (state_attr(''fan.mi_air_purifier_3h'', ''fan_level'') | int) != (states(''input_number.mi_air_purifier_3h_fan_level'') | int) }}'
  action:
    # Send browser notification
    - service: persistent_notification.create
      data:
        title: 'Mi Air Purifier 3H'
        message: 'Fan level change update: {{ states(''input_number.mi_air_purifier_3h_fan_level'') }} > {{ state_attr(''fan.mi_air_purifier_3h'', ''fan_level'') }}'
    - service: input_number.set_value
      entity_id: input_number.mi_air_purifier_3h_fan_level
      data_template:
        value: '{{ state_attr(''fan.mi_air_purifier_3h'', ''fan_level'') | int }}'

Note: automations are set to notify browser on any purifier change; simply disable it by commenting out (with #) the lines - service: persistent_notification.create, data, title and message

1 Like

Something is wrong with automations (Purifier 3H). When I change mode from eg. Auto to favourite it changes for a second and then changes to fan. This is what I see in log:

Mi Air Purifier 3H mode change init has been triggered by state of input_select.mi_air_purifier_3h_mode
10:32:19 - 3 minuty temu
Mi Air Purifier 3H mode change update has been triggered by state of fan.mi_air_purifier_3h
10:32:19 - 3 minuty temu
Mi Air Purifier 3H fan level change init has been triggered by state of input_number.mi_air_purifier_3h_fan_level
10:32:18 - 3 minuty temu
Mi Air Purifier 3H fan level change update has been triggered by state of fan.mi_air_purifier_3h
10:32:18 - 3 minuty temu

Look like both automations fire one by one…

Changing mode is changing fan level and we have chain reaction…

Hello,

Work like a charm but really difficult for my first integration … But i’m happy now. Thanks a lot !

@check I can see the only difference are the conditions, like the one bellow, you added on 3 automations. I will give them a try and let you know my thoughts.

@majkers I think this is how Purifier implements changes in Favorite level. When going through different favorite levels it changes also the fan level. The lowest ones are with FAN level 1 and the highest ones with FAN level 3. So the automations see also a FAN changes and reacts accordingly. I have also to think about on how not to run automation when Favorite level changed.

I just updated my initial post where I added checks for 2S in automations. It works flawlessly without bloating the log when device sends status update.

I’ve had lot’s of issues with purifiers this year and finally I can say it’s working right.

1 Like

Thanks all for sharing your job. Was very helpful to me.

I have been reworking this system until I got something more compact. It also solves all problems with state ping-pong I had due to 3H connectivity issues.

Added automation:

  • Recognizes open door and window and pauses/resumes purifier (wont turn on purifier while they are open)
  • Recognizes presence, stops purifier after leaving and wont start until returning home
  • Clean before returning home, based on time of a day and presence
  • Follows day and night hours
  • Faster reaction to PM changes, and even faster with external PM sensor

You may remove all time_pattern triggers if your purifier wifi is reliable.

image
image
image

/config/integrations/airpurifier.yaml

#======================#
#  Mi Air Purifier 3H  #
#======================#
fan:
  - platform: xiaomi_miio
    name: "Mi Air Purifier 3H"
    host: !secret mi_air_host
    token: !secret mi_air_token
    model: zhimi.airpurifier.mb3

input_number:
    mi_air_purifier_favorite_level:
      name: "Favorite level"
      initial: 0
      min: 0
      max: 14
      step: 1
      icon: mdi:weather-windy

input_boolean:
    mi_air_purifier_paused:
      name: Air Purifier Paused
      initial: off
      icon: mdi:air-filter

binary_sensor:
  - platform: template
    sensors:
      mi_air_purifier_mode_off:
        friendly_name: "Purifier Off"
        value_template: "{{ is_state('fan.mi_air_purifier_3h', 'off') }}"
      mi_air_purifier_mode_auto:
        friendly_name: "Purifier Auto mode"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 0) and is_state('fan.mi_air_purifier_3h', 'on') }}"
      mi_air_purifier_mode_silent:
        friendly_name: "Purifier Silent mode"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 1) and is_state('fan.mi_air_purifier_3h', 'on') }}"
      mi_air_purifier_mode_favorite:
        friendly_name: "Purifier Favorite mode"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 2) and is_state('fan.mi_air_purifier_3h', 'on') }}"
      mi_air_purifier_mode_fan:
        friendly_name: "Purifier Fan mode"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 3) and is_state('fan.mi_air_purifier_3h', 'on') }}"
      mi_air_purifier_mode_fan_1:
        friendly_name: "Purifier Fan mode 1"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 3) and is_state_attr('fan.mi_air_purifier_3h', 'fan_level', 1) and is_state('fan.mi_air_purifier_3h', 'on') }}"
      mi_air_purifier_mode_fan_2:
        friendly_name: "Purifier Fan mode 2"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 3) and is_state_attr('fan.mi_air_purifier_3h', 'fan_level', 2) and is_state('fan.mi_air_purifier_3h', 'on') }}"
      mi_air_purifier_mode_fan_3:
        friendly_name: "Purifier Fan mode 3"
        value_template: "{{ is_state_attr('fan.mi_air_purifier_3h', 'mode', 3) and is_state_attr('fan.mi_air_purifier_3h', 'fan_level', 3) and is_state('fan.mi_air_purifier_3h', 'on') }}"


sensor:
  - platform: template
    sensors:
      mi_air_purifier_air_quality_pm25:
        friendly_name: "Air quality (AQI) PM2.5"
        value_template: >
           {% set value = state_attr('fan.mi_air_purifier_3h', 'aqi') %}
           {% if state_attr('fan.mi_air_purifier_3h', 'aqi') == None %}
            {{ 0 }}
           {%- else -%}
            {{ value }}
           {% endif %}           
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-fog"

/config/automations/airpurifier.yaml

#==============================================#
#  Air Purifier favorite level change
#==============================================#
- id: air_purifier_favorite_level_change
  alias: Air Purifier favorite level change
  description: ''
  trigger:
  - entity_id: input_number.mi_air_purifier_favorite_level
    platform: state
  condition:
    - condition: state
      entity_id: binary_sensor.mi_air_purifier_mode_favorite
      state: 'on'
  action:
  - data_template:
      level: '{{ states(''input_number.mi_air_purifier_favorite_level'') | int }}'
    entity_id: fan.mi_air_purifier_3h
    service: xiaomi_miio.fan_set_favorite_level
#==============================================#
#  Air Purifier favorite level change
#==============================================#
- id: air_purifier_favorite_level_update
  alias: Air Purifier favorite level change
  description: ''
  trigger:
  - entity_id: fan.mi_air_purifier_3h
    platform: state
  condition: []
  action:
  - data_template:
      value: '{{ state_attr(''fan.mi_air_purifier_3h'', ''favorite_level'') | int }}'
    entity_id: input_number.mi_air_purifier_favorite_level
    service: input_number.set_value
#==============================================#
#  Air Purifier set favorite level based on PM2.5
#==============================================#
- id: air_purifier_set_favorite_level_based_on_PM2.5
  alias: Air Purifier set favorite level based on PM2.5
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    above: '50'
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    below: '50'
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    below: '40'
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    below: '30'
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    below: '20'
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    below: '10'
  - minutes: '/2'
    platform: time_pattern
  condition:
    - condition: state
      entity_id: binary_sensor.mi_air_purifier_mode_favorite
      state: 'on'
  action:
  - data_template:
      level: >
        {% if states("sensor.mi_air_purifier_air_quality_pm25") | int > 50 -%}
        11
        {%- elif states("sensor.mi_air_purifier_air_quality_pm25") | int > 40 -%}
        9
        {%- elif states("sensor.mi_air_purifier_air_quality_pm25") | int > 30 -%}
        8
        {%- elif states("sensor.mi_air_purifier_air_quality_pm25") | int > 20 -%}
        6
        {%- elif states("sensor.mi_air_purifier_air_quality_pm25") | int > 10 -%}
        4
        {%- else -%}
        2
        {%- endif %}
    entity_id: fan.mi_air_purifier_3h
    service: xiaomi_miio.fan_set_favorite_level
#==============================================#
#  PAUSE
#==============================================#
- id: air_purifier_pause
  alias: Air Purifier pause
  description: ''
  trigger:
  - platform: state
    entity_id: binary_sensor.door_contact_sensor_contact
    from: 'off'
    to: 'on'
  - platform: state
    entity_id: binary_sensor.window_contact_sensor_contact
    from: 'off'
    to: 'on'
  condition:
  - condition: and
    conditions:
    - condition: state
      entity_id: input_boolean.mi_air_purifier_paused
      state: 'off'
    - condition: state
      entity_id: fan.mi_air_purifier_3h
      state: 'on'
  action:
  - service: input_boolean.turn_on
    data: {}
    entity_id: input_boolean.mi_air_purifier_paused
  - service: fan.turn_off
    data: {}
    entity_id: fan.mi_air_purifier_3h
  mode: single
#==============================================#
#  RESUME
#==============================================#
- id: air_purifier_resume
  alias: Air Purifier resume
  description: ''
  trigger:
  - platform: state
    entity_id: binary_sensor.door_contact_sensor_contact
    from: 'on'
    to: 'off'
  - platform: state
    entity_id: binary_sensor.window_contact_sensor_contact
    from: 'on'
    to: 'off'
  condition:
  - condition: and
    conditions:
    - condition: state
      entity_id: binary_sensor.window_contact_sensor_contact
      state: 'off'
    - condition: state
      entity_id: binary_sensor.door_contact_sensor_contact
      state: 'off'
    - condition: state
      entity_id: input_boolean.mi_air_purifier_paused
      state: 'on'
  action:
  - service: input_boolean.turn_off
    data: {}
    entity_id: input_boolean.mi_air_purifier_paused
  - service: fan.turn_on
    data: {}
    entity_id: fan.mi_air_purifier_3h
  mode: single
#==============================================#
#  LEAVE HOME
#==============================================#
- id: air_purifier_leave_home
  alias: Air Purifier leave home
  description: ''
  trigger:
  - platform: state
    from: home
    to: not_home
    entity_id: device_tracker.shiis_iphone
  condition:
  - condition: state
    entity_id: fan.mi_air_purifier_3h
    state: 'on'
  action:
  - data: {}
    entity_id: fan.mi_air_purifier_3h
    service: fan.turn_off
  mode: single
#==============================================#
#  RETURN HOME
#==============================================#
# - id: air_purifier_return_home
#   alias: Air Purifier return home
#   description: ''
#   trigger:
#   - platform: state
#     from: not_home
#     to: home
#     entity_id: device_tracker.shiis_iphone
#   condition:
#   - condition: state
#     entity_id: fan.mi_air_purifier_3h
#     state: 'off'
#   action:
#   - service: fan.set_speed
#     entity_id: fan.mi_air_purifier_3h
#     data_template:
#       speed: 'Silent'
#   mode: single
#==============================================#
#  PRE-CLEAN BEFORE RETURNING HOME
#==============================================#
- id: air_purifier_pre-clean
  alias: Air Purifier pre-clean
  description: ''
  trigger:
  - platform: time
    at: '15:00'
  condition:
  - condition: and
    conditions:
    - condition: state
      entity_id: device_tracker.shiis_iphone
      state: not_home
    - condition: state
      entity_id: input_boolean.mi_air_purifier_paused
      state: 'off'
  action:
  - service: fan.set_speed
    entity_id: fan.mi_air_purifier_3h
    data_template:
      speed: 'Favorite'
  mode: single
#==============================================#
#  CLEAN AFTER CLOSING WINDOWS
#==============================================#
# - id: air_purifier_auto-clean_window
#   alias: Air Purifier auto-clean window
#   description: ''
#   trigger:
#   - platform: state
#     entity_id: binary_sensor.window_contact_sensor_contact
#     from: 'on'
#     to: 'off'
#   condition:
#   - condition: and
#     conditions:
#     - condition: time
#       after: '8:00'
#       before: '23:00'
#     - condition: state
#       entity_id: input_boolean.mi_air_purifier_paused
#       state: 'off'
#     - condition: state
#       entity_id: fan.mi_air_purifier_3h
#       state: 'off'
#   action:
#   - service: fan.set_speed
#     entity_id: fan.mi_air_purifier_3h
#     data_template:
#       speed: 'Favorite'
#   mode: single
#==============================================#
#  CLEAN ABOVE 50 PM25
#==============================================#
- id: air_purifier_auto-clean
  alias: Air Purifier auto-clean
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    above: '50'
    for: 00:01:00
  - platform: time_pattern
    minutes: '/5'
  condition:
  - condition: and
    conditions:
    - condition: time
      after: '8:00'
      before: '23:00'
    - condition: state
      entity_id: device_tracker.shiis_iphone
      state: home
    - condition: state
      entity_id: input_boolean.mi_air_purifier_paused
      state: 'off'
    - condition: state
      entity_id: binary_sensor.window_contact_sensor_contact
      state: 'off'
    - condition: state
      entity_id: binary_sensor.door_contact_sensor_contact
      state: 'off'
    - condition: state
      entity_id: binary_sensor.headset_presence
      state: 'on'
    - condition: state
      entity_id: binary_sensor.mi_air_purifier_mode_fan
      state: 'off'
    - condition: numeric_state
      entity_id: sensor.mi_air_purifier_air_quality_pm25
      above: 50
  action:
  - service: fan.set_speed
    entity_id: fan.mi_air_purifier_3h
    data_template:
      speed: 'Favorite'
  - service: xiaomi_miio.fan_set_favorite_level
    entity_id: fan.mi_air_purifier_3h
    data_template:
      level: 11
  mode: single
#==============================================#
#  SWITCH TO SILENT AT 10 PM25
#==============================================#
- id: air_purifier_auto-clean_silent
  alias: Air Purifier auto-clean silent
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.mi_air_purifier_air_quality_pm25
    below: '10'
    for: 00:01:00
  - platform: time_pattern
    minutes: '/5'
  condition:
  - condition: and
    conditions:
    - condition: state
      entity_id: fan.mi_air_purifier_3h
      state: 'on'
    - condition: numeric_state
      entity_id: sensor.mi_air_purifier_air_quality_pm25
      below: '10'
    - condition: state
      entity_id: binary_sensor.mi_air_purifier_mode_favorite
      state: 'on'
  action:
#   - service: fan.set_speed
#     entity_id: fan.mi_air_purifier_3h
#     data_template:
#       speed: 'Silent'
  - service: fan.turn_off
    data: {}
    entity_id: fan.mi_air_purifier_3h
  mode: single
#==============================================#
#  SWITCH TO SILENT FOR SLEEP
#==============================================#
- id: air_purifier_sleep
  alias: Air Purifier sleep
  description: ''
  trigger:
  - platform: numeric_state
    entity_id: sensor.pc_power
    below: '30'
  condition:
  - condition: and
    conditions:
    - condition: time
      after: '23:00'
      before: '08:00'
    - condition: state
      entity_id: input_boolean.mi_air_purifier_paused
      state: 'off'
    - condition: state
      entity_id: fan.mi_air_purifier_3h
      state: 'on'
  action:
#   - service: fan.set_speed
#     entity_id: fan.mi_air_purifier_3h
#     data_template:
#       speed: 'Silent'
  - service: fan.turn_off
    data: {}
    entity_id: fan.mi_air_purifier_3h
  mode: single

Dashboard

type: vertical-stack
cards:
  - type: picture-elements
    image: local/images/mi-air-purifier-3h.png
    elements:
      - type: state-label
        entity: fan.mi_air_purifier_3h
        attribute: aqi
        style:
          top: 21%
          left: 73.3%
          min-width: 40px
          min-height: 40px
          text-align: center
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(0, 2, 0)'
          border-radius: 20px
      - type: image
        entity: fan.mi_air_purifier_3h
        state_image:
          'on': local/images/mi-air-purifier-3h_on.png
          'off': local/images/mi-air-purifier-3h_off.png
        style:
          top: 38%
          left: 73.3%
      - type: state-label
        entity: fan.mi_air_purifier_3h
        attribute: average_aqi
        prefix: 'Average PM2.5 '
        suffix: ' μg/m³'
        style:
          top: 12%
          left: 60%
          transform: 'translate(-100%, 0)'
          text-shadow: '1px 1px 2px black, 0 0 25px rgb(41, 41, 41)'
      - type: state-label
        entity: fan.mi_air_purifier_3h
        attribute: filter_hours_used
        prefix: 'Filter used '
        suffix: ' hrs'
        style:
          top: 25%
          left: 60%
          transform: 'translate(-100%, 0)'
          text-shadow: '1px 1px 2px black, 0 0 25px rgb(41, 41, 41)'
      - type: state-label
        entity: fan.mi_air_purifier_3h
        attribute: filter_life_remaining
        prefix: 'Filter remaining '
        suffix: '%'
        style:
          top: 38%
          left: 60%
          transform: 'translate(-100%, 0)'
          text-shadow: '1px 1px 2px black, 0 0 25px rgb(41, 41, 41)'
      - type: state-label
        entity: fan.mi_air_purifier_3h
        attribute: purify_volume
        prefix: 'Purified volume '
        suffix: ' m³'
        style:
          top: 51%
          left: 60%
          transform: 'translate(-100%, 0)'
          text-shadow: '1px 1px 2px black, 0 0 25px rgb(41, 41, 41)'
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_auto
        title: Auto
        icon: 'mdi:calendar-sync'
        tap_action:
          action: call-service
          service: fan.set_speed
          service_data:
            entity_id: fan.mi_air_purifier_3h
            speed: Auto
        style:
          top: 75%
          left: 6%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_silent
        title: Silent
        icon: 'mdi:fan-minus'
        tap_action:
          action: call-service
          service: fan.set_speed
          service_data:
            entity_id: fan.mi_air_purifier_3h
            speed: Silent
        style:
          top: 75%
          left: 16%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_favorite
        title: Favorite
        icon: 'mdi:fan-chevron-up'
        tap_action:
          action: call-service
          service: fan.set_speed
          service_data:
            entity_id: fan.mi_air_purifier_3h
            speed: Favorite
        style:
          top: 75%
          left: 26%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_fan_1
        title: Fan level 1
        icon: 'mdi:fan-speed-1'
        tap_action:
          action: call-service
          service: xiaomi_miio.fan_set_fan_level
          service_data:
            entity_id: fan.mi_air_purifier_3h
            level: 1
        style:
          top: 75%
          left: 36%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_fan_2
        title: Fan level 2
        icon: 'mdi:fan-speed-2'
        tap_action:
          action: call-service
          service: xiaomi_miio.fan_set_fan_level
          service_data:
            entity_id: fan.mi_air_purifier_3h
            level: 2
        style:
          top: 75%
          left: 46%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_fan_3
        title: Fan level 3
        icon: 'mdi:fan-speed-3'
        tap_action:
          action: call-service
          service: xiaomi_miio.fan_set_fan_level
          service_data:
            entity_id: fan.mi_air_purifier_3h
            level: 3
        style:
          top: 75%
          left: 56%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_off
        title: 'Off'
        icon: 'mdi:fan-off'
        tap_action:
          action: call-service
          service: fan.turn_off
          service_data:
            entity_id: fan.mi_air_purifier_3h
        style:
          top: 5%
          left: 6%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
  - card:
      entities:
        - entity: input_number.mi_air_purifier_favorite_level
      type: entities
    conditions:
      - entity: binary_sensor.mi_air_purifier_mode_favorite
        state: 'on'
    type: conditional

/config/www/images/

mi-air-purifier-3h_off mi-air-purifier-3h_on

Optional PM sensor
Hardware used:

  • wemos d1 mini
  • pms7003

Replace all instances of sensor.mi_air_purifier_air_quality_pm25 with sensor.bedroom_pm_pm_2_5um in automation file.

ESPHOME config:

substitutions:
  devicename: esp_env02
  human_devicename: Bedroom PM

esphome:
  name: $devicename
  platform: ESP8266
  board: d1_mini
  on_boot:
      - switch.turn_on: pms_set
      - delay: 3s
      - switch.turn_off: pms_set

#<<: !include common/common.yaml
<<: !include common/time.yaml
<<: !include common/wifi.yaml
<<: !include common/api.yaml
<<: !include common/ota.yaml
<<: !include common/web_server.yaml
<<: !include common/text_sensors.yaml
logger:
  level: DEBUG
  baud_rate: 0
  esp8266_store_log_strings_in_flash: false

interval:
  - interval: 60s
    then:
      - if:
          condition:
            - lambda: 'return id(purifier_favorite).state == false;'
          then:
            - switch.turn_on: pms_set
            - delay: 3s
            - switch.turn_off: pms_set

  - interval: 10s
    then:
      - if:
          condition:
            - lambda: 'return id(purifier_favorite).state == true;'
          then:
            - switch.turn_on: pms_set
            - delay: 3s
            - switch.turn_off: pms_set

sensor:
  - !include common/sensor/wifi-signal.yaml
  - !include common/sensor/uptime.yaml

  - platform: pmsx003
    type: PMSX003
    pm_1_0:
      name: ${human_devicename} PM 1.0µm
      icon: mdi:air-filter
      accuracy_decimals: 0
      filters:
        - throttle: 3s
        - delta: 1
    pm_2_5:
      name: ${human_devicename} PM 2.5µm
      icon: mdi:air-filter
      accuracy_decimals: 0
      filters:
        - throttle: 3s
        - delta: 1
    pm_10_0:
      name: ${human_devicename} PM 10.0µm
      icon: mdi:air-filter
      accuracy_decimals: 0
      filters:
        - throttle: 3s
        - delta: 1

binary_sensor:
  - !include common/binary_sensor/status.yaml
  
  - platform: homeassistant
    internal: true
    id: purifier_favorite
    entity_id: binary_sensor.mi_air_purifier_mode_favorite

switch:
  - !include common/switch/restart.yaml
  - platform: gpio
    internal: true
    pin: GPIO0
    id: pms_set

uart:
  tx_pin: GPIO1
  rx_pin: GPIO3
  baud_rate: 9600
2 Likes

Hi @Tomaae. Nice work and I have added it on the top of this topic. Indeed, calling a service instead of “double” automation (input to and from the purifier) could be very useful to avoid ping pong. Some of the automations are really interesting like silence during the night hours and off/on when a window is open. Also the work on graphical interface.
I am having some additional ideas and will try to add my input on your work on the next days. Could you also post a picture with favorite level selection?

Oh yeah, I forgot to add notes about extra automation I have.
I want to expand on them too. Like changing favorite level when enabling fav mode, instead of just time based and maybe reworking whole time based model to “above/bellow” triggers.
I’m also integrating separate PM sensor based on ESPHOME and pms7003 which will be located further away from my purifier so I can have it work more effectively. It is also far more responsive compared to build in one.

Favorite level selection is the same as yours, I have not yet found a way to integrate it into picture elements.

I have integrated a simplified version of yours to test functionalities. Indeed calling the service is better than “double” automation.
image
but I am now thinking on something a little bit different to present also the aqi colored. I have pictures ready but let see when I am going to have time to integrate them

MI-g MI-y MI-r MI

Oh yes, using services works reliably. Before I switched to services, I had previous settings return back about 80% of the time. But that could be issue with 3H and its unreliable wifi.
Using color for AQI is nice, I just used it to indicate on/off status. Its really simple to implement tho, if you want to use it in that way.
But if you use image so large, there may not be space for status text and control buttons without having it feel crowded.

Hi, I figured out how to add favorite and fun as conditional.
This is still working progress to add aqi colors, humidity and temperature like on purifier display.
Below is the work so far based on your template:
off
fan favorite silent auto

new sensor in configuration.yaml

sensor:
      mi_air_purifier_favorite_level:
        friendly_name: "Favorite Level"
#        value_template: "{{ state_attr('fan.mi_air_purifier_3h', 'favorite_level') }}"
        value_template: >
           {% if state_attr('fan.mi_air_purifier_3h', 'favorite_level') == None %}
            {{ 0 }}
           {%- else -%}
            {{ state_attr('fan.mi_air_purifier_3h', 'favorite_level') }}
           {% endif %}
        icon_template: "mdi:weather-windy"

Dashboard:

type: picture-elements
image: local/images/mi-air-purifier-3h.jpg
elements:
  - type: image
    entity: fan.mi_air_purifier_3h
    state_image:
      'on': local/images/mi-air-purifier-3h_on.jpg
      'off': local/images/mi-air-purifier-3h_off.jpg
    style:
      top: 32%
      left: 73.3%
  - type: state-icon
    entity: binary_sensor.mi_air_purifier_mode_off
    title: 'Off'
    icon: 'mdi:power-standby'
    tap_action:
      action: call-service
      service: fan.turn_off
      service_data:
        entity_id: fan.mi_air_purifier_3h
    style:
      top: 5%
      left: 6%
      transform: 'translate(-50%, 0)'
      background-color: 'rgb(41, 41, 41)'
      border-radius: 20px
  - type: state-label
    entity: fan.mi_air_purifier_3h
    attribute: aqi
    style:
      top: 21%
      left: 73.3%
      min-width: 40px
      min-height: 40px
      text-align: center
      transform: 'translate(-50%, 0)'
      color: 'rgb(255,255,255)'
      background-color: 'rgb(0, 2, 0)'
      border-radius: 20px
  - type: state-icon
    entity: binary_sensor.mi_air_purifier_mode_auto
    title: Auto
    icon: 'mdi:autorenew'
    tap_action:
      action: call-service
      service: fan.set_speed
      service_data:
        entity_id: fan.mi_air_purifier_3h
        speed: Auto
    style:
      top: 40%
      left: 6%
      transform: 'translate(-50%, 0)'
      background-color: 'rgb(41, 41, 41)'
      border-radius: 20px
  - type: state-icon
    entity: binary_sensor.mi_air_purifier_mode_silent
    title: Silent
    icon: 'mdi:power-sleep'
    tap_action:
      action: call-service
      service: fan.set_speed
      service_data:
        entity_id: fan.mi_air_purifier_3h
        speed: Silent
    style:
      top: 40%
      left: 16%
      transform: 'translate(-50%, 0)'
      background-color: 'rgb(41, 41, 41)'
      border-radius: 20px
  - type: state-icon
    entity: binary_sensor.mi_air_purifier_mode_favorite
    title: Favorite
    icon: 'mdi:heart'
    tap_action:
      action: call-service
      service: fan.set_speed
      service_data:
        entity_id: fan.mi_air_purifier_3h
        speed: Favorite
    style:
      top: 40%
      left: 26%
      transform: 'translate(-50%, 0)'
      background-color: 'rgb(41, 41, 41)'
      border-radius: 20px
  - type: state-icon
    entity: binary_sensor.mi_air_purifier_mode_fan
    title: Fan
    icon: 'mdi:fan'
    tap_action:
      action: call-service
      service: fan.set_speed
      service_data:
        entity_id: fan.mi_air_purifier_3h
        speed: Fan
    style:
      top: 40%
      left: 36%
      transform: 'translate(-50%, 0)'
      background-color: 'rgb(41, 41, 41)'
      border-radius: 20px
  - type: conditional
    conditions:
      - entity: binary_sensor.mi_air_purifier_mode_fan
        state: 'on'
    elements:
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_fan_1
        title: Fan level 1
        icon: 'mdi:fan-speed-1'
        tap_action:
          action: call-service
          service: xiaomi_miio.fan_set_fan_level
          service_data:
            entity_id: fan.mi_air_purifier_3h
            level: 1
        style:
          top: 70%
          left: 16%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_fan_2
        title: Fan level 2
        icon: 'mdi:fan-speed-2'
        tap_action:
          action: call-service
          service: xiaomi_miio.fan_set_fan_level
          service_data:
            entity_id: fan.mi_air_purifier_3h
            level: 2
        style:
          top: 70%
          left: 26%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: state-icon
        entity: binary_sensor.mi_air_purifier_mode_fan_3
        title: Fan level 3
        icon: 'mdi:fan-speed-3'
        tap_action:
          action: call-service
          service: xiaomi_miio.fan_set_fan_level
          service_data:
            entity_id: fan.mi_air_purifier_3h
            level: 3
        style:
          top: 70%
          left: 36%
          transform: 'translate(-50%, 0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
  - type: conditional
    conditions:
      - entity: binary_sensor.mi_air_purifier_mode_favorite
        state: 'on'
    elements:
      - type: state-label
        entity: sensor.mi_air_purifier_favorite_level
        style:
          top: 70%
          left: 26%
          min-width: 40px
          min-height: 40px
          text-align: center
          transform: 'translate(-50%, 0)'
          color: 'rgb(255,255,0)'
          background-color: 'rgb(0, 2, 0)'
          border-radius: 20px
      - type: icon
        icon: 'mdi:plus'
        tap_action:
          action: call-service
          service: input_number.increment
          service_data:
            entity_id: input_number.mi_air_purifier_favorite_level
        style:
          top: 75%
          left: 36%
          transform: 'translate(-50%, 0)'
          color: 'rgb(255,255,0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px
      - type: icon
        icon: 'mdi:minus'
        tap_action:
          action: call-service
          service: input_number.decrement
          service_data:
            entity_id: input_number.mi_air_purifier_favorite_level
        style:
          top: 75%
          left: 16%
          transform: 'translate(-50%, 0)'
          color: 'rgb(255,255,0)'
          background-color: 'rgb(41, 41, 41)'
          border-radius: 20px

Oh, thats a great idea, I will try it out too. Hopefully 3H will play nicely with it.
I have also implemented all those automation changes I mentioned. Its really smooth now and very fast. Specially with external sensor.
I have added code for that one too, but thats WIP as I want to add more sensors there. That wont have any effect on purifier tho.

PS: is new sensor really needed? cant it be handled by input_number.mi_air_purifier_favorite_level?

Haven’t figured out how to display the favourite value using input number as integer and not decimal like 4.0, 7.0. I was tried this also initially. So that was the ideea it came to me in order to display integer values.