Lovelace: Xiaomi - Mi air purifier 3H card

@uss I am not introducing any cloud credentials just the local IPs and token so don’t see any reason why not to work. Maybe HA is not working without internet

1 Like

In my configuration, as long as one presses the preset mode button on the card, or the favorite levels, the purifier reacts instantly and the change on the card is instantly.
I am using as the mode sensor a template for fan preset_mode, instead of a binary sensor for fan mode and fan state on.
There are 2 issues thought.
First time after a reboot, it takes 20-30 seconds (the delay you are talking about) to get the status for the preset mode.
The same if one presses the physical button on the purifier.

I can only suggest you to voice your opinion in the Github, hopefully it can put a bit of pressure on the developers.

Can you use the mode sensor, to show the state in a lovelace card?

In that case, would you mind posting it? Would love to check out if it would alleviate things.

This is the card:

type: picture-elements
title: Pi2 Air-Purifier
image: local/pictures/XiaomiAir2S/Air2SOff.png
elements:
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
    elements:
      - type: image
        image: local/pictures/XiaomiAir2S/Air2SOn.png
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        style:
          top: 50%
          left: 50%
          width: 100%
  - type: conditional
    conditions:
      - entity: switch.pi2_led
        state: 'off'
    elements:
      - type: image
        image: local/pictures/XiaomiAir2S/Air2SOff.png
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        style:
          top: 50%
          left: 50%
          width: 100%
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
    elements:
      - title: Led
        type: state-icon
        icon: hass:white-balance-sunny
        entity: switch.pi2_led
        tap_action:
          action: toggle
        style:
          top: 9%
          left: 15%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
    elements:
      - title: Child Lock
        type: state-icon
        icon: hass:lock
        entity: switch.pi2_child_lock
        tap_action:
          action: toggle
        style:
          top: 59%
          left: 15%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
    elements:
      - title: Buzzer
        type: state-icon
        icon: hass:volume-high
        entity: switch.pi2_buzzer
        tap_action:
          action: toggle
        style:
          top: 59%
          left: 85%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'off'
    elements:
      - title: Mode
        type: state-icon
        icon: hass:cached
        entity: fan.pi2
        tap_action:
          action: call-service
          service: switch.turn_on
          service_data:
            entity_id: switch.pi2_led
        hold_action:
          action: call-service
          service: fan.turn_off
          service_data:
            entity_id: fan.pi2
        style:
          top: 9%
          left: 85%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'off'
    elements:
      - title: 'Off'
        type: state-icon
        icon: hass:cached
        entity: fan.pi2
        tap_action:
          action: call-service
          service: fan.turn_on
          service_data:
            entity_id: fan.pi2
        style:
          top: 9%
          left: 85%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(128, 128, 128)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
      - entity: sensor.pi2_preset_mode_template
        state: Auto
    elements:
      - title: Mode Auto
        type: image
        image: local/pictures/XiaomiAir2S/Air2SAuto.png
        entity: fan.pi2
        tap_action:
          action: more-info
        style:
          top: 39%
          left: 65%
          width: 5%
          transform: translate(-50%, 0)
      - title: AutoMode
        type: state-icon
        icon: hass:cached
        entity: fan.pi2
        tap_action:
          action: call-service
          service: fan.set_preset_mode
          service_data:
            entity_id: fan.pi2
            preset_mode: Silent
        hold_action:
          action: call-service
          service: fan.turn_off
          service_data:
            entity_id: fan.pi2
        style:
          top: 9%
          left: 85%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
      - entity: sensor.pi2_preset_mode_template
        state: Silent
    elements:
      - title: Mode Silent
        type: image
        image: local/pictures/XiaomiAir2S/Air2SSilent.png
        entity: fan.pi2
        tap_action:
          action: more-info
        style:
          top: 39%
          left: 65%
          width: 5%
          transform: translate(-50%, 0)
      - title: SilentMode
        type: state-icon
        icon: hass:cached
        entity: fan.pi2
        tap_action:
          action: call-service
          service: fan.set_preset_mode
          service_data:
            entity_id: fan.pi2
            preset_mode: Favorite
        hold_action:
          action: call-service
          service: fan.turn_off
          service_data:
            entity_id: fan.pi2
        style:
          top: 9%
          left: 85%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
      - entity: sensor.pi2_preset_mode_template
        state: Favorite
    elements:
      - title: Mode Favorite
        type: image
        image: local/pictures/XiaomiAir2S/Air2SFavorite.png
        entity: fan.pi2
        tap_action:
          action: more-info
        style:
          top: 39%
          left: 65%
          width: 5%
          transform: translate(-50%, 0)
      - title: FavoriteMode
        type: state-icon
        icon: hass:cached
        entity: fan.pi2
        tap_action:
          action: call-service
          service: fan.set_preset_mode
          service_data:
            entity_id: fan.pi2
            preset_mode: Auto
        hold_action:
          action: call-service
          service: fan.turn_off
          service_data:
            entity_id: fan.pi2
        style:
          top: 9%
          left: 85%
          '--mdc-icon-size': 40px
          transform: translate(-50%, 0)
          '--paper-item-icon-active-color': rgb(255, 128, 0)
      - title: Favorite level
        type: state-label
        entity: sensor.pi2_favorite_level_template
        tap_action:
          action: none
        style:
          top: 53%
          left: 50%
          min-width: 40px
          min-height: 40px
          text-align: center
          font-size: 200%
          transform: translate(-50%, 0)
          color: rgb(255, 128, 0)
      - title: Favorite level +
        type: icon
        icon: hass:plus
        tap_action:
          action: call-service
          service: script.pi2_favorite_up
        style:
          top: 54.5%
          left: 60%
          min-width: 40px
          min-height: 40px
          transform: translate(-50%, 0)
          color: rgb(192, 192, 192)
          color_off: rgb(255, 128, 0)
      - title: Favorite level -
        type: icon
        icon: hass:minus
        tap_action:
          action: call-service
          service: script.pi2_favorite_down
        style:
          top: 54.5%
          left: 44%
          min-width: 40px
          min-height: 40px
          transform: translate(-50%, 0)
          color: rgb(192, 192, 192)
          color_off: rgb(255, 128, 0)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
    elements:
      - title: PM2.5
        type: state-label
        entity: sensor.pi2_pm2_5_template
        tap_action:
          action: more-info
        style:
          top: 26%
          left: 49%
          text-align: center
          font-size: 500%
          transform: translate(-50%, 0)
          color: rgb(255,255,255)
      - title: Temperature
        type: state-label
        entity: sensor.pi2_temperature_template
        tap_action:
          action: more-info
        style:
          top: 37.2%
          left: 36%
          text-align: center
          font-size: 190%
          transform: translate(-50%, 0)
          color: rgb(255,255,255)
      - type: icon
        icon: hass:temperature-celsius
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        style:
          top: 39.7%
          left: 41%
          '--mdc-icon-size': 17px
          transform: translate(-50%, 0)
          color: rgb(255,255,255)
      - title: Humidity
        type: state-label
        entity: sensor.pi2_humidity_template
        tap_action:
          action: more-info
        style:
          top: 37.2%
          left: 47%
          text-align: center
          font-size: 190%
          transform: translate(-50%, 0)
          color: rgb(255,255,255)
      - type: icon
        icon: hass:percent-outline
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        style:
          top: 39.7%
          left: 52%
          '--mdc-icon-size': 17px
          transform: translate(-50%, 0)
          color: rgb(255,255,255)
      - type: icon
        icon: hass:wifi
        tap_action:
          action: none
        hold_action:
          action: none
        double_tap_action:
          action: none
        style:
          top: 39.2%
          left: 58%
          '--mdc-icon-size': 22px
          transform: translate(-50%, 0)
          color: rgb(255,255,255)
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
      - entity: sensor.pi2_pm25_severity_template
        state: clean
    elements:
      - title: PM2.5 Clean
        type: image
        image: local/pictures/XiaomiAir2S/Air2SStatusClean.png
        entity: sensor.pi2_pm25_severity_template
        tap_action:
          action: more-info
        state_image: null
        style:
          top: 52%
          left: 50%
          width: 18%
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
      - entity: sensor.pi2_pm25_severity_template
        state: polluted
    elements:
      - title: PM2.5 Polluted
        type: image
        image: local/pictures/XiaomiAir2S/Air2SStatusPolluted.png
        entity: sensor.pi2_pm25_severity_template
        tap_action:
          action: more-info
        state_image: null
        style:
          top: 52%
          left: 50%
          width: 18%
  - type: conditional
    conditions:
      - entity: fan.pi2
        state: 'on'
      - entity: switch.pi2_led
        state: 'on'
      - entity: sensor.pi2_pm25_severity_template
        state: critical
    elements:
      - title: PM2.5 Critical
        type: image
        image: local/pictures/XiaomiAir2S/Air2SStatusCritical.png
        entity: sensor.pi2_pm25_severity_template
        tap_action:
          action: more-info
        state_image: null
        style:
          top: 52%
          left: 50%
          width: 19%

