I’m posting this howto is kind of a breadcrumb for folks looking to learn and solve their own issues.
Scenario: you have two switches, but you want three. Luckily there’s a way to game it out of the system. Basically you can treat both switches updating at the same time as a 3rd switch.
What you do is:
- when either switch updates set a boolean to true,
- use a nonblocking delay to give the other switch a chance to set it’s boolean
- if the other switches boolean isn’t set to true, execute the single switch action
- if both are true execute a double switch action
- each switch then sets it’s boolean to false
In the example below, one switch cycles a template number that sets a scene for the bedroom. The other switch turns a fan on or off. Both together cycles the bedroom input number, then applies it to the kitchen, livingroom, and hallway. Basically any switch I can’t get to at night without potentially stubbing my toe in a darkened room. I’m still learning esphome so don’t be afraid to suggest improvements.
Relevant example code
- id: too_hot_boolean
type: bool
restore_value: false
initial_value: 'false'
- id: switch_1_change
type: bool
restore_value: false
initial_value: 'false'
- id: switch_2_change
type: bool
restore_value: false
initial_value: 'false'
- id: bedroom_scene
type: int
restore_value: false
initial_value: '0'
binary_sensor:
- platform: gpio
pin:
number: GPIO13
name: "${switch_1_friendly_name} Switch Now"
on_state:
then:
- lambda: id(switch_1_change) = true;
- delay: 250ms
## only turn on fan if not controlling the rest of the house
- if:
condition:
- lambda: return !id(switch_2_change);
then:
- homeassistant.service:
service: switch.toggle
data_template:
entity_id: switch.fan_outlet_switch
else:
- delay: 500ms
- lambda: id(switch_1_change) = false;
- platform: gpio
pin:
number: GPIO5
name: "${switch_2_friendly_name} Switch Now"
on_state:
then:
- lambda: id(switch_2_change) = true;
- delay: 250ms
## get the current bedroom scene number so we can increment it
- http_request.get:
url: http://bedroom-switch.lan/number/switch_scene
on_response:
then:
- lambda: |-
json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
id(bedroom_scene) = root["state"];
//bedroom has 4 possible scenes includeing off, but most only have 3
//so we need to change it accourdingly
if(++id(bedroom_scene) > ((id(switch_1_change) && id(switch_2_change))?2:3)) {
id(bedroom_scene) = 0;
}
});
- http_request.post: !lambda |-
return "http://bedroom-switch.lan/number/bedroom_switch_scene/set?value=" + std::to_string(id(bedroom_scene));
- if:
## if both switches were hit, apply it to the rest of the house
## the kitchen switch is by the front door so sets all the switches to the bedroom.
condition:
- lambda: return (id(switch_1_change) && id(switch_2_change));
then:
- http_request.post: !lambda |-
return "http://kitchen-switch.lan/number/scene/set?value=" + std::to_string(id(bedroom_scene));
- delay: 500ms
- lambda: id(switch_2_change) = false;