ESPHome on_turn_on not triggered if switch is already on

Hello. I have been converting my devices to ESPHome from Tasmota. However, for the life of me I could not replicate Tasmota’s pulsetime functionality, mainly because:

If the switch receives a turn_on request while it is already on then the on_turn_on action is not triggered. It is only triggered if switching from off to on.

Consider this snippet to replicate pulsetime:

switch:
  - platform: gpio
    name: "Relay1"
    pin: GPIO12
    id: relay_1
    icon: ${device_icon}
    on_turn_on:
      - script.execute: pulsetime
    on_turn_off:
      - script.stop: pulsetime

script:
  - id: pulsetime
    mode: restart
    then:
      - delay: 10min
      - switch.turn_off: relay_1

Once turned on, the switch turns off after 10min – fine.
However, what if a PIR action sends a turn_on request to the device whilst it is already on?

In Tasmota the remaining pulsetime is reset.
In the definition above, the script could reset itself and restart counting

BUT

The on_turn_on action is never triggered!

See what happens when I manually switch off then on the device

08:39:10	[D]	[switch:012] 'Relay1' Turning ON.
08:36:39	[D]	[script:077] Script 'pulsetime' restarting (mode: restart)

But if the device is already on and I send a turn_on request, I only get:

08:41:11	[D]	[switch:012] 'Relay1' Turning ON.

No on_turn_on (and therefore script) is executed!

Can anybody help with this?

Answer is to use template switch, which have turn_on_action & turn_off_action.

on_turn_on is designed to trigger on state change, unfortunately or not.

Thank you very much for the quick response!

Yes, it works. The solution is a bit convoluted. If someone can simplify it, that would be perfect.

Based on your suggestion, this is what I did:

switch:
  - platform: template
    name: "Relay1"
    id: relay_1
    lambda: |-
      if (id(int_relay_1).state) {
        return true;
      } else {
        return false;
      }
    turn_on_action:
      - switch.turn_on: int_relay_1
      - script.execute: pulsetime
    turn_off_action:
      - switch.turn_off: int_relay_1  
      - script.stop: pulsetime

  - platform: gpio
    name: "Internal Relay1"
    pin: GPIO12
    id: int_relay_1
    internal: true

script:
  - id: pulsetime
    mode: restart
    then:
      - delay: 10min
      - switch.turn_off: relay_1

Basically, the template switch is now a “shadow switch” for the real internal switch.

And now when the switch is turned on, this is what happens:

11:25:23	[D]	[sensor:093] 'Uptime': Sending state 47.52600 s with 0 decimals of accuracy
11:25:24	[D]	[switch:012] 'Relay1' Turning ON.
11:25:24	[D]	[switch:012] 'Internal Relay1' Turning ON.
11:25:24	[D]	[switch:055] 'Internal Relay1': Sending state ON
11:25:24	[D]	[switch:055] 'Relay1': Sending state ON

And when the switch is turned on and it is already on, this is what happens:

11:29:55	[D]	[switch:012] 'Relay1' Turning ON.
11:29:55	[D]	[switch:012] 'Internal Relay1' Turning ON.
11:29:55	[D]	[script:077] Script 'pulsetime' restarting (mode: restart)

Just as desired.

It is a little convoluted and you could improve a lot. First off, Switch is the wrong platform to use if your attempting to make an “internal relay”. You need to be using a binary sensor which is much more appropriate for this situation. Even when you are using a physical button/switch you’ll use binary_sensor most of the time, not Switch.

This simply gives reads the state of a gpio and when turned ON or Pressed it sends a command to execute your script which will then restart because you set

 mode: restart
binary_sensor:
  - platform: gpio
    pin: gpio12
    name: "Relay1"
    id: relay_1
    on_press:
      - script.execute: pulsetime

script:
  - id: pulsetime
    mode: restart
    then:
      - delay: 10min
      - switch.turn_off: relay_1

If you elaborate on what the 10min delay is for, im sure we could stream line it even more.

I will give this a try and report back.

Why the 10min?

When only one PIR controls a switch, and I want the switch to turn off after 10 of the PIR clearing, I could simply put that in HA automation (turn switch off 10 mins after PIR goes to on). If the PIR detects motion again within the 10 min, the automation takes care of this and resets the timer.

However, I have a switch that is controller by two PIRs. Programming this in an automation would be difficult. Instead, any of the PIRs can turn on the switch, and the switch turns itself off after 10 min of no re-activation . Get it?

I read your suggestion again. Unfortunately, it won’s work. There is no “press” action in this case – the relay is activated by an external action (PIR sensor), and a turn_on by that action does not activate on_press.

My solution works.

It would be easier, though, if ESPHome implemented a PulseTime function like Tasmota.

A PIR “sensor” is not a switch. Its a binary_sensor like I said above and it most certainly has a "press: action and many more.

I explained this last time.

Right here, it clearly shows “press” and many many more.

Dont get hung up on definitions like, button, switch, binary_sensor, PIR sensor, etc. They all have different names and different purposes but, to an esp board they are all identical and the esp cant tell a button and a PIR sensor apart, they look identical to the esp. All of them are “binary” they only have 2 states On/Off or High/Low and most things will require you set them up as a binary_sensor.