ESP32Camera deep sleep

Hello, my small HA setup is battery powered with a solar panel. I’ve 3 ESP32cam connected but I would like to spare some energy using deep sleep feature. The idea is to put 3 cameras in deep sleep during the night (from 19:00 to 09:00) Reading several posts, it seams that MQTT is mandatory and API configuration needs to be removed.

There is someone that can provide me a configuration example?

Many thanks in advance.

Here my current config file:

substitutions:
  hostname: "gnc"
  camname: "gnc"

esphome:
  name: $hostname
  friendly_name: $hostname
  #on_boot:
  #  - lambda: |-
  #      id(my_ota).set_auth_password("xxxxx");

esp32:
  board: esp32cam
  framework:
    type: arduino

logger:
#  level: very_verbose

api:
  encryption:
    key: !secret api_key
  services:
  - service: camera_set_param
    variables:
      name: string
      value: int
    then:
      - lambda: |-
          bool state_return = false;
          if (("resolution" == name) && (value >= 0U) && (value <= 17U)) { id($camname).set_frame_size((esphome::esp32_camera::ESP32CameraFrameSize)value); state_return = true; }
          if (("vertical_flip" == name) && (value >= 0) && (value <= 1)) { id($camname).set_vertical_flip(value); state_return = true; }
          if (("horizontal_mirror" == name) && (value >= 0) && (value <= 1)) { id($camname).set_horizontal_mirror(value); state_return = true; }
          if (("contrast" == name) && (value >= -2) && (value <= 2)) { id($camname).set_contrast(value); state_return = true; }
          if (("brightness" == name) && (value >= -2) && (value <= 2)) { id($camname).set_brightness(value); state_return = true; }
          if (("saturation" == name) && (value >= -2) && (value <= 2)) { id($camname).set_saturation(value); state_return = true; }
          if (("special_effect" == name) && (value >= 0U) && (value <= 6U)) { id($camname).set_special_effect((esphome::esp32_camera::ESP32SpecialEffect)value); state_return = true; }
          if (("aec_mode" == name) && (value >= 0U) && (value <= 1U)) { id($camname).set_aec_mode((esphome::esp32_camera::ESP32GainControlMode)value); state_return = true; }
          if (("aec2" == name) && (value >= 0U) && (value <= 1U)) { id($camname).set_aec2(value); state_return = true; }
          if (("ae_level" == name) && (value >= -2) && (value <= 2)) { id($camname).set_ae_level(value); state_return = true; }
          if (("aec_value" == name) && (value >= 0U) && (value <= 1200U)) { id($camname).set_aec_value(value); state_return = true; }
          if (("agc_mode" == name) && (value >= 0U) && (value <= 1U)) { id($camname).set_agc_mode((esphome::esp32_camera::ESP32GainControlMode)value); state_return = true; }
          if (("agc_value" == name) && (value >= 0U) && (value <= 30U)) { id($camname).set_agc_value(value); state_return = true; }
          if (("agc_gain_ceiling" == name) && (value >= 0U) && (value <= 6U)) { id($camname).set_agc_gain_ceiling((esphome::esp32_camera::ESP32AgcGainCeiling)value); state_return = true; }
          if (("wb_mode" == name) && (value >= 0U) && (value <= 4U)) { id($camname).set_wb_mode((esphome::esp32_camera::ESP32WhiteBalanceMode)value); state_return = true; }
          if (("test_pattern" == name) && (value >= 0U) && (value <= 1U)) { id($camname).set_test_pattern(value); state_return = true; }
          if (true == state_return) {
            id($camname).update_camera_parameters();
          }
          else {
            ESP_LOGW("esp32_camera_set_param", "Error in name or data range");
          }

ota:
  platform: esphome
  password: !secret ota_password
  id: my_ota
  
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: $hostname Fallback Hotspot
    password: !secret fallback_ap_psw

captive_portal:

esp32_camera:
  id: $camname
  name: Camera

  external_clock:
    pin: GPIO0
    frequency: 8MHz
  i2c_pins:
    sda: GPIO26
    scl: GPIO27
  data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35]
  vsync_pin: GPIO25
  href_pin: GPIO23
  pixel_clock_pin: GPIO22
  power_down_pin: GPIO32
  
  # orientation
  horizontal_mirror: false
  vertical_flip: false
  resolution: 1024x768
  
# esp32_camera_web_server:
#   - port: 8080
#     mode: stream
#   - port: 8081
#     mode: snapshot

button:
  - platform: restart
    name: Restart

binary_sensor:
  - platform: status
    name: Status

sensor:
  - platform: wifi_signal
    name: WiFi Signal db
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"
        
  - platform: copy
    source_id: wifi_signal_db
    name: WiFi Signal Percent
    filters:
        - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: Signal %
    entity_category: "diagnostic"

output:
  - platform: ledc
    channel: 2
    pin: GPIO4
    id: espCamLED
  - platform: gpio
    pin:
      number: GPIO33
      inverted: True
    id: gpio_33
    
light:
  - platform: monochromatic
    output: espCamLED
    name: Flash LED
  - platform: binary
    output: gpio_33
    name: Red LED 

