How to combine the two, if combining makes any sense

For the last few days I have been working on the automation for my Xiaomi Air Purifier 2S. After many trials and versions, and thanks to the help of the guys on this forum, I have reached the optimal version. A number of problems arose from the fact that the “off” mode is not clearly interpreted and theoretically the only valid preset modes are: Auto, Silent, Favourite. In any case, the actual code works as expected.

alias: Air purifier automation
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.air_purifier_pm2_5
    above: 85
    below: 2000
    id: Auto
  - platform: numeric_state
    entity_id:
      - sensor.air_purifier_pm2_5
    above: 35
    below: 84.9
    id: Silent
  - platform: numeric_state
    entity_id:
      - sensor.air_purifier_pm2_5
    below: 34.9
    id: "off"
    for:
      hours: 0
      minutes: 5
      seconds: 0
  - platform: state
    entity_id:
      - schedule.nighttime
condition: []
action:
  - choose:
      - conditions:
          - condition: state
            entity_id: schedule.nighttime
            state: "on"
        sequence:
          - service: switch.turn_off
            target:
              entity_id:
                - switch.air_purifier_led
                - switch.air_purifier_buzzer
            data: {}
      - conditions:
          - condition: state
            entity_id: schedule.nighttime
            state: "off"
        sequence:
          - service: switch.turn_on
            metadata: {}
            data: {}
            target:
              entity_id:
                - switch.air_purifier_buzzer
                - switch.air_purifier_led
  - if:
      - condition: template
        value_template: "{{ trigger.id != 'off' }}"
    then:
      - service: fan.set_preset_mode
        data:
          preset_mode: "{{ trigger.id }}"
        target:
          entity_id: fan.air_purifier
    else:
      - service: fan.turn_off
        target:
          entity_id: fan.air_purifier
        data: {}
mode: restart

I have a second automation handling the control of the device by the window opening sensor. Unfortunately, I don’t know how to integrate the two and whether such an integration even makes sense. I have looked through many threads on the forum but nothing comes out of them to apply to my case. Please look at what I have created and give some suggestions on what to do and how to do it. My knowledge is still too small to figure out something for practical application myself.

alias: Air purifier on/off
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.ikea_window_sensor_opening
    from: "off"
    to: "on"
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition: []
action:
  - service: fan.turn_off
    target:
      entity_id:
        - fan.air_purifier
    data: {}
  - service: automation.turn_off
    data:
      stop_actions: false
    enabled: true
    target:
      entity_id: automation.air_purifier
  - wait_for_trigger:
      - platform: state
        entity_id:
          - binary_sensor.ikea_window_sensor_opening
        from: "on"
        to: "off"
        for:
          hours: 0
          minutes: 0
          seconds: 10
    continue_on_timeout: false
  - service: automation.turn_on
    target:
      entity_id:
        - automation.air_purifier
    data: {}
    enabled: true
  - condition: numeric_state
    entity_id: sensor.air_purifier_pm2_5
    above: 1
    enabled: true
  - service: fan.turn_on
    target:
      entity_id:
        - fan.air_purifier
    data: {}
    enabled: true
mode: restart

There’s no particular benefit in combining automations - they all go in the same yaml file - and it can make them longer and harder to maintain.

The main consideration is… will this still make sense to you when you come back to it in six months? Now that we have labels and categories finding stuff is much easier. You might also look at ways of annotating automations.

Good point :+1:

1 Like

In this particular case, combining the two automations has the potential to produce a better result. There would be no need to programmatically enable/disable it (like what your second automation is currently doing) because it can determine, by itself, what it should/shouldn’t do by simply checking the window’s state.

What I’d always avoid, is turning automations on/off via another automation. This is practically an invitation to spend a lot of time in searching for an error. It’s just not really the best idea. :slight_smile:

Maybe you could tell us in simple words, what you want to do exactly.

I’ve a similar thing going with my Air Purifiers, but I do it in a totally different way. I want mine to switch from “silence” (where they are running most of the time) to “favourite” (they go nuts, because if the windows open, I want to change the air as quickly as possible) when I open my balcony door, and back to where they were, when I close the window.
I’m doing this with a scene. If I open the balcony door, I create a scene on the fly, that saves a lot of things, like the mode or the speed of the purifiers. When closing the door, I set that scene, so I get back to the state I’ve been before. Let’s say you have a party, and therefor speed up the purifier. In your case, you work with fixed values, so you would need to chanhe the settings back to your “party settings”. You get what I mean… :slight_smile:

Very interesting. Could you give me some hints, please? How do you see this possibility?
As you noted, I chose your idea because it appeared to best realise the objectives. It turned out that other solutions do not switch off the fan when the lowest PM2.5 threshold is reached.