This is template.yaml

sensor:
#===================================#
#  Mi Air Purifier Pi2 (Model 2S)   #
#===================================#
  - name: pi2_pm2_5_template
    state: "{{ states('sensor.pi2_pm2_5')|float|round|int }}"
  - name: pi2_temperature_template
    state: "{{ states('sensor.pi2_temperature')|float|round|int }}"
  - name: pi2_humidity_template
    state: "{{ states('sensor.pi2_humidity')|float|round|int }}"
  - name: pi2_pm25_severity_template
    state: >
      {% set pm2_5 = states('sensor.pi2_pm2_5')|float|round|int %}
      {% if pm2_5 > 150 %}
        {{ 'critical' }}
      {% elif pm2_5 > 75 %}
        {{ 'polluted' }}
      {% else %}
        {{ 'clean' }}
      {% endif %}
  - name: pi2_preset_mode_template
    state: "{{ state_attr('fan.pi2', 'preset_mode') }}"
  - name: pi2_favorite_level_template
    state: "{{ states('number.pi2_favorite_level')|float|round|int }}"

Here you have script.yaml

#===================================#
#  Mi Air Purifier Pi2 (Model 2S)   #
#===================================#
pi2_favorite_up:
  sequence:
  - service: number.set_value
    data:
      value: >
       {% set level = states('number.pi2_favorite_level')|int + 1 %}
       {% if level < 14 %}
          {{ level|float|round|int }} 
        {% else %} 
          {{ 14 }} 
        {% endif %}
    target:
      entity_id: number.pi2_favorite_level
  mode: single

