Help with advanced switch

I have an application that requires a double pulse of the relay to turn on, and a push and hold of the relay for a power off for around 3 seconds.

I have this setup and working, but this provides 2 switch entities, one for on and one for off. How can I combine this into 1 switch?

Also, is there a way I can get the switch to confirm the state with an input?

Basically, I want to control a diesel heater. I have wired onto the back of the controller. To power on, it requires a single 1 second push of the power button, sometime if it goes to sleep, it needs 2, one to wake it up. To power it down, it requires a push and hold for roughly 3 seconds.

I have wired a relay to a 12v source that activates when the heater is ON. This is my input that will

  1. let me know when the heater is on and running
  2. confirm the state of the switch so it does not go out of sync.

Would appreciate any help with this. Here is my current config.

switch:
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    name: BusHeaterOff
    turn_on_action:
    - switch.turn_on: busheaterOff
    - delay: 3s
    - switch.turn_off: busheaterOff
    - delay: 1s 
    - switch.turn_off: pulse_relay_1
  - platform: gpio
    pin:
      number: 5
      inverted: True
      allow_other_uses: true
    id: busheaterOff
    internal: true
    
    
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1_1
    name: BusHeaterOn
    turn_on_action:
    - switch.turn_on: busheaterOn
    - delay: 1s
    - switch.turn_off: busheaterOn
    - delay: 1s 
    - switch.turn_on: busheaterOn
    - delay: 1s
    - switch.turn_off: busheaterOn
    - delay: 1s 
    - switch.turn_off: pulse_relay_1_1
  - platform: gpio 
    pin:
      number: 5
      inverted: True
      allow_other_uses: true
    id: busheaterOn
    internal: true

  - platform: template
    id: heaterpower
    name: HeaterPower
    turn_on_action:
      - switch.turn_on: pulse_relay_1_1
    turn_off_action:
      - switch.turn_off: pulse_relay_1

Tried this too, but once a switch action is triggered, the relay just continues to pulse on and off once every second non stop.

switch:
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    name: BusHeaterOff
    turn_on_action:
    - switch.turn_on: busheaterOff
    - delay: 3s
    - switch.turn_off: busheaterOff
    - delay: 1s 
    - switch.turn_off: pulse_relay_1
    turn_off_action: 
      then:
      - switch.turn_on: busheaterOff
      - delay: 1s
      - switch.turn_off: busheaterOff
      - delay: 1s 
      - switch.turn_on: busheaterOff
      - delay: 1s
      - switch.turn_off: busheaterOff
      - delay: 1s 
      - switch.turn_off: pulse_relay_1
  - platform: gpio
    pin:
      number: 5
      inverted: True
    id: busheaterOff
    internal: true

You’re turning the pulse_relay_1 template switch off again, maybe try to drop that action?

switch:
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    name: BusHeaterOff
    turn_on_action:
    - switch.turn_on: busheaterOff
    - delay: 3s
    - switch.turn_off: busheaterOff
    turn_off_action: 
      then:
      - switch.turn_on: busheaterOff
      - delay: 1s
      - switch.turn_off: busheaterOff
      - delay: 1s 
      - switch.turn_on: busheaterOff
      - delay: 1s
      - switch.turn_off: busheaterOff

  - platform: gpio
    pin:
      number: 5
      inverted: True
    id: busheaterOff
    internal: true

Thanks, that does seem to work actually.

However, if I open the switch, turn it on then close the window for the switch, when I go back into the switch is in the off state, when I left it on, I did not turn it off?

You should probably either set optimistic: true in the switch config or publish the state of the switch in the turn_on and turn_off actions.

Boom, thats it thanks!

Is there a way for the switch to confirm the state based on an input?

Would that be a publish action for an input? to publish the state of the switch?

I guess you could put in some conditions and only publish the switch state if those conditions are met. I would change the input to a binary_sensor and use its state as a condition. So only do the on_turn_on actions if the binary_sensor is off, and subsequently, after a delay (I chose 1s, but adjust that if you’re heater is slower at turning on/off), check again if we should actually publish the switch state.

Something like this:

binary_sensor:
  - platform: gpio 
    pin:
      number: 5
      inverted: True
      allow_other_uses: true
    id: busheaterOn
    internal: true
  
switch:  
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    name: BusHeaterOff   
    turn_on_action:
      - if:
          condition:
            binary_sensor.is_off: busheaterOn
          then:   
            - switch.turn_on: busheaterOff
            - delay: 3s
            - switch.turn_off: busheaterOff
            - delay: 1s
            - if:
                condition:
                  binary_sensor.is_on: busheaterOn
                then:
                  - switch.template.publish:
                      id: pulse_relay_1
                      state: ON
              
    turn_off_action: 
      - if:
          condition:
            binary_sensor.is_on: busheaterOn
          then:   
            - switch.turn_on: busheaterOff
            - delay: 1s
            - switch.turn_off: busheaterOff
            - delay: 1s 
            - switch.turn_on: busheaterOff
            - delay: 1s
            - switch.turn_off: busheaterOff
            - delay: 1s
            - if:
                condition:
                  binary_sensor.is_off: busheaterOn
                then:
                  - switch.template.publish:
                      id: pulse_relay_1
                      state: OFF

Ah ok thanks,

But I am getting this error.

