Xiaomi Air Purifier - Show all sensors and Switches in UI and HomeKit

Having support for Xiaomi Air Purifier’s is awesome. Still the component fan.xiaomi_miio lacks in functionality in the UI as i described on GitHub.

It took me more than 5 hours now to make the config show all sensors and switches in the UI and create needed automations. Therefor i thought it is better to post it here in case someone else might want to use it or even extend it. I would really appreciate any further development or improvements!

I even integrated it into Homekit as good as possible. At least the humidity and air quality sensor did not work out of the box but now they do.

Also i quality-hand-picked fitting icons :slight_smile:

This is how it looks like:

Of course you can customize the layout, put it all together in one card or remove entities as you want.

configuration.yaml

fan:
  # Xiaomi Air Purifier 2S
  - platform: xiaomi_miio
    host: IP
    token: TOKEN
    name: "Xiaomi Air Purifier 2S"
    
sensor:
  # Xiaomi Air Purifier 2S
  - platform: template
    sensors:
      xiaomi_airpurifier_temp:
        friendly_name: "Temperature"
        value_template: "{{ state_attr('fan.xiaomi_miio_device', 'temperature') }}"
        unit_of_measurement: "°C"
        device_class: "temperature"
      xiaomi_airpurifier_humidity:
        friendly_name: "Humidity"
        value_template: "{{ state_attr('fan.xiaomi_miio_device', 'humidity') }}"
        unit_of_measurement: "%"
        device_class: "humidity"
      xiaomi_airpurifier_air_quality_pm25:
        friendly_name: "Air quality"
        value_template: "{{ state_attr('fan.xiaomi_miio_device', 'aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-fog"
      xiaomi_airpurifier_speed:
        friendly_name: "Fan speed"
        value_template: "{{ state_attr('fan.xiaomi_miio_device', 'motor_speed') }}"
        unit_of_measurement: "rpm"
        icon_template: "mdi:speedometer"
      xiaomi_airpurifier_filter_remaining:
        friendly_name: "Filter remaining"
        value_template: "{{ state_attr('fan.xiaomi_miio_device', 'filter_life_remaining') }}"
        unit_of_measurement: "%"
        icon_template: "mdi:heart-outline"

switch:
  # Xiaomi Air Purifier 2S
  - platform: template
    switches:
      xiaomi_airpurifier_led:
        friendly_name: "LED"
        value_template: "{{ is_state_attr('fan.xiaomi_miio_device', 'led', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_led_on
          data:
            entity_id: fan.xiaomi_miio_device
        turn_off:
          service: xiaomi_miio.fan_set_led_off
          data:
            entity_id: fan.xiaomi_miio_device
        icon_template: "mdi:lightbulb-outline"
      xiaomi_airpurifier_child_lock:
        friendly_name: "Child lock"
        value_template: "{{ is_state_attr('fan.xiaomi_miio_device', 'child_lock', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_child_lock_on
          data:
            entity_id: fan.xiaomi_miio_device
        turn_off:
          service: xiaomi_miio.fan_set_child_lock_off
          data:
            entity_id: fan.xiaomi_miio_device
        icon_template: "mdi:lock-outline"
      xiaomi_airpurifier_buzzer:
        friendly_name: "Buzzer"
        value_template: "{{ is_state_attr('fan.xiaomi_miio_device', 'buzzer', true) }}"
        turn_on:
          service: xiaomi_miio.fan_set_buzzer_on
          data:
            entity_id: fan.xiaomi_miio_device
        turn_off:
          service: xiaomi_miio.fan_set_buzzer_off
          data:
            entity_id: fan.xiaomi_miio_device
        icon_template: "mdi:volume-high"
  
input_select:
  # Xiaomi Air Purifier 2S
  xiaomi_airpurifier_mode:
    name: Mode
    options:
      - Auto
      - Silent
      - Favorite
    icon: "mdi:animation-outline"

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

automation.yaml

# Xiaomi Air Purifier 2S
- alias: Air Purifier mode change
  trigger:
    entity_id: input_select.xiaomi_airpurifier_mode
    platform: state
  action:
    service: fan.set_speed
    data_template:
      entity_id: fan.xiaomi_miio_device
      speed: '{{ states.input_select.xiaomi_airpurifier_mode.state }}'