I would be suprised if they need to only use MQTT and have API disabled. I have some ESP32-CAMs in a hot environment and only want one photo per hour to check oil levels. I use the api and not MQTT.

I use the deep sleep functionality, with a command to wake in 59minutes. Upon wake the ESP32 invokes a HA script which requests a camera snap from the device. After this, it triggers a template switch on the ESP which puts it to sleep.

I would have thought you cam add a time: componesnt (either sntp or ha) and then use the on_time functionality to run a script every night at 7pm to put the camera to sleep for 14 hours.

As I understand it, the wake after delay functionality is not super accurate, so I wouldn’t be surprised in there is up to a couple of minute drift on wake time, but that shouldn’t be an issue in your scenario.

Thanks for your suggestion, you put me in the right direction, the code I’m testing looks like this:


deep_sleep:
  id: deep_sleep_1
  run_duration: 10min
  sleep_duration: 12h
 
time:
  - platform: sntp
    on_time:
      # Every day
      - seconds: 0
        minutes: 0
        hours: 19
        #days_of_week: MON-FRI
        then:
          - deep_sleep.enter: deep_sleep_1

It could work?

That looks about right to me!

I haven’t had any issues but that will just go to sleep every 12 hours so if it’s awake at that time (7PM) the script should work. I know to get some temperature sensors working I had to set the update interval so the sensors only update every hour and only stay awake for 45 seconds. Before I did that they would just go unavailable when it powered down. A little bit different then what you are trying to accomplish. I don’t have MQTT defined and the API is in there also. Might help if your solution doesn’t as you obviously have to wait and see.

i2c:
  sda: 6
  scl: 7
  
sensor:
  - platform: wifi_signal
    name: seeed-ig88 WiFi signal
    update_interval: 1815s
  - platform: uptime
    name: seeed-ig88 uptime

  - platform: sht3xd
    temperature:
      name: "ig88 temperature" 
      id: temperature_ig88
      filters:
        - lambda: return x * (9.0/5.0) + 32.0;
      unit_of_measurement: "°F"      
    humidity:
      name: "ig88 humidity"
      id: humidity_ig88
    address: 0x45
    update_interval: 3620s

  - platform: bmp280
    temperature:
      name: "ig88 barometric temperature"
      id: temp_ig88
    pressure:
      name: "ig88 barometric pressure"
      id: pressure_ig88
    address: 0x77
    update_interval: 3620s

deep_sleep:
  run_duration: 45s
  sleep_duration: 60min

This approach can probably work, but also consider another approach to ensure the sensors submit the data before the deep sleep happens…

The way I go it is to have the sleep set as 1 hour but not to automatically enter deep sleep for 10 minutes… However I also have a template switch with an action assigned to enter sleep immediately if turned on…

Then jnside HA I have an automation to turn on this sleep switch after the sensor has been updated. This means that the device will enter sleep I immediately after data is received.

This means that if there are connectivity glitches which prevent the device submitting the data then the device will try for longer.

It also has the advantage that if you want to do an OTA upgrade, you can temporarily disable this sleep automation in HA so the device stays Alice longer allowing you to flash it.

I did some tests and this configuration seems to work ( and I’m really happy :-)). I just need to check the long sleep time.

deep_sleep:
  id: deep_sleep_1
  #run_duration: 10min
  sleep_duration: 10h

time:
  - platform: homeassistant
    on_time:
      # Every day
      - seconds: 0
        minutes: 00
        hours: 21
        #days_of_week: MON-FRI
        then:
          - deep_sleep.enter: deep_sleep_1

Prevent the deepsleep in this scenario isn’t required in my view due to the long alive time during the day where I can flash new versione without time constraints.

It would be perfect to be able to define in HA the start hour and the sleep duration hours. I suppose it should be done via template, helpers.

Any suggestion is welcome.:slight_smile:

Yes, if you want the command to sleep to come from HA you can create a template switch on the ESP

switch:
  - platform: template
    name: "Sleep"
    turn_on_action:
      - deep_sleep.enter:
          sleep_duration: 60min

Then just create an automation to turn this switch on at whatever time you want

To define the hours to sleep for, you can create a global (restore: true). Use this global as the sleep duration and create a template number with an on_value script to update the global value when a new number is set from HA

1 Like

Really thanks for the support, it make more sense to me to delegate the schedule to HA, I’ll try to apply your suggestion.

I would not have thought of this and will make future projects much easier so thanks! Also just wanted to mention that I was reading the time component ESPHome docs and it supports cron format so the possibilities are endless for more complex time schedules like turning something on the 4th month on the 2nd day at the 0 hour which could also be done from HA, users choice. There are also lambda options for ESPHome.

time:
  - platform: sntp
    # ...
    on_time:
      # Every 5 minutes
      - seconds: 0
        minutes: /5
        then:
          - switch.toggle: my_switch

      # Every morning on weekdays
      - seconds: 0
        minutes: 30
        hours: 7
        days_of_week: MON-FRI
        then:
          - light.turn_on: my_light

      # Cron syntax, trigger every 5 minutes
      - cron: '00 /5 * * * *'
        then:
          - switch.toggle: my_switch