Light and Led driven by push button and motion sensor: What is the best way to automate?

I have the following configuration for several lights:

  • A Light (or group of lights)
  • A push button - typically connected to a ESPxx that sends a MQTT message like button/x/y with payload 1 for normal push. (2 for double press and L for long press)
  • A motion sensor - typically connected to a ESPxx that sends a MQTT message like motion/x/y with payload 1. A bit later payload 0 is send.
  • An indicator led - typically connected to a ESPxx. HA send a MQTT message like led/x/y with payload 0-9 to drive the led.

Each of the components can be available as 1 or multiple units. For example 2 push buttons to drive the same light. Next to the buttons you might have an indicator led.
The indicator led will burn constantly when the light has been turned on by a button. It will flash when it has been turned on by motion.
When turned on by motion, it will automatically switch of after x time.

To implement this I have made the following automations:

  • xxx button_x_y_1
  • xxx on by motion
  • xxx activation state change
  • xxx off after motion

Next to that I have an input_text helper that is named xxx_activation_state. It can contain ‘OFF’, ‘BUTTON’ or ‘MOTION’ indicating how the state was changed.
xxx button_x_y_1 is the automation that is triggered when a push button is pushed. It only sets the input_text xxx_activation_state to ‘BUTTON’ or ‘OFF’.
xxx on by motion is the automation that is triggered when motion is detected. It only sets the input_text xxx_activation_state to ‘MOTION’ when its current value is not ‘BUTTON’.
xxx activation state change is triggered whenever the input_text is changed. This automation will switch the light and the leds according to the value of the input_text.
xxx off after motion is triggered when the input_text is set to ‘MOTION’ for 3 minutes. (So I don’t need a timer).
In order to be able to re-trigger when new motion is detected, xxx on by motion will first set the input_text to ‘UNKNOWN’ and then set it ‘MOTION’ by doing so, the internal time (with the ‘for 3 minutes’) works as expected.

With this approach I’m able to have multiple ‘xxx button_x_y_1’ or ‘xxx motion_x_y_1’ automations.

Now, the above set of automations seems to work, but I am wondering if there is a better, shorter way of doing this?

There are multiple ways to implement this, I think your first choice is how you want to store state, I think there are 3 good options:

  1. Use a 3-State - the solution you use now.
  2. Use a 4-State - the same as the 3-state except you add a “both” option to indicate both the sensor and the button are requesting the light on.
  3. Use two boolean helpers / on-off switches to separately track the button and sensor demands.

I prefer option #3 for the following reasons:

  • Adding additional sensors or buttons is easy.
    • All sensors just switch the sensor switch on.
    • If I want a toggle button, I add an action to toggle the button switch.
    • If I want separate on and off buttons I add an action to set the button switch to that position.
  • All “input wiring” is simple, sensors don’t care about buttons and buttons don’t care about sensors.
  • I have the complete state - I may not need the “both on” state now, but I might in the future, using this option means I have that option.
  • The most common use case is an inclusive or - if the button is on and/or the sensor is on turn on a light - if both are off turn off the light.

Note: These choices are not mutually exclusive you could have a 3-state and 2 input-booleans. However if you do this I would recommend chaining them, meaning that:

  • The buttons and sensors only drive the input booleans.
  • You have events/automations on changes of the input booleans that update your 3 state.

This approach preserves the simplicity for adding new buttons and sensors as they still only have to update the input booleans. Additionally you can test that the 3-state updates correctly by manually flipping the booleans.

Finally I will note that a lot of HA functionality is duplicated across domains, specifically there are versions of on/off switches and 3-states in:

  • (Input) Helpers.
  • Template (Switches)
  • MQTT

I try to use MQTT switches when I can - to avoid the need for extra objects, but sometimes I am forced to use helpers and/or template switches in order to take advantage of specific functionality/quirks of a particular domain.

David, thank you for your reply.
Your approach is mainly in line with mine.
I currently don’t see a practical need for the 4-state solution. Although it is similar to the 3-state solution. As soon as the 4th state is needed, it can be easily added.
My previous solution had 2 booleans. But I had a feeling that the 3-state approach was more convenient. It probably a matter of taste!
having said this, I see that you propose greatly the same solution as the one I described.
I was hoping that someone would come up with a HA feature I am not aware of to implement the same functionality but in a more simple way or with less than 4 automations.
As an example: In the past I used a time to switch off the light when it was switch on by motion. Recently, I learned that there is the ‘for x time’ feature that could replace the timer.

I have come to a few “realizations” about how HA is structured.

Specifically most devices/entities have some combination of:

  • Triggers
  • Conditions
  • Actions

Actions are just a placeholder meaning that you can relocate a sequence of actions into a script then just have an action to call the script. Hence you can reuse more complex logic.

Conditions are not “Special” they can be replaced with an if/then condition as your first action, so again they can be relocated to scripts.

Triggers generate an event and it is possible to query the event in an if condition to find out what happened and which device triggered it. You can’t eliminate the need for specifying triggers, but you can add a bunch of different triggers to a single automation and then sort out what actually happened inside a script.


As a practical example I have a bunch of (Moes) scene switches. I have created a script that handles the different options for a single button:

  • Single click - toggle light on/off
  • Double click - evening mode - turn on, change light to yellow temperature and reduce brightness.
  • Long press - day mode - turn on, 100 brightness, full white.

Now say I have two groups:

  • Group A has 2 switches and 2 lights.
  • Group B has 3 switches and 4 lights

I only need:

  • 1 script.
  • 1 Automation for Group A
  • 1 Automation for Group B.

Both automations contain a list of all the lights and a list of trigger conditions (I actually need to list the triggers 3 times (once for each click pattern for each switch) - but thats an issue with the integration not the concept.

So any click pattern, on any switch in group B, will affect all lights in group B.


Tip:
Template switches have built in trigger/actions (there is no condition) so using them avoids the need for an automation - you can directly call scripts without needing separate automations.

Summary
If your concern is simply total number of automations, you can restructure how you build your automations to minimize them.

Alternatively you can accept a larger number of automations, but choose to make them all dirty simple and move all the complex logic into scripts.