pi2_favorite_down:
  sequence:
  - service: number.set_value
    data:
      value: >
       {% set level = states('number.pi2_favorite_level')|int - 1 %}
       {% if level > 0  %}
         {{ level|float|round|int }}
       {% else %}
         {{ 0 }} 
       {% endif %}
    target:
      entity_id: number.pi2_favorite_level
  mode: single

Pictures
Air2S
Air2SAuto
Air2SDivider
Air2SFavorite
Air2SOff
Air2SOn
Air2SSilent
Air2SStatusClean
Air2SStatusCritical
Air2SStatusPolluted

1 Like

Thank you!

@uss I have noticed you are missing the Fun levels (don’t know if available on your purifier), this is exactly where we are using binary sensors and where we noticed the delay in displaying the changes.

Sorry. I don’t understand what you mean.
I do read he fan levels.

And act on them in script.yaml.

image

image

We are having “Fun” and 3 predefined levels - speed 33.33, 66.66, 100%

Ohhh!
I forgot to copy the line

sensor:

in template.yaml. I have other sensor templates and I have taken only the purifier code.
I made the correction.

I see what you mean. I don’t have the model 3. What fan does?

I mean, what is the difference between Favorite and Fan?

“Fun” - 3 predefined levels - speed 33.33, 66.66, 100%

And Favorite?

15 predefined levels - in native Mi Home app corresponds to 15 manually selected coverage areas

I see. Then it is easy.
Define in template.yaml another sensor, something like:

- name: pi2_fan_level_template
    state: >
      {% fan_level=states('number.pi2_favorite_level') %}
      {% if fan_level > 10 %}
        {{ 'high' }}
      {% elif fan_level > 5 %}
        {{ 'medium' }}
      {% else %}
        {{ 'low' }}
      {% endif %}

and in script.yaml the other way around.

You can use those 2 in Lovelace to have the status and the action

Could be a solution. Not entirely sure that 4 correspond to low, 9 to medium and 14 to high but worth checking. However in Miio 3H we have this predefined in speed list. and also in percentage step.

I reckon you don’t have the number.pi2_favorite_level defined in MIoT, but you can translate the percentage in levels with a template.

On the other hand, I’ve been thinking about what you said, that having in MIoT only the local IP and the token means it is local. I’m not entirely sure about that. Having the token means you already are enrolled on the cloud, then the device knows what the cloud address is and the cloud knows who you are based on the token.

But you did not provide any credentials. On the other hand you could reset the wifi, get the new token without enrolling it in the cloud. The product can be integrate into HA. Worth testing