Sure thing. I follow you.
In simple words, I need my air purifier to stop when I open the window and to start when I close it. It’s a bedroom so it’s very unlikely any party is going happen in that room. Nothing fancy, as you see.
I was also thinking of setting up a scene but other forumers have warned me that it would overcomplicate things and not contribute anything particularly valuable. I therefore created a separate automation which works well and does what it should do. I was just thinking about merging the two. And here, as you can see, there are two opinions and two points of view. Both logically convincing. To merge or not to merge, that is the question :tipping_hand_man:

Can you explain what happens when this State Trigger is triggered?

  - platform: state
    entity_id:
      - schedule.nighttime

It doesn’t have an explicit value for id so Home Assistant will automatically assign it an index value corresponding to its position in the list of triggers (it’s the fourth trigger so 4). The value isn’t off so this section of code will handle it as a preset mode and attempt to set the fan’s mode to 4.

  - if:
      - condition: template
        value_template: "{{ trigger.id != 'off' }}"
    then:
      - service: fan.set_preset_mode
        data:
          preset_mode: "{{ trigger.id }}"
        target:
          entity_id: fan.air_purifier

Is that the way you want it to work?

Thanks for your help.

The trigger is helper based. When nighttime is active, the LED and buzzer are switched off. When it is inactive, both entities are switched on. This helper is used in several other automations. I thought it can be useful for this one as well.
I wondered whether to put this in When at all, but omission caused problems with Choose action. So, it’s not about influencing fan states, it’s about controlling the LED switches and buzzer depending on the time of day. And it works as I wanted it to work. I didn’t know how else to deal with it, and the ideas noticed on the forum were overly complicated. I understand that it’s not a very clever attitude, yes?

Now this:

 - if:
      - condition: template
        value_template: "{{ trigger.id != 'off' }}"
    then:
      - service: fan.set_preset_mode
        data:
          preset_mode: "{{ trigger.id }}"
        target:
          entity_id: fan.air_purifier
    else:
      - service: fan.turn_off
        target:
          entity_id: fan.air_purifier
        data: {}

Because off is not one of the preset modes, then the automation’s action requires a if-then statement, as you advised in another post. It has to be this way. Otherwise, the air purifier is never turned off, but goes into auto mode. There is a problem with the 2S model, as it only has three states: Auto, Silent and Favorite. I tested several other solutions, and none worked flawlessly. Only the solution you suggested effectively circumvents the problem. Apart from that, it is elegantly simple.

As I explained above, the code you created does that and it also attempts to set the fan’s preset_mode (using a value of trigger.id you didn’t explicitly specify).

Check the automation’s trace when the automation was triggered by this trigger:

  - platform: state
    entity_id:
      - schedule.nighttime

Report what value it used to set the fan’s preset_mode.

If I did what you wanted me to do, it looks like this:

Result:
params:
  domain: fan
  service: set_preset_mode
  service_data:
    preset_mode: ''
    entity_id:
      - fan.air_purifier
  target:
    entity_id:
      - fan.air_purifier
running_script: false

Yes thank you, that’s exactly what’s needed. This line shows that the automation attempted to set the fan’s preset_mode to an empty string:

    preset_mode: ''

Clearly that’s undesirable so the automation should not attempt to set the preset_mode when it simply needs to turn on/off the LED and buzzer according to the schedule.

I needed to know that in order to help me finish creating a consolidated version of your two automations.

1 Like

The following automation consolidates the functionality of your two existing automations:

alias: Consolidated Air purifier automation
description: ""
trigger:
  - id: 'schedule'
    platform: state
    entity_id:
      - schedule.nighttime

  - id: 'Auto'
    platform: numeric_state
    entity_id:
      - sensor.air_purifier_pm2_5
    above: 85
    below: 2000

  - id: 'Silent'
    platform: numeric_state
    entity_id:
      - sensor.air_purifier_pm2_5
    above: 35
    below: 84.9

  - id: 'off'
    platform: numeric_state
    entity_id:
      - sensor.air_purifier_pm2_5
    below: 34.9
    for:
      minutes: 5

  - id: 'off'
    platform: state
    entity_id:
      - binary_sensor.ikea_window_sensor_opening
    from: 'off'
    to: 'on'

  - id: 'on'
    platform: state
    entity_id:
      - binary_sensor.ikea_window_sensor_opening
    from: 'on'
    to: 'off'
    for:
      seconds: 10
