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.
/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/
Optional PM sensor
Hardware used:
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