- alias: Air Purifier mode changed
  trigger:
    platform: state
    entity_id: fan.xiaomi_miio_device
  action:
    service: input_select.select_option
    entity_id: input_select.xiaomi_airpurifier_mode
    data_template:
      option: '{{ states.fan.xiaomi_miio_device.attributes.speed }}'
- alias: Air Purifier favorite level change
  trigger:
    entity_id: input_number.xiaomi_airpurifier_favorite_level
    platform: state
  action:
    service: xiaomi_miio.fan_set_favorite_level
    data_template:
      entity_id: fan.xiaomi_miio_device
      level: '{{ states.input_number.xiaomi_airpurifier_favorite_level.state | int }}'
- alias: Air Purifier favorite level changed
  trigger:
    platform: state
    entity_id: fan.xiaomi_miio_device
  action:
    service: input_number.set_value
    entity_id: input_number.xiaomi_airpurifier_favorite_level
    data_template:
      value: '{{ states.fan.xiaomi_miio_device.attributes.favorite_level }}'

cards:

- entities:
    - entity: fan.xiaomi_miio_device
    - entity: input_select.xiaomi_airpurifier_mode
    - entity: input_number.xiaomi_airpurifier_favorite_level
    - entity: switch.xiaomi_airpurifier_child_lock
    - entity: switch.xiaomi_airpurifier_led
    - entity: switch.xiaomi_airpurifier_buzzer
    - entity: sensor.xiaomi_airpurifier_speed
    - entity: sensor.xiaomi_airpurifier_filter_remaining
    show_header_toggle: false
    theme: default
    title: Air Purifier
    type: entities
- entities:
    - entity: sensor.xiaomi_airpurifier_air_quality_pm25
    - entity: sensor.xiaomi_airpurifier_temp
    - entity: sensor.xiaomi_airpurifier_humidity
  show_header_toggle: false
  theme: default
  title: Environment
  type: entities
- entities:
    - sensor.xiaomi_airpurifier_air_quality_pm25
  hours_to_show: 80
  refresh_interval: 60
  title: Air quality
  type: history-graph

Greetings

39 Likes

Thanks for sharing :slight_smile:

I think that should be configuration.yaml, not .yml

I just added the missing functionality (automation) for the mode-select and favorite-level-slider and cleaned up the code a little bit. It took me another few hours doing so. I hope i got everything now and someone might find this useful :slight_smile:

Also I hope very much that this will be integrated into fan.xiaomi_miio as a default so we dont have to do all this setup. Also when adding a second Air Purifier you have to duplicate all the above code(which results in a mess) change alle the ids(which results in a lot of work and probably made mistakes).

2 Likes

Found one error: [homeassistant.components.homekit.util] ['Auto', 'Silent', 'Favorite'] does not contain the speed setting off as its first element. Assuming that Auto is equivalent to 'off'.

No time to fix now. Maybe someone has an idea.

1 Like

Thank you very much, it was very helpful.

In my case, I had problems with the connection of Xiaomi Air Purifier 2S
I did it for the first time.
that’s how it works for me

 # Xiaomi Air Purifier 2S
 - platform: xiaomi_miio
      name: Air Purifier 2S	         // name: fan.air_purifier_2s
      host: 192.168.1.xx
      token: TOKEN

I replaced fan.xiaomi_miio_device with fan.air_purifier_2s and it all worked.

Thank you very much

1 Like

@MickL Thanks for sharing.

In automation.yaml replace “speed” for “mode”:

- alias: Air Purifier mode changed
  trigger:
    platform: state
    entity_id: fan.xiaomi_miio_device
  action:
    service: input_select.select_option
    entity_id: input_select.xiaomi_airpurifier_mode
    data_template:
      option: '{{ states.fan.xiaomi_miio_device.attributes.mode }}' #- speed for mode
1 Like

Just got the device. Your config is great. Thanks a lot for sharing.

1 Like

I follow the above great sample without problem for my first unit. However, when adding the second unit with similar config, it won’t recognize and create the second unit entity.

The solution is to add “model” under the “fan:” config section:

fan:
# xiaomi purifier in main bedroom
  - platform: xiaomi_miio
    name: Xiaomi Air Purifier Bedroom
    host: 192.168.x.xx0
    token: ....token 1........
    model: zhimi.airpurifier.mc1
