Skip to content

Instantly share code, notes, and snippets.

@adrianslabu
Last active January 21, 2026 00:43
Show Gist options
  • Select an option

  • Save adrianslabu/0a163a38edfc684fc3a2d6e42b6f9e7e to your computer and use it in GitHub Desktop.

Select an option

Save adrianslabu/0a163a38edfc684fc3a2d6e42b6f9e7e to your computer and use it in GitHub Desktop.
esphome:
name: smart-cafe
friendly_name: Smart Cafe
on_boot:
priority: -100
then:
- lambda: |-
if (id(cold_lever).state) {
id(lever_state).publish_state("Cold");
} else if (id(hot_lever).state) {
id(lever_state).publish_state("Hot");
} else if (id(off_lever).state) {
id(lever_state).publish_state("Off");
}
id(script_running).publish_state("False");
if (id(light_sensor).state > 0.014) {
id(device_state).publish_state(true);
} else {
id(device_state).publish_state(false);
}
esp32:
board: esp32-c3-devkitm-1
framework:
type: esp-idf
output:
- platform: gpio
pin: GPIO1
id: power_pin
button:
- platform: template
name: "Power"
id: power
on_press:
- if:
condition:
lambda: 'return id(device_state).state;'
then:
- lambda: |-
if (id(valve_mode).current_option() != "Off") { id(valve_mode).publish_state("Off"); }
- delay: 100ms
- output.turn_on: power_pin
- delay: 100ms
- output.turn_off: power_pin
else:
- output.turn_on: power_pin
- delay: 100ms
- output.turn_off: power_pin
- delay: 100ms
- lambda: |-
if (id(valve_mode).current_option() != "Off") { id(valve_mode).publish_state("Off"); }
- platform: template
id: blue_btn
name: "Blue Button"
on_press:
- lambda: |-
if (id(child_lock).state) {
} else {
std::string button = "blue";
if (id(script_running).state == "True") {
button = "off";
}
if (id(device_state).state) {
id(buttons_script).execute(button);
}
}
- platform: template
id: yellow_btn
name: "Yellow Button"
on_press:
- lambda: |-
if (id(child_lock).state) {
} else {
std::string button = "yellow";
if (id(script_running).state == "True") {
button = "off";
}
if (id(device_state).state) {
id(buttons_script).execute(button);
}
}
- platform: template
id: red_btn
name: "Red Button"
on_press:
- lambda: |-
if (id(child_lock).state) {
} else {
std::string button = "red";
if (id(script_running).state == "True") {
button = "off";
}
if (id(device_state).state) {
id(buttons_script).execute(button);
}
}
switch:
- platform: gpio
name: "Hot Valve"
id: hot_valve
pin: GPIO2
interlock: [ cold_valve ]
restore_mode: ALWAYS_OFF
internal: False
- platform: gpio
name: "Cold Valve"
id: cold_valve
pin: GPIO3
interlock: [ hot_valve ]
restore_mode: ALWAYS_OFF
internal: False
- platform: template
name: "Child Lock"
id: child_lock
optimistic: true
restore_mode: ALWAYS_OFF
select:
- platform: template
name: "Valve"
id: valve_mode
optimistic: true
options:
- "Off"
- "Cold"
- "Hot"
on_value:
- if:
condition:
lambda: 'return x == "Off";'
then:
- switch.turn_off: cold_valve
- switch.turn_off: hot_valve
- if:
condition:
lambda: 'return x == "Cold";'
then:
- switch.turn_off: hot_valve
- switch.turn_on: cold_valve
- if:
condition:
lambda: 'return x == "Hot";'
then:
- switch.turn_off: cold_valve
- switch.turn_on: hot_valve
number:
- platform: template
id: blue_time
name: "Blue Button Time"
min_value: 1
max_value: 60
step: 1
optimistic: true
restore_value: true
initial_value: 30
- platform: template
id: yellow_time
name: "Yellow Button Time"
min_value: 1
max_value: 60
step: 1
optimistic: true
restore_value: true
initial_value: 10
- platform: template
id: red_time
name: "Red Button Time"
min_value: 1
max_value: 60
step: 1
optimistic: true
restore_value: true
initial_value: 13
binary_sensor:
- platform: gpio
pin:
number: GPIO5
mode: INPUT_PULLDOWN
id: cold_lever
internal: true
on_state:
lambda: |-
if (id(cold_lever).state) {
id(lever_state).publish_state("Cold");
}
- platform: gpio
pin:
number: GPIO6
mode: INPUT_PULLDOWN
id: hot_lever
internal: true
on_state:
lambda: |-
if (id(hot_lever).state) {
id(lever_state).publish_state("Hot");
}
- platform: template
id: off_lever
internal: true
lambda: |-
return !id(cold_lever).state && !id(hot_lever).state;
on_state:
then:
- lambda: |-
if (id(off_lever).state) {
id(lever_state).publish_state("Off");
}
- platform: gpio
pin:
number: GPIO4
mode: INPUT_PULLDOWN
id: blue_button
internal: true
on_press:
- button.press: blue_btn
- platform: gpio
pin:
number: GPIO7
mode: INPUT_PULLDOWN
id: yellow_button
internal: true
on_press:
- button.press: yellow_btn
- platform: gpio
pin:
number: GPIO10
mode: INPUT_PULLDOWN
id: red_button
internal: true
on_press:
- button.press: red_btn
- platform: template
id: device_state
name: "State"
sensor:
- platform: adc
pin: GPIO0
id: light_sensor
name: "Light Sensor"
update_interval: 0.1s
internal: True
filters:
- exponential_moving_average:
alpha: 0.1
send_every: 1
on_value_range:
- above: 0.014
then:
- delay: 500ms
- if:
condition:
sensor.in_range:
id: light_sensor
above: 0.014
then:
- binary_sensor.template.publish:
id: device_state
state: ON
- below: 0.013
then:
- delay: 500ms
- if:
condition:
sensor.in_range:
id: light_sensor
below: 0.013
then:
- binary_sensor.template.publish:
id: device_state
state: OFF
text_sensor:
- platform: template
id: lever_state
name: "Lever State"
update_interval: never
- platform: template
id: script_running
name: "Script Running"
update_interval: never
- platform: template
id: active_button
name: "Active Button"
update_interval: never
script:
- id: buttons_script
mode: restart
parameters:
button: string
then:
- lambda: |-
if (id(script_running).state == "True") {
id(valve_mode).publish_state("Off");
id(script_running).publish_state("False");
return;
}
if (id(lever_state).state == "Cold") {
id(valve_mode).publish_state("Cold");
} else if (id(lever_state).state == "Hot") {
id(valve_mode).publish_state("Hot");
} else {
id(script_running).publish_state("False");
return;
}
id(script_running).publish_state("True");
if (button == "blue") {
id(active_button).publish_state("Blue");
} else if (button == "yellow") {
id(active_button).publish_state("Yellow");
} else if (button == "red") {
id(active_button).publish_state("Red");
} else {
id(active_button).publish_state("Idle");
}
- delay: !lambda 'return (button == "blue") ? id(blue_time).state * 1000 : (button == "yellow") ? id(yellow_time).state * 1000 : (button == "red") ? id(red_time).state * 1000 : 0;'
- lambda: |-
id(valve_mode).publish_state("Off");
id(script_running).publish_state("False");
id(active_button).publish_state("Idle");
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "your key"
ota:
- platform: esphome
password: "your password"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Smart-Cafe Fallback Hotspot"
password: "W0a33gCSdq3x"
captive_portal:
type: horizontal-stack
cards:
- type: custom:bubble-card
card_type: button
button_type: state
name: SmartCafe
icon: mdi:coffee-maker-outline
tap_action:
action: navigate
navigation_path: "#smartcafe"
button_action:
tap_action:
action: navigate
navigation_path: "#smartcafe"
card_layout: large
modules:
- opacity
sub_button:
main:
- name: Blue
entity: button.smart_cafe_blue_button
icon: mdi:circle
state_background: false
show_background: false
tap_action:
action: toggle
- entity: button.smart_cafe_yellow_button
icon: mdi:circle
state_background: false
show_background: false
name: Yellow
show_name: false
tap_action:
action: toggle
- entity: button.smart_cafe_red_button
icon: mdi:circle
state_background: false
show_background: false
name: Red
show_name: false
tap_action:
action: toggle
- entity: switch.smart_cafe_child_lock
icon: mdi:lock-open-variant
state_background: false
show_background: false
name: Child Lock
show_name: false
tap_action:
action: toggle
- name: Power
entity: button.smart_cafe_power
icon: mdi:power
state_background: false
show_background: false
tap_action:
action: perform-action
perform_action: button.press
target:
entity_id: button.smart_cafe_power
bottom: []
entity: binary_sensor.smart_cafe_state
show_icon: true
styles: |
styles: |
{
.bubble-button-card-container {
background-color: ${hass.states['binary_sensor.smart_cafe_state'].state === 'on' ? '#056bb8' : ''} !important;
}
.bubble-sub-button-1 .bubble-sub-button-icon {
color: blue !important;
}
.bubble-sub-button-2 .bubble-sub-button-icon {
color: yellow !important;
}
.bubble-sub-button-3 .bubble-sub-button-icon {
color: red !important;
}
${subButtonIcon[3].setAttribute(
"icon",
hass.states['switch.smart_cafe_child_lock'].state === 'on'
? 'mdi:lock'
: 'mdi:lock-open-variant'
)}
type: vertical-stack
cards:
- type: custom:bubble-card
card_type: pop-up
hash: "#smartcafe"
name: SmartCafe
icon: mdi:coffee-maker-outline
button_type: name
show_header: true
show_icon: true
show_name: true
styles: >
.bubble-button-card-container { border-radius: 14px; background: none
!important; }
.bubble-icon {
--mdc-icon-size: 50px !important;
}
.bubble-icon-container {
background: none;
}
.bubble-pop-up {
background: radial-gradient(ellipse at bottom, red, blue);
}
card_layout: normal
modules:
- "!default"
- "!opacity"
sub_button:
main: []
bottom: []
- type: custom:bubble-card
card_type: separator
styles: |
.bubble-line {
background: var(--primary-text-color);
opacity: 0.1;
}
name: Buttons
- type: custom:bubble-card
card_type: button
button_type: state
name: Power
show_state: true
icon: mdi:power
show_attribute: false
force_icon: false
entity: binary_sensor.smart_cafe_state
tap_action:
action: none
button_action:
tap_action:
action: perform-action
perform_action: button.press
target:
entity_id: button.smart_cafe_power
sub_button:
- entity: sensor.smart_cafe_lever_state
show_state: true
show_name: true
name: Lever
icon: mdi:dip-switch
tap_action:
action: none
- entity: switch.smart_cafe_child_lock
icon: mdi:lock-open-variant
state_background: false
show_background: false
name: Child Lock
show_name: true
show_state: true
tap_action:
action: toggle
styles: |-
{
.bubble-button-card-container {
background-color: ${hass.states['binary_sensor.smart_cafe_state'].state === 'on' ? '#056bb8' : ''} !important;
}
${subButtonIcon[1].setAttribute(
"icon",
hass.states['switch.smart_cafe_child_lock'].state === 'on'
? 'mdi:lock'
: 'mdi:lock-open-variant'
)}
- type: horizontal-stack
cards:
- type: custom:bubble-card
card_type: button
button_type: switch
entity: button.smart_cafe_blue_button
name: Blue
show_state: false
icon: mdi:button-pointer
show_attribute: false
force_icon: false
styles: |-
{
.bubble-button-card-container {
background-color: ${hass.states['sensor.smart_cafe_active_button'].state === 'Blue' ? '#056bb8' : ''} !important;
}
.bubble-icon {
color: #056bb8 !important;
}
- type: custom:bubble-card
card_type: button
button_type: slider
show_state: true
icon: mdi:tune-variant
entity: number.smart_cafe_blue_button_time
force_icon: true
show_icon: true
scrolling_effect: true
name: Blue Button Time
- type: horizontal-stack
cards:
- type: custom:bubble-card
card_type: button
button_type: switch
name: Yellow
show_state: false
icon: mdi:button-pointer
show_attribute: false
force_icon: false
entity: button.smart_cafe_yellow_button
styles: |-
{
.bubble-button-card-container {
background-color: ${hass.states['sensor.smart_cafe_active_button'].state === 'Yellow' ? '#056bb8' : ''} !important;
}
.bubble-icon {
color: yellow !important;
}
- type: custom:bubble-card
card_type: button
button_type: slider
show_state: true
icon: mdi:tune-variant
force_icon: true
show_icon: true
scrolling_effect: true
name: Yellow Button Time
entity: number.smart_cafe_yellow_button_time
- type: horizontal-stack
cards:
- type: custom:bubble-card
card_type: button
button_type: switch
name: Red
show_state: false
icon: mdi:button-pointer
show_attribute: false
force_icon: false
entity: button.smart_cafe_red_button
styles: |-
{
.bubble-button-card-container {
background-color: ${hass.states['sensor.smart_cafe_active_button'].state === 'Red' ? '#056bb8' : ''} !important;
}
.bubble-icon {
color: red !important;
}
- type: custom:bubble-card
card_type: button
button_type: slider
show_state: true
icon: mdi:tune-variant
force_icon: true
show_icon: true
scrolling_effect: true
name: Red Button Time
entity: number.smart_cafe_red_button_time
- type: custom:bubble-card
card_type: separator
styles: |
.bubble-line {
background: var(--primary-text-color);
opacity: 0.1;
}
name: Valves
- type: horizontal-stack
cards:
- type: custom:bubble-card
card_type: button
show_state: true
icon: mdi:coach-lamp
button_type: switch
entity: switch.smart_cafe_hot_valve
name: Hot Valve
- type: custom:bubble-card
card_type: button
button_type: switch
name: Cold Valve
show_state: true
icon: mdi:ceiling-light-multiple-outline
entity: switch.smart_cafe_cold_valve
grid_options:
columns: 12
rows: auto
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment