I have invested in wifi light bulb (Biltema/Tuya concerted to ESPHome) but then everything is controlled remotely and the Wife/Spouse/Family Acceptance Factor has not been that great. I have taped the light switch buttons and the family members are stretching the tape.
I have now created a Switch button sequence where the light bulb changes brightness (itâs so far just a monochrome light bulb) each time I power cycle it, e.g. 100%, 75%, 50%, 10%, off, 100%, 75%, etc, etc.
Please note that itâs important to separate the Power-On boot behavior from the other boot sequences.
I share the code below if someone else would like to do the same, or if you are more fluent in ESPHome YAML hacking than I am and are willing to improve what I have done.
In short what this does:
- Defines global variables for counting Power-On boots, storing last on/off state, and storing last brightness
- Saving on/off state and brightness whenever possible at a shutdown, i.e. some kind of controlled shutdown like a SW reboot. This eliminates the need for defining a light component restore_mode and will save the FLASH memory since there will be fewer write cycles
- Checks the boot counter to find out the sequence number of Power-On reboots using a template switch and case statement. If not a Power-On boot, we just restore the previous state saved in the global variables
- To not have to wait one minute when power-cycle the switch I needed to decrease the flash write latency using the preferences component:
preferences: flash_write_interval: 2s
- And I needed to turn off the restore mode in the light component
- Whenever having a group light bulbs connected to the same switch we need to sync the counters. I did this by exposing a boot counter reset button to HA
And thatâs pretty much all
esphome:
name: "iot-esphome-light-e27-nb-m-bt06"
friendly_name: "iot-esphome-light-e27-nb-m-bt06"
on_boot:
priority: 601
then:
- if:
condition:
lambda: |-
return ESP.getResetReason() == "Power-On";
then:
- light.turn_on:
id: light_monochromatic
brightness: !lambda |-
float brightness;
switch ((id(boot_count) += 1) % 5) {
case 0: brightness = 1.0; break; // 100% brightness
case 1: brightness = 0.75; break; // 75% brightness
case 2: brightness = 0.5; break; // 50% brightness
case 3: brightness = 0.1; break; // 10% brightness
case 4: brightness = 0.0; break; // Off
default: brightness = 1.0; // Just in case
}
return brightness;
else:
- light.control:
id: light_monochromatic
state: !lambda |-
return id(last_light_state);
brightness: !lambda |-
return id(last_brightness);
on_shutdown:
then:
- lambda: |-
id(last_light_state) = id(light_monochromatic).current_values.is_on();
id(last_brightness) = id(light_monochromatic).current_values.get_brightness();
globals:
- id: boot_count
type: int
restore_value: yes
initial_value: '0'
- id: last_brightness
type: float
restore_value: yes
initial_value: "0.0"
- id: last_light_state
type: bool
restore_value: yes
initial_value: 'false'
preferences:
flash_write_interval: 2s #Shorten the default value from 1 min to 2 second
bk72xx:
board: generic-bk7231t-qfn32-tuya
logger:
level: DEBUG
web_server:
captive_portal:
mdns:
api:
encryption:
key: !secret api_encryption-key
ota:
platform: esphome
id: my_ota
password: !secret ota_password
wifi:
networks:
- ssid: !secret wifi_ssid_iot
password: !secret wifi_password_iot
ap:
password: !secret wifi_password1
button:
- platform: restart
name: Restart
- platform: template
name: "Reset Boot Count"
on_press:
then:
- lambda: |-
id(boot_count) = 0; // Reset the boot_count global variable
text_sensor:
- platform: debug
reset_reason:
name: Reset Reason
sensor:
- platform: uptime
name: Uptime
- platform: template
name: "Boot Count"
id: boot_count_sensor
lambda: |-
return id(boot_count);
output:
- platform: libretiny_pwm
id: output_cold
pin: P7
light:
- platform: monochromatic
id: light_monochromatic
name: Light
output: output_cold
#restore_mode: ALWAYS_ON
#restore_mode: RESTORE_DEFAULT_ON
default_transition_length:
seconds: 2
But there are some more things to do:
- Making the code easier to modify for those have more complex setup with colors etc.
- Saving some Flash writes by checking if the on/off state and brightness is the same as the stored values in the shutdown trigger. This since the ESP/Tuya chip with ESPHome FW sometimes reboots occasionally and we donât write the the Flash that if not needed.
- Check if the flash_write_interval that I set to 2 seconds really works. From what I can see, I can toggle the switch button faster than 2 seconds and it still works. Having longer time will show some mercy to the chip power circuits
Edit: I added the same feature for a light bulb that I could controol the tone and then it looks like this in the boot automation. As can be seen, quite messy
on_boot:
# - priority: 0
# then:
# - lambda: |-
# id(my_ota).set_auth_password(ESPHOME_IDFN("ota_password"));
priority: 601
then:
- if:
condition:
lambda: |-
id(boot_count) += 1;
return ESP.getResetReason() == "Power-On";
then:
- light.turn_on:
id: light_cwww
brightness: !lambda |-
float brightness;
switch (id(boot_count) % 5) {
case 0: brightness = 1.0; break;
case 1: brightness = 1.0; break;
case 2: brightness = 0.2; break;
case 3: brightness = 0.2; break;
default: brightness = 0.0; // Off
}
return brightness;
cold_white: !lambda |-
float cold_white;
switch (id(boot_count) % 5) {
case 0: cold_white = 1.0; break;
case 1: cold_white = 0.0; break;
case 2: cold_white = 1.0; break;
case 3: cold_white = 0.0; break;
default: cold_white = 0.0; // Off
}
return cold_white;
warm_white: !lambda |-
float warm_white;
switch (id(boot_count) % 5) {
case 0: warm_white = 0.0; break;
case 1: warm_white = 1.0; break;
case 2: warm_white = 0.0; break;
case 3: warm_white = 1.0; break;
default: warm_white = 0.0; // Off
}
return warm_white;
else:
- light.control:
id: light_cwww
state: !lambda |-
return id(last_light_state);
cold_white: !lambda |-
return id(last_cold_white);
warm_white: !lambda |-
return id(last_warm_white);
brightness: !lambda |-
return id(last_brightness);
on_shutdown:
then:
- lambda: |-
id(last_light_state) = id(light_cwww).current_values.is_on();
id(last_cold_white) = id(light_cwww).current_values.get_cold_white();
id(last_warm_white) = id(light_cwww).current_values.get_warm_white();
id(last_brightness) = id(light_cwww).current_values.get_brightness();