# xiaomi purifier in mezzanine
  - platform: xiaomi_miio
    name: Xiaomi Air Purifier Mezzanine
    host: 192.168.x.xx1
    token: .....token 2......
    model: zhimi.airpurifier.mc1

By adding the model:

  • the device name is now recognized as what we define in “name:”, no longer be “fan.xiaomi_miio_device” for the first unit that you created before. So the above sample will create two entities named “fan.xiaomi_air_purifier_bedroom” and “fan.xiaomi_air_purifier_mezzanine”, respecitively.

Then we can add further config for as many units as we like.

1 Like

Works great, thank you.

How to add a button to the card to “reset filter” after replacement? I see in the binding page:
SERVICE FAN.XIAOMI_MIIO_RESET_FILTER
And that would require a pushbutton, not a toggle.

Anyone else having issues with the automations being constantly triggerd as seen in the log? It goes on and on, almost every minute.

Screenshot

2 Likes

For some reason nothing happens when I switch the fan speeds on the favorite mode. Am I the only one with the issue? mc1 is the device.

Just for your comparison. This automation script works for me.

# Xiaomi Air Purifier 2S
  # Bedroom
  - alias: Air Purifier mode change
    trigger:
      entity_id: input_select.xiaomi_airpurifier_mode
      platform: state
    action:
      service: fan.set_speed
      data_template:
        entity_id: fan.xiaomi_air_purifier_bedroom
        speed: '{{ states.input_select.xiaomi_airpurifier_mode.state }}'
  - alias: Air Purifier mode changed
    trigger:
      platform: state
      entity_id: fan.xiaomi_air_purifier_bedroom
    action:
      service: input_select.select_option
      entity_id: input_select.xiaomi_airpurifier_mode
      data_template:
        option: '{{ states.fan.xiaomi_air_purifier_bedroom.attributes.speed }}'
  - alias: Air Purifier favorite level change
    trigger:
      entity_id: input_number.xiaomi_airpurifier_favorite_level
      platform: state
    action:
      service: fan.xiaomi_miio_set_favorite_level
      data_template:
        entity_id: fan.xiaomi_air_purifier_bedroom
        level: '{{ states.input_number.xiaomi_airpurifier_favorite_level.state | int }}'
  - alias: Air Purifier favorite level changed
    trigger:
      platform: state
      entity_id: fan.xiaomi_air_purifier_bedroom
    action:
      service: input_number.set_value
      entity_id: input_number.xiaomi_airpurifier_favorite_level
      data_template:
        value: '{{ states.fan.xiaomi_air_purifier_bedroom.attributes.favorite_level }}'
  - alias: Air Purifier mode changed
    trigger:
      platform: state
      entity_id: fan.xiaomi_air_purifier_bedroom
    action:
      service: input_select.select_option
      entity_id: input_select.xiaomi_airpurifier_mode
      data_template:
        option: '{{ states.fan.xiaomi_air_purifier_bedroom.attributes.mode }}' #- speed for mode
1 Like

@bthoven @MickL Where should I place the code for the cards?

Right now I filled only the automations.yaml and configuration.yaml and indeed I get the constant triggering as reported by @karsie

I don’t know what causes your problem. Just for your reference, belows are my setup in configuration.yaml:
image

and under sensor: section

  # Xiaomi Air Purifier 2S
  - platform: template
    sensors:
      xiaomi_airpurifier_temp:
        friendly_name: "Temperature"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_bedroom', 'temperature') }}"
        unit_of_measurement: "°C"
        device_class: "temperature"
      xiaomi_airpurifier_humidity:
        friendly_name: "Humidity"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_bedroom', 'humidity') }}"
        unit_of_measurement: "%"
        device_class: "humidity"
      xiaomi_airpurifier_air_quality_pm25:
        friendly_name: "Air quality"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_bedroom', 'aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-fog"
      xiaomi_airpurifier_speed:
        friendly_name: "Fan speed"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_bedroom', 'motor_speed') }}"
        unit_of_measurement: "rpm"
        icon_template: "mdi:speedometer"
      xiaomi_airpurifier_filter_remaining:
        friendly_name: "Filter remaining"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_bedroom', 'filter_life_remaining') }}"
        unit_of_measurement: "%"
        icon_template: "mdi:heart-outline"
