How to configure a 3 state switch as a single switch in ESPHome?

I have a “3 state switch” in my home and would like to use with ESPHome, it’s something like the one in the picture below:

Currently I got it set up as 3 individual ON/OFF switches with the following config:

binary_sensor:
  - platform: gpio
    name: "Switch state 1"
    pin:
      number: 2
      inverted: True
      mode: INPUT_PULLUP
  - platform: gpio
    name: "Switch state 2"
    pin:
      number: 4
      inverted: True
      mode: INPUT_PULLUP
  - platform: gpio
    name: "Switch state 3"
    pin:
      number: 5
      inverted: True
      mode: INPUT_PULLUP

I would like to know how I can configure it so it shows up as a single switch in ESPHome and HA that can be in one of 3 states.

You can’t. The switch domain only has two states, on and off.

You could use an input select.

Alright, thanks. Is there some documentation available about input select (or some sample code maybe)?

  1. Create an input select with three options in home assistant

  2. Use the on_press trigger in each of your three binary sensors to set the input select using home assistant services in esphome. The service you want is input_select.select_option

EDIT: actually I just realised you have no way of controlling the 3 way switch with home assistant (it’s a “dumb” switch). So instead of using an input select (which you could have used to control the switch, if it was smart), use a template sensor in esphome to show the state.

2 Likes

Thanks! That got me in the right direction. I have a lot to learn about HA and ESPHome and all the terminology involved.

This is what I ended up with:

binary_sensor:
  - platform: gpio
    id: mv1
    pin:
      number: 2
      inverted: True
      mode: INPUT_PULLUP
    on_press:
      then:
        - sensor.template.publish:
            id: template_mv
            state: 1
  - platform: gpio
    id: mv2
    pin:
      number: 4
      inverted: True
      mode: INPUT_PULLUP
    on_press:
      then:
        - sensor.template.publish:
            id: template_mv
            state: 2
  - platform: gpio
    id: mv3
    pin:
      number: 5
      inverted: True
      mode: INPUT_PULLUP
    on_press:
      then:
        - sensor.template.publish:
            id: template_mv
            state: 3

sensor:
  - platform: template
    name: "Dumb switch state"
    id: template_mv
1 Like

:laughing: Nice.

That’s not a simple task. Especially for a first effort. Well done.

Thanks :smile:, yes as a beginner I found it pretty confusing finding the parts I required in the documentation and where to put certain code samples. Hopefully this can be improved in the future so other beginners aren’t discouraged :slightly_smiling_face:.

I added a filter with a delayed_on: 250ms so when quickly moving the switch from 1 to 3 ESPHome will not set the sensor to 2. And lastly, to retain states across boots I added some on_boot logic. Final result for now:

esphome:
  on_boot:
    - priority: -10
      then:
        - if:
            condition:
              binary_sensor.is_on: mv1
            then:
              - sensor.template.publish:
                  id: template_mv
                  state: 1
        - if:
            condition:
              binary_sensor.is_on: mv2
            then:
              - sensor.template.publish:
                  id: template_mv
                  state: 2
        - if:
            condition:
              binary_sensor.is_on: mv3
            then:
              - sensor.template.publish:
                  id: template_mv
                  state: 3

binary_sensor:
  - platform: gpio
    id: mv1
    pin:
      number: 2
      inverted: True
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 250ms
    on_press:
      then:
        - sensor.template.publish:
            id: template_mv
            state: 1
  - platform: gpio
    id: mv2
    pin:
      number: 4
      inverted: True
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 250ms
    on_press:
      then:
        - sensor.template.publish:
            id: template_mv
            state: 2
  - platform: gpio
    id: mv3
    pin:
      number: 5
      inverted: True
      mode: INPUT_PULLUP
    filters:
      - delayed_on: 250ms
    on_press:
      then:
        - sensor.template.publish:
            id: template_mv
            state: 3

sensor:
  - platform: template
    name: "Dumb switch state"
    id: template_mv

(not sure where I actually needed to use dashes but this seems to work)

1 Like

They’re only required where you have a list of more than one thing or action to do. It does not hurt to include them if you only have one item. In fact it helps if you come back and edit in more later.

1 Like

Hi @jant90 i would like to integrate a similar button in hass. Might i ask what hardware you used and how you wired it up?

Thanks!

I used a cheap ESP32 devboard (I have boards from various brands, including unbranded ones), obviously flashed it with ESPHome using the YAML from my earlier posts. I used an ESP32 because I also use it to read BLE sensors, otherwise I would use an ESP8266 because it has more stable Wi-Fi stack (for me at least, the ESP32 needs to reconnect every 200 minutes, it will then resend the sensor state MQTT message).

Anyways, I connected the 4 wires from the wall switch to the ESP’s GPIO pins that I configured in the YAML file. There is one wire for each state of the switch and a fourth wire that connects to ground. By using INPUT_PULLUP mode no resistors are required, you can directly connect the wires to the GPIO pins.

This way the switch should show up as a sensor in Home Assistant with state 1, 2, or 3, depending on the state of the actual switch.

Hi, I know this is a while ago, but I was attempting to implement a similar solution, and looking at yours, and also the documentation, I’ve tried all manner of things but it just wants bools…

Expected boolean value, but cannot convert to a boolean. Please use ‘true’ or ‘false’.

  - platform: gpio
    pin:
      number: 34
    id: A2_switch_open
    clickable: false
    name: "Gate A2 Open Detect"
    filters:
      - delayed_on: 10ms
    on_press:
      then:
        - switch.template.publish:
            id: gate_a2_state
            state: 0
    on_release:
      then:
        - switch.template.publish:
            id: gate_a2_state
            state: 1

After seeing this in the docs:

state (Optional, dict): Widgets or their (sub)parts can have have states, which support separate styling. These state styles inherit from the theme, but can be locally set or overridden within style definitions. Can be one of:
.....
user_1, user_2, user_3, user_4 (Optional, boolean): Custom states.

- button:
    checkable: true
    state:
      checked: true # here you activate the state to be used at boot
    checked:
      bg_color: 0x00FF00 # here you apply styles to be used when in the respective state

I also tried things like this…

    on_press:
      then:
        - switch.template.publish:
            id: gate_a1_state
            state: 
              closed: true
    on_release:
      then:
        - switch.template.publish:
            id: gate_a1_state
            state: 
              closed: false

but no dice.

edit: I suspect I’m just… tired.

I have 3 relays for selecting open mid and closed on a door
I have two switch/sensors for detecting if gate is fully open or fully closed
I was trying to have a requested_state and a known_state type thing
but I’m not getting states right.

ghkjflgkjhflgjh

Well… I think I’ve made it happen, but in a really weird way. I need to re-examine it at a later date and come back.