Restore switch state after reboot using globals

Hey all,

I have a relay module that uses esp32s3 and I’m trying to restore my relay state (with id relay1) to ‘OFF’ after a power reboot, if it was ‘OFF’ prior to the reboot. I’m using global variables for this. Here’s my attempt:

esphome:
  name: waveshare-6ch-relay
  on_boot:
    then:
      if:
        condition:
           lambda: "return id(relay1_status).state == 'false';"
        then:
          - switch.turn_off: relay1

esp32:
  board: esp32-s3-devkitc-1
  flash_size: 8MB
  framework:
    type: arduino

# Enable logging
logger:
  level: DEBUG
   
ota:
  - platform: esphome

wifi:
  ap: 
    ssid: "6CH-Relay"

captive_portal:

mqtt:
  broker: 1.1.1.1
  username: test1
  password: test0
  keepalive: 4s

globals:
  - id: relay1_status
    type: bool
    restore_value: true
    initial_value: 'false'

switch:
  - platform: gpio
    pin: GPIO1
    id: relay1
    name: Relay 1
    restore_mode: RESTORE_DEFAULT_ON
    on_turn_on:
      then:
        - globals.set:
            id: relay1_status
            value: 'true'
    on_turn_off:
      then:
        - globals.set:
            id: relay1_status
            value: 'false'

I’m getting the following error during compile:

Compiling .pioenvs/waveshare-6ch-relay/src/main.cpp.o
/config/esphome/waveshare-6ch-relay-wifi-mqtt-only.yaml:7:46: warning: character constant too long for its type
            lambda: "return id(relay1_status).state == 'false';"
                                              ^~~~~~~
/config/esphome/waveshare-6ch-relay-wifi-mqtt-only.yaml: In lambda function:
/config/esphome/waveshare-6ch-relay-wifi-mqtt-only.yaml:7:37: error: request for member 'state' in 'relay1_status->esphome::globals::RestoringGlobalsComponent<bool>::value()', which is of non-class type 'bool'
            lambda: "return id(relay1_status).state == 'false';"
                                     ^~~~~
*** [.pioenvs/waveshare-6ch-relay/src/main.cpp.o] Error 1
========================== [FAILED] Took 9.31 seconds ==========================

Not sure what this means,

I also tried :

on_boot:
  then:
    - lambda: |-
        if (!id(relay1_status)) { 
          id(relay1).turn_off();
        }

And this compiled but for some odd reason that I’m struggling to figure out, it didn’t work. relay1 turned on even when it was off prior to a reboot.

Thanks.

Globals don’t have state, use them just like variables.
lambda: “return id(relay1_status) == ‘false’;”

Anyway, you should be able to restore your switch state without globals.

Is your relay active high? Or maybe it should be inverted?
Also be aware that default flash write interval is 1min, if you change the relay state and right after turn the power off, new state is not saved.
You can adjust that if needed:

preferences:
  flash_write_interval: 30s
1 Like

Whoa, changing flash interval worked! Thank you!

You are welcome.
Be aware that in some rare applications, for example if your relay was changing the state every second 24/7, setting interval to 0 would lead to 1/s flash writes and would wear flash 60 times quicker than with default setting.

In normal use you don’t have to worry about it though.

1 Like

That’s good to know. So just to confirm - I have flash interval set to 30s and I’m seeing in logs that esp writes to flash 30s after relay changes state [I initially assumed it’d write to flash every 30s regardless of state changes]. If I set this to 0s, it means esp will write to flash right away. Which, in my case, shouldn’t be harmful since my relay doesn’t change states super often [once in a couple hours maybe]. So I’m safe to set this at 0s?

Yes, would be safe. But in practice, do you need so quick “backup” on your application?
If your relay changes state every 5min, the flash write would be same with default or 0s interval.
Just be aware that in some other application it could be bad idea. Fortunately you see the flash writes on log.

1 Like

Vish mentioned a power reboot, and the same thing happens with ESP32 deep_sleep (which is actually a shutdown then boot of the main processor).

With a standard relay when you stop applying power to the control pin the relay returns to its default state. Most often this is because the program turned that GPIO pin off - but also happens when the power to the microcontroller turns off. When power is turned on there is no way of knowing (from the relay anyway) what the state was before power went off. Hence the need for a global variable.

In my case I want the relay to stay set while the power is off, which requires a latching relay … but again the relay itself does not indicate whether it is currently set to “A” or “B” when the ESP32 reboots.

… and so I got here with the same error Vish had. Thank you Karosm for your explanation. Looking again at ESPHome.io documentation for Glabal Variables, now that I know what to look for … yes the example does not use .state.

Maybe the top of the page should be changed to point this out:

Global Variables

In some cases you might need to share a global variable across multiple lambdas. Globals don’t have state, use them just like variables. For example, global variables can be used to store the state of a garage door.

But this is really what that would be saying:
global variables don't have state, use them just like other variables.

I am guessing that whoever wrote the original text thought it inconceivable that someone would assume/think a global variable was different from a local variable. The examples don’t show using state and there are examples of usage, so it is actually better than some of the other sections.

Writing documentation that is easy for EVERYONE to use is actually incredibly hard, since people have different knowledge levels, understanding of concepts, and willingness to read.

The thing about open source is that it gets better when people care enough to help make it that way. If you feel the documentation would be better like that, submit a PR and see what others think.

1 Like