Unable to find action with the name 'template.switch.publish'.

Heres my full YAML but its not liking the template.switch.publish still.

binary_sensor:
  - platform: gpio
    id: powerstatus
    pin:
      number: 14
      mode: INPUT_PULLUP
      inverted: True
    name: "Power Status"
#    device_class: smoke
    filters:
  
switch:  
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    name: BusHeaterOff   
    turn_on_action:
      - if:
          condition:
            binary_sensor.is_off: powerstatus
          then:   
            - switch.turn_on: heaterpower
            - delay: 3s
            - switch.turn_off: heaterpower
            - delay: 1s
            - if:
                condition:
                  binary_sensor.is_on: powerstatus
                then:
                  - template.switch.publish:
                      id: pulse_relay_1
                      state: ON           
    turn_off_action: 
      - if:
          condition:
            binary_sensor.is_on: powerstatus
          then:   
            - switch.turn_on: heaterpower
            - delay: 1s
            - switch.turn_off: heaterpower
            - delay: 1s 
            - switch.turn_on: heaterpower
            - delay: 1s
            - switch.turn_off: heaterpower
            - delay: 1s
            - if:
                condition:
                  binary_sensor.is_off: powerstatus
                then:
                  - template.switch.publish:
                      id: pulse_relay_1
                      state: OFF


  - platform: gpio
    pin:
      number: 5
      inverted: True
    id: heaterpower
    internal: true

It’s switch.template.publish.

Sorry, swapped it around in my head.

Thanks, that is working.

However, if I understand this config correctly, when I turn the binary_sensor on, it should also set the switches state to on?

Also, I noticed you used internal for the binary_sensor,
this is a physical sensor that is actually switching on when the heater is on,
This way, if I switch the heater on from any other source than homeassistant, it will know what state to put the switch in,

It does not do this.

Thanks again

I did that because you had the switch set to internal. It only has the effect of not creating the binary_sensor in HA, but will still work internally.

Anyway, you could just have the binary_sensor publishing the switch state instead.

I would also move the turn on/off actions to a script.

binary_sensor:
  - platform: gpio
    id: powerstatus
    pin:
      number: 14
      mode: INPUT_PULLUP
      inverted: True
    name: "Power Status"
    on_press:
      then:
        - switch.template.publish:
            id: pulse_relay_1
            state: ON
    on_release:
      then:
        - switch.template.publish:
            id: pulse_relay_1
            state: OFF
        
switch:  
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    name: BusHeaterOff
    turn_on_action:
      - script.execute: turn_heater_on
    turn_off_action: 
      - script.execute: turn_heater_off
 
  - platform: gpio
    pin:
      number: 5
      inverted: True
    id: heaterpower
    internal: true

script:
  - id: turn_heater_on
    mode: single
    then:
      - switch.turn_on: heaterpower
      - delay: 3s
      - switch.turn_off: heaterpower
  - id: turn_heater_off
    mode: single
    then:
      - switch.turn_on: heaterpower
      - delay: 1s
      - switch.turn_off: heaterpower
      - delay: 1s 
      - switch.turn_on: heaterpower
      - delay: 1s
      - switch.turn_off: heaterpower

Btw. If you don’t give a component a name, but only an id, you don’t have to set internal: true.

Weird, nothing shows as a error in the yaml editor in esphome but when I try compile,

ERROR Error while reading config: Invalid YAML syntax:

mapping values are not allowed here
  in "/config/esphome/heater-control.yaml", line 57, column 34

All indentation and formatting looks correct to me.

ah got it, keeping on my toes eh :rofl:

Missing a : after then

    on_release:
      then

Heh, yeah or just me not testing the code :wink:

You’re a bloody legend aye, that is perfect!

I’m going to throw one more spanner in the works. When the heater powers off, its take about 10 minutes to actually switch the binary_sensor off due to a cool down period.

I guess now that the switch state is published based on the binary_sensor, it may not matter as much.

I’m glad it works for you. :grinning:

Regarding the cool down period: I can think of a few ways to work around that, but none that would work, if you turn off the heater manually - unless you add a sensor to the actual physical switch on the heater, otherwise it would have no idea when the heater is turned off manually.

Yea, I already struggled to find a 12v source that I could use to trigger a relay, and the source I found turns on instantly, but only turns off when the cool down period ends.

I think its ok now as the binary_sensor is publishing the switch state,

Just means that after you power down, it will remain in an on state, both switch and binary sensor until the cool down period has finished.

This is good enough.

Thanks so much for the help!

Only happy to help, but good enough is halfway bad :wink:

Anyway, you could set optimistic: true on the switch and have it reflect the change immediately. You would then use the binary_sensor to indicate the actual current state of the heater. This way you don’t have to wait 10 minutes, if you turn the heater off by mistake with the switch. You would still have to wait 10 minutes, for the switch to reflect the change, if you turn the heater off manually though.

switch:  
  - platform: template
    restore_mode: DISABLED
    id: pulse_relay_1
    optimistic: true
    ...

This is working well, however today I noticed it went out of sync,

What happened was the esp was offline, the heater was on and when the esp came back online, the switch was reporting as off and the binary sensor was reporting as on, as it should be.

Is there a way on on_boot to check the state of the binary sensor and set the switch accordingly?

Thanks