condition: []
action:
  - choose:
      - conditions: "{{ trigger.id == 'schedule' }}"
        sequence:
          - service: "switch.turn_{{ iif(states('schedule.nighttime') == 'on', 'off', 'on') }}"
            target:
              entity_id:
                - switch.air_purifier_led
                - switch.air_purifier_buzzer

      - conditions: "{{ trigger.id in ['off', 'on'] }}"
        sequence:
          - condition: template
            value_template: >
              {{ trigger.id == 'off' or
                (trigger.id == 'on' and states('sensor.air_purifier_pm2_5') | float(0) > 1) }}
          - service: "fan.turn_{{ trigger.id }}"
            target:
              entity_id: fan.air_purifier

    default:
      - service: fan.set_preset_mode
        data:
          preset_mode: "{{ trigger.id }}"
        target:
          entity_id: fan.air_purifier
mode: restart
4 Likes

You are the incarnated angel, truly. Thanks a lot. I wouldn’t have been able to do it myself. I don’t have enough knowledge. To top it all off, I got lost in various forum opinions and advice, often conflicting with each other :no_good_man:
I have just tested the solution thoroughly and it works as expected. The only thing is that after the first run you see this:


This error was produced from the earliest version. I thought it was due to my fault. Once the script is running, the error is no longer traced. I am curious what it is coming from. It seems that at startup the fan’s preset_mode is not set. Does it have to be?

Download the trace file, that was recorded when that error happened, and post it here.

Instructions for how to download a trace can be found here:

Here you are:

