Deep sleep and rotary encoders in ESP32

Hi!

I’m trying to make a rotary encoder work as a remote dimmer for my lights using ESPHome on a ESP32. It’s working fine using the rotary_encoder sensor.

binary_sensor:
  - platform: gpio
    name: "Rotary Encoder Button"
    internal: true
    pin:
      number: GPIO27
    on_press:
      - logger.log: "Button pressed"
      # Do something to turn on/off the light

sensor:
  - platform: rotary_encoder
    name: "Rotary Encoder"
    internal: true
    pin_a: GPIO25
    pin_b: GPIO26
    on_clockwise:
      - logger.log: "Turned Clockwise"
      # Do something to increase the light intensity
    on_anticlockwise:
      - logger.log: "Turned Anticlockwise"
      # Do something to decrease the light intensity

Now I want to make it run on batteries using the deep_sleep component. It’s working fine using just one GPIO (with wakeup_pin), but I don’t understand how to deep sleep with three input pins (GPIO25, GPIO26 and GPIO27). As soon as the ESP32 enters in deep sleep mode, it immediately wakes up. This is my current attempt:

deep_sleep:
  id: deep_sleep_control
  wakeup_pin_mode: INVERT_WAKEUP
  esp32_ext1_wakeup:
    mode: ALL_LOW
    pins:
      - GPIO25
      - GPIO26
      - GPIO27

I think I’ve tried with every combination for wakeup_pin_mode and esp32_ext1_wakeup.mode. Using esp32_ext1_wakeup.mode=ANY_LOW the ESP32 goes to sleep, but then it won’t wake up. Using esp32_ext1_wakeup.mode=ANY_HIGH, the ESP32 immediately wakes up after going to sleep. I guess this would be easier if I could set a different wake-up status for every pin.

Any help?

Thanks!

Try setting this to IGNORE instead.

That’s the default value for wakeup_pin_mode, and I tested with all of them (I cannot really notice the difference). Having esp32_ext1_wakeup.mode=ALL_LOW, the only way I’ve found to wake up the ESP32 is by pressing the button and rotating the encoder at the same time (I guess it make sense because this way all three of the GPIO pins will eventually change to the same value).

My guess is that I should use esp32_ext1_wakeup.mode=ANY_HIGH because I want the board to wake up when any of the GPIO value change, but this way the device reboots over and over :frowning:

Ok, after some reading about how interrupts works in the ESP32, I found a configuration that (almost) works.

deep_sleep:
  id: deep_sleep_control
  wakeup_pin:
    number: GPIO27
  wakeup_pin_mode: INVERT_WAKEUP
  esp32_ext1_wakeup:
    mode: ALL_LOW
    pins:
      - GPIO25
      - GPIO26

So here I’m using the EXT0 for the encoder button and the EXT1 for shaft rotation. I think I should be able to only use EXT1, but maybe I would need to negate some input and I don’t want to add extra hardware.

Now I can check on boot which GPIO woke up the ESP32 and do my stuff.

  on_boot:
    priority: 900
    then:
      - lambda: |-
          int wakeup_reason = esp_sleep_get_wakeup_cause();
          ESP_LOGD("boot", "wakeup_reason: %d", wakeup_reason);
          if (wakeup_reason == 3) {   // EXT1
            uint64_t wakeup_status = esp_sleep_get_ext1_wakeup_status();
            double gpio_num = log(wakeup_status) / log(2);
            ESP_LOGD("boot", "gpio_num: %f", gpio_num);
          }

Now I just have to figure out why esp_sleep_get_ext1_wakeup_status() returns 0 most of the time (although sometimes I get the expected value)…