# mezzanine
      xiaomi_airpurifier_temp2:
        friendly_name: "Temperature"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_mezzanine_2', 'temperature') }}"
        unit_of_measurement: "°C"
        device_class: "temperature"
      xiaomi_airpurifier_humidity2:
        friendly_name: "Humidity"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_mezzanine_2', 'humidity') }}"
        unit_of_measurement: "%"
        device_class: "humidity"
      xiaomi_airpurifier_air_quality_pm252:
        friendly_name: "Air quality"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_mezzanine_2', 'aqi') }}"
        unit_of_measurement: "μg/m³"
        icon_template: "mdi:weather-fog"
      xiaomi_airpurifier_speed2:
        friendly_name: "Fan speed"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_mezzanine_2', 'motor_speed') }}"
        unit_of_measurement: "rpm"
        icon_template: "mdi:speedometer"
      xiaomi_airpurifier_filter_remaining2:
        friendly_name: "Filter remaining"
        value_template: "{{ state_attr('fan.xiaomi_air_purifier_mezzanine_2', 'filter_life_remaining') }}"
        unit_of_measurement: "%"
        icon_template: "mdi:heart-outline"

Maybe it depends on the fact that I added the automations for the GUI card without actual card since I couldn’t find out where the code is supposed to go.

Everything else work fine.

Log updates constantly because what triggers the actions is entity_id itself so any change triggers the automation. To avoid this behavior I’ve added additional condition to mode_changed and favorite_level_changed automations for checking if actual speed and mode is different than is actually set in state object. That way I don’t run automation if it is not needed i.e. tries to set mode and speed to the same values. My code looks like this and works properly:

- id: mi_2s_mode_change
  alias: Air Purifier mode change
  trigger:
    entity_id: input_select.xiaomi_airpurifier_mode
    platform: state
  action:
    service: fan.set_speed
    data_template:
      entity_id: fan.mi_2s
      speed: '{{ states.input_select.xiaomi_airpurifier_mode.state }}'
- id: mi_2s_mode_changed
  alias: Air Purifier mode changed
  trigger:
    platform: state
    entity_id: fan.mi_2s
  condition:
    condition: and
    conditions:
    - condition: template
      value_template: "{{ (state_attr('fan.mi_2s', 'speed') | string) != (states('input_select.xiaomi_airpurifier_mode') | string) }}"
  action:
    service: input_select.select_option
    entity_id: input_select.xiaomi_airpurifier_mode
    data_template:
      option: '{{ states.fan.mi_2s.attributes.speed }}'
      
- id: mi_2s_favorite_level_change
  alias: Air Purifier favorite level change
  trigger:
    entity_id: input_number.xiaomi_airpurifier_favorite_level
    platform: state
  action:
    service: fan.xiaomi_miio_set_favorite_level
    data_template:
      entity_id: fan.mi_2s
      level: '{{ states.input_number.xiaomi_airpurifier_favorite_level.state | int }}'
      
- id: mi_2s_favorite_level_changed
  alias: Air Purifier favorite level changed
  trigger:
    platform: state
    entity_id: fan.mi_2s
  condition:
    condition: and
    conditions:
    - condition: template
      value_template: "{{ (state_attr('fan.mi_2s', 'favorite_level') | int) != (states('input_number.xiaomi_airpurifier_favorite_level') | int) }}"
  action:
    service: input_number.set_value
    entity_id: input_number.xiaomi_airpurifier_favorite_level
    data_template:
      value: '{{ states.fan.mi_2s.attributes.favorite_level }}'

hope it helps :slight_smile:

3 Likes

I think the best way is to switch UI to yaml mode. Just read the docs: https://www.home-assistant.io/lovelace/yaml-mode/
You should create file ui-lovelace.yaml and include it into configuration.yaml like this:

lovelace:
  mode: yaml

Then you can start creating your UI layout design with cards and others.

I solved by adding “manual cards”

It helped me a lot! Thanks :slight_smile:
But I have another issue… When air purifer is turned off the " [Air Purifier mode changed]" is still triggered. When it is turned on, it is ok.

Someone mentioned before that when turned off it has different state then “Auto, Silent, Favorite”. So maybe this is a issue? Have you got any idea?