{
  "trace": {
    "last_step": "action/0/default/0",
    "run_id": "10469dbb787907a75ec0cecb256ba31e",
    "state": "stopped",
    "script_execution": "error",
    "timestamp": {
      "start": "2024-05-06T01:33:27.101822+00:00",
      "finish": "2024-05-06T01:33:27.114096+00:00"
    },
    "domain": "automation",
    "item_id": "1714922827678",
    "error": "Preset mode  is not valid, valid preset modes are: Auto, Silent, Favorite",
    "trigger": null,
    "trace": {
      "trigger": [
        {
          "path": "trigger",
          "timestamp": "2024-05-06T01:33:27.102128+00:00",
          "changed_variables": {
            "this": {
              "entity_id": "automation.consolidated_air_purifier_automation",
              "state": "on",
              "attributes": {
                "id": "1714922827678",
                "last_triggered": "2024-05-05T22:00:00.011515+00:00",
                "mode": "restart",
                "current": 0,
                "friendly_name": "Consolidated Air purifier automation"
              },
              "last_changed": "2024-05-05T15:30:11.939064+00:00",
              "last_reported": "2024-05-05T22:00:00.460886+00:00",
              "last_updated": "2024-05-05T22:00:00.460886+00:00",
              "context": {
                "id": "01HX5CAQRBMC5BFMBPKR9G990H",
                "parent_id": "01HX5CAQR0E8CA06J699B9GCA7",
                "user_id": null
              }
            },
            "trigger": {
              "platform": null
            }
          }
        }
      ],
      "action/0": [
        {
          "path": "action/0",
          "timestamp": "2024-05-06T01:33:27.103365+00:00",
          "changed_variables": {
            "context": {
              "id": "01HX5RHJNXA4SYTJB4WDCV84HP",
              "parent_id": "01HX5RHJNW4RTFQ7RSP6AV3BMG",
              "user_id": null
            }
          },
          "error": "Preset mode  is not valid, valid preset modes are: Auto, Silent, Favorite",
          "result": {
            "choice": "default"
          }
        }
      ],
      "action/0/choose/0": [
        {
          "path": "action/0/choose/0",
          "timestamp": "2024-05-06T01:33:27.103658+00:00",
          "result": {
            "result": false
          }
        }
      ],
      "action/0/choose/0/conditions/0": [
        {
          "path": "action/0/choose/0/conditions/0",
          "timestamp": "2024-05-06T01:33:27.103798+00:00",
          "result": {
            "result": false,
            "entities": []
          }
        }
      ],
      "action/0/choose/1": [
        {
          "path": "action/0/choose/1",
          "timestamp": "2024-05-06T01:33:27.104437+00:00",
          "result": {
            "result": false
          }
        }
      ],
      "action/0/choose/1/conditions/0": [
        {
          "path": "action/0/choose/1/conditions/0",
          "timestamp": "2024-05-06T01:33:27.104568+00:00",
          "result": {
            "result": false,
            "entities": []
          }
        }
      ],
      "action/0/default/0": [
        {
          "path": "action/0/default/0",
          "timestamp": "2024-05-06T01:33:27.105482+00:00",
          "error": "Preset mode  is not valid, valid preset modes are: Auto, Silent, Favorite",
          "result": {
            "params": {
              "domain": "fan",
              "service": "set_preset_mode",
              "service_data": {
                "preset_mode": "",
                "entity_id": [
                  "fan.air_purifier"
                ]
              },
              "target": {
                "entity_id": [
                  "fan.air_purifier"
                ]
              }
            },
            "running_script": false
          }
        }
      ]
    },
    "config": {
      "id": "1714922827678",
      "alias": "Consolidated Air purifier automation",
      "description": "",
      "trigger": [
        {
          "id": "schedule",
          "platform": "state",
          "entity_id": [
            "schedule.nighttime"
          ]
        },
        {
          "id": "Auto",
          "platform": "numeric_state",
          "entity_id": [
            "sensor.air_purifier_pm2_5"
          ],
          "above": 85,
          "below": 2000
        },
        {
          "id": "Silent",
          "platform": "numeric_state",
          "entity_id": [
            "sensor.air_purifier_pm2_5"
          ],
          "above": 35,
          "below": 84.9
        },
        {
          "id": "off",
          "platform": "numeric_state",
          "entity_id": [
            "sensor.air_purifier_pm2_5"
          ],
          "below": 34.9,
          "for": {
            "minutes": 5
          }
        },
        {
          "id": "off",
          "platform": "state",
          "entity_id": [
            "binary_sensor.ikea_window_sensor_opening"
          ],
          "from": "off",
          "to": "on"
        },
        {
          "id": "on",
          "platform": "state",
          "entity_id": [
            "binary_sensor.ikea_window_sensor_opening"
          ],
          "from": "on",
          "to": "off",
          "for": {
            "seconds": 10
          }
        }
      ],
      "condition": [],
      "action": [
        {
          "choose": [
            {
              "conditions": [
                {
                  "condition": "template",
                  "value_template": "{{ trigger.id == 'schedule' }}"
                }
              ],
              "sequence": [
                {
                  "service": "switch.turn_{{ iif(states('schedule.nighttime') == 'on', 'off', 'on') }}",
                  "target": {
                    "entity_id": [
                      "switch.air_purifier_led",
                      "switch.air_purifier_buzzer"
                    ]
                  }
                }
              ]
            },
            {
              "conditions": [
                {
                  "condition": "template",
                  "value_template": "{{ trigger.id in ['off', 'on'] }}"
                }
              ],
              "sequence": [
                {
                  "condition": "template",
                  "value_template": "{{ trigger.id == 'off' or\n  (trigger.id == 'on' and states('sensor.air_purifier_pm2_5') | float(0) > 1) }}\n"
                },
                {
                  "service": "fan.turn_{{ trigger.id }}",
                  "target": {
                    "entity_id": "fan.air_purifier"
                  }
                }
              ]
            }
          ],
          "default": [
            {
              "service": "fan.set_preset_mode",
              "data": {
                "preset_mode": "{{ trigger.id }}"
              },
              "target": {
                "entity_id": "fan.air_purifier"
              }
            }
          ]
        }
      ],
      "mode": "restart"
    },
    "blueprint_inputs": null,
    "context": {
      "id": "01HX5RHJNXA4SYTJB4WDCV84HP",
      "parent_id": "01HX5RHJNW4RTFQ7RSP6AV3BMG",
      "user_id": null
    }
  },
  "logbookEntries": [
    {
      "name": "Consolidated Air purifier automation",
      "message": "triggered",
      "source": null,
      "entity_id": "automation.consolidated_air_purifier_automation",
      "context_id": "01HX5RHJNXA4SYTJB4WDCV84HP",
      "when": 1714959207.1023653,
      "domain": "automation"
    }
  ]
}

One thing has slipped away. Because the window opening and the PM2.5 level have the same trigger ID, when the PM2.5 level rises above 34.9 the automation starts the purifier even though the window is still open. Am I assuming correctly that establishing a unique ID for the open window condition will change the game?

In your trace diagram, none of the automation’s six Triggers was triggered.
image

This is confirmed by the trace file which shows that the automation was not triggered by any of its triggers (it’s null).

            "trigger": {
              "platform": null
            }

The evidence suggests that the automation was run manually using its Run command. Because there’s no evidence it was triggered by any of its triggers.

A quick fix is to add a State Condition confirming the window is closed before attempting to set preset_mode.

    default:
      - condition: state
        entity_id: binary_sensor.ikea_window_sensor_opening
        state: 'off'
      - service: fan.set_preset_mode
        data:
          preset_mode: "{{ trigger.id }}"
        target:
          entity_id: fan.air_purifier
1 Like

Your quick fix did the job. Thanks.

1 Like