Internet Of ThingsTimelapse

Mini Battery and Solar Powered Timelapse Camera

I wanted a small, battery-powered timelapse camera. First I tried mobile phones but they were not stable in the long term. Previously I’d used a Raspberry Pi which is good, but not battery friendly, a bit big, and a bit of an overkill. A PiZero would be an alternative (untried).

Instead, I choose a ESP32-Cam which can:

  • go to deep-sleep (10uA for the ESP, Cam to be tested) overnight
  • save JPG files from its mini camera (but good enough) to SD card
  • connect to WiFi to transmit / control
  • be small and cheap!

I use the following:

  • ESP32-Cam from which is similar to AI-Thinker
  • A 2000mAh 585460 flat LiPo battery. A 18650 LiPo battery worked, but needs seperate low-voltage protection.
  • Adafruit Solar Charger
  • 3v to 5v USB step up (from battery output to 5V* for Cam)
  • FTDI Programmer to flash the firmware
  • 1W 6V solar panel (20cmx20cm)

* Note 5V is required for the ESP32-Cam, although the ESP32 needs only 3.3V.


I used a 3.3V / 5V (switchable via toggle) FDTI programmer. I used 5V thinking that I’d supply 5V to VCC and 3.3V to the RX/TX pins. Oops! It actually supplies 5V to RX/TX pins too. Seems ok but better to select 3.3V to get this on the RX/TX and grab a 5V breakout pin to power the board.

Power Supply and Battery

A 1W solar panel provides 4Wh/W (Brisbane) x 1W = 4Wh per day.

This is 4Wh / 3.3V = 1.2Ah per day @ 3.3V. Say 1000mA/day. The 18650 battery is 2600mAh, so needs 2.6 days to charge!

Power consumption of the camera is to be tested. ESP32 is 50mA and only 10uA alseep. Maybe 50mA average (?), or 2600mAh / 50mA = 52h on battery. On panels, maybe 50mA * 10h = 500 mAh/day required:

First test 1 June 2019: Without sleeping, ran for about 20 hours continuously with photos at 10s. This is about right: in this mode, we have Wifi, Cam and SD on. That takes about 130mA which gives a run-time of 15 hours.

More detailed readings:

  • Deepsleep is 4mA instead of bare ESP32 of 10uA. No a major problem in this application.
  • Camera is an additional 10mA, regardless of taking or just ‘on’.
  • That bright LED is a power sucker.
  • Turning the SD has no power penalty. Even holding a file open has no impact.
  • Using esp_wifi_set_ps(WIFI_PS_NONE)) will improve upload speed, but
ModeWiFiCamSD ActiveCPULED Pin4mARun time @ 2000mAh (h)
Continuous SD Save (No LED)xx9022
SD, WiFi, x (No PS)x xx120
SD, WiFi, Camx (No PS)x xx180 (230 photo)
SD, Wifi, Cam, Modem Sleep / PS Onx (PS)xxx150 (average)13
SD, Wifi Off, Cam (Wifi was on)xxx100 (170 photo)
SD, Wifi Off, Cam Off (Cam,Wifi were on)xx70
FTP Uploading (LED)xxxx18011
Continuous SD Save (LED)xxx3406

We see that compared to a ‘bare’ ESP32, the Cam version reasonable energy consumption if you remove the LED. However, the deepsleep mode is no longer extremely low consumption. This suggests a battery-only unit would only run for a week, but a solar-and-battery is feasible. Alternatively, a weekly recharge might work.

WiFi takes about 1.3s to start and the Cam turns 0.5s to start.

Deepsleep might be good for long periods. We estimate the runtime (in hours).

MethodPhotos @ 3s
Photos @ 10s
Photos @ 60s
[Deepsleep, Batch Upload]
Photos @ 600s
[Deepsleep, Batch Upload]
Always On, No WiFi23313840
Deep Sleep, No Wifi2661222500
Deep Sleep, Save, Upload in Batch1843182426
Always On, WiFi, Upload in Batch15243639

So regardless of if we have WiFi or not, the upshot is,

  • Intervals <10s: Always On is fine
    • Use Modem Sleep (default) on to reduce standby WiFi power
    • 13h of operation is insufficient – use a larger battery (5000mAh) to get 2.5 days operation and use a solar panel.
  • Intervals >60s: Deepsleeping worthwhile.

Energy Results and Further Improvements

Real-life battery life on 2000mAh is still poor : only 6 hours. This is due to the standby 70mA (i.e. cam not taking but init’d, WiFi off). Arduino IDE doesn’t allow full control of sleep modes. So I switched to ESP-IDF.

Based on these excellent posts about ESP32 battery life, I tested the ESP32-CAM board. This is based on the power_save example. Moved to using a 1ohm resistor and measuring voltage to find the current (I=V/R) – this is more convenient that an in-line DMM current meter.

ModeCurrent (mA)DescriptionNotes 
Default21Full defaults, wait at startup
Add basic DFS14Enable DFS from menuconfig
Better DFS5Scale: 10MHz to 80MHz
Wifi On120PS_NONE(DFS reset to 10 to 240MHz)
Wifi Default15 (20 avg?) PS_MODEM_MIN
Wifi Max Powersave7 (10 avg?) PS_MODEM_MAXThe "listen_interval" only affects this mode. Greater than 10 (default: 3) is not interactive.

We see that Dynamic Frequency Scaling (i.e. clock gate the CPU when idle) is very effective to stop idle time chewing mA. With WiFi docs, using the MODEM_SLEEP mode in default (“MIN”) mode is pretty good. Bumping up the “MAX” mode allows the listen_interval to be set. It’s in 100mS units. Setting to 1s (i.e 10x) results in some improvements.

This looks promising. Now we need check the current when the camera is init’d but idle.

Lack of GPIO!

The ESP32 needs to know the state of the battery and solar, so it can control itself. It uses the Adafruit solar controller’s output. It also uses time-of-day to off when dark (a PE cell would be an alternative).

Reading voltage required two GPIO pins. However, these are NOT AVAILABLE on the ESP-32 cam. All broken out pins appear to be used by either the SD card or UART or camera. GPIO16 didn’t work (TBC!). I couldn’t use the SD card pins. The only option I see is to use the TX/RX pins (GPIO1, GPIO3). These are not connected to the ADC so cannot read analog. Also this means serial is not available, but RemoteDebugger library is possible.

GPIO3 (RX) works to read the open-drain of the “charging” or “done” indicator. I can’t get GPIO1 (TX) to read, nor GPIO16. GPIO2 works but is used by the SD card. This comment agrees with the TX/RX issue. Hence only a single digital input is available – either “charging” or “done”. As the least worst, I’ll use “done” to signal that uploading should start.

Hence, the following is ideal, but not possible:

Since the maximum possible voltage is 6V (“the voltage at L+ can rise to whatever comes out of your solar panel”), I use a voltage divider to halve the voltages before measuring with the ESP32’s ADC.

Lowish Battery, solar powering L+ > B+ (by < 150mV)
B+ > 3.2V
Wifi Off
Cam On
Low BatteryB+ <= 3.2VDeep sleep
Good solar, battery > 50%L+ > B+ (by > 150mV)

B+ > 3.5V
Wifi Full

Cam On
No solar, battery > 50%L+ < B+

B+ > 3.5V
Wifi Minimal

Cam On
No solar, battery < 50%L+ < B+

B+ <= 3.5V
Wifi Off

Cam on

Image File Transfer

Wifi Minimal means upload limited snapshots of the current images, while Wifi Full means upload all images. Some upload options:

  • Dropbox : adapt a library
  • Upload to a server running Apache or similiar, via HTTP
  • scp : no libraries?
  • FTP: easily adapt a library

The dropbox option looked simplest, but the only library needed heavy modification to work with ESP32. This worked okay, but was very slow: approximately 3kB/s. This is only one medium quality image per 10s.

A quality C library for FTP on the Esp32 worked well. The only trick was the ESP32-Arduino SD_MMC library mounts the card to “/sdcard” and fails if you try to mount at “/”. The Arduino File libraries understand this read from “/”. However, the FILE* ftp library sees “/sdcard”. A thin-wrapper in C++ to the FTP library always it to play nice with Arduino File classes.

Performance for FTP (ESP32 -> WiFi -> AWS EC2 server) was 120kB/S. This is a few images per second.

File opening is 300ms on the SD Card. Posix functions (FILE*) appear faster than fs::File classes in Arduino.

vsftpd worked well on AWS and Ubuntu after Googling fixed passive mode problems.

Movie Creation and Monitoring

The general approach is to get the image files to a server as simply as possible. Then do complex stuff on the server.


The latest image is copied to a known location for a webserver to display. A more advanced system would copy one file a minute (or so) to the webserver, which could then have a simliar forward/back viewer to preview the movie.


Every hour (or so), a script runs to create an hour-long movies. It would have to work out which movies are to be updated, based on new images. Use python and ffmpeg, and TimeLapseMovieMaker to create videos.

A “movie-to-now” could be created by joining the hourly movies together.

Also, each day a daily movie could be made.

Images can be deleted once an hourly movie is made. However, how to handle the case where late-arriving images need to be added to an old movie? Perhaps some kind of simple database is required to track images and movies? Or a simple metric of delete-when-7 days old-and-movie-is-make?


Some of the elements are similar to “Blobs” software, but sufficiently different to warrant a new project.

  • Implement different tasks (upload, camera, etc) via FreeRTOS.
  • Use WifiManger to connect to station or use AP, as required.
  • On hard-reset (or some other signal such as flag on web server / physical button / every 1 hour), run configuration webserver.
  • Camera loop can sleep between takes
  • Time Task to check internet time / RTC (for timestamps)
  • Power Task to check power supply and set flags / control operation. Related: sleep when dark.
  • Minimal upload can be done after image is taken. If so (i.e. enough battery/solar), it just uploads current image (every nth image) and closes WiFi.
  • Full upload as a permanent task which runs when possible.

The separate tasks check their own conditions and block if not required, then a sleep_idle_hook to sleep whenever possible. This is event-driven.

( An option would be to run in a loop, executing tasks when conditions are met. This is a more procedural style. )

WebApp to Modify On-the-Fly

A webpage to view the state of the ESP32, the last image and to modify things like the photo interval would be handy.

The webserver

It should

  • Run as a single web page webapp and use AJAX or websockets to communicate.
  • Have a file browser and editor

The Expressif WebServer for arduino-esp32 is pretty simple and doesn’t support websocket, but has nice example and a ready-to-go file browser. I choose this initially. But the SDWebServer doesn’t work out of the box (some easy “/” related problems) and is limited to a single client.

The more complex AsyncServer seems more production-ready and has websockets. There are, however, fewer examples and no SD card file server for the ESP32. With some modifications, SPIFFSEditor can use SD_MMC filesystem (no folders, though – would need to add). The addHandler process is easy. I’ll use this.

Interface / Javascript

AJAX or websockets will allow nicer development. I’m trying BootStrap to get a tidy interface. and enable you to easily create a css/html set of file to display nice buuttons and the like.

Next, how to use JS or jQuery to communicate with the webserver? WebStorm is good for editting the html/css/js and provides a webserver to test it locally (on a pc).

7 thoughts on “Mini Battery and Solar Powered Timelapse Camera

  1. Hi Brett,
    An interesting article – thanks!
    I too have been experimenting with the ESP32-cam for timelapse recording. I intend to record some building work that will be starting on my house soon.

    A couple of things I’ve found; The onboard 3.3 regulator is very inefficient, I’m feeding around 3.6 volts directly to the 3.3V pin, so that regulator isn’t doing anything except draining power! I found that If I disconnected just the two outer pins of the regulator which is the large device near to the reset button, the standby current dropped from about 6mA to around 1.75mA. I’ve also experimented with removing then 1k pulldown resistor for the ‘pwdwn’ pin on the camera, and connecting that line to the ‘cam pwr’ line on the ESP, the idea being that the camera gets powered off when ESP goes into deep sleep. That does appear to reduce the total sleep current to less than 1mA (I can’t accurately measure it but I think its about 0.7 – 0.8mA) The only problem I’ve found with this is that the camera takes time to adjust its light level each time the ESP wakes, so I’ve had to delay the picture capture by about 1 second, otherwise it’s over exposed.

    I’ve found the AI-thinker schematic is here:

    Jim (Norfolk, England)

    1. Hi Jim,
      I’d be interested to see your results. You can see a TL of my last house construction (“Sustainable Buildings > A39 -> Overview”).

      I was a bit disappointed about the deepsleep current, as I’ve previously got 0.010mA for a FireBeetle Esp32 with a regulator. Getting < 1.0mA might make a long-term, interior unit feasible. The 6W PV + 2000mAh battery seems to work well outside. At least in sunny Brisbane! Thanks for the link. Cheers, Brett

  2. Did you have a local AP that the ESP32 could connect to via WiFi? I am looking to run a long term time lapse of a house build and would prefer file uploads either regularly or intermittently but not sure how to run the 4G with out draining the battery. Also, how did you fix the image quality issues? I have been tweaking the compression rates and a few other settings but the images are very washed out and low quality.

    1. Hi Jeremy!

      Yes, I have a AP for WiFi upload. I haven’t used 4G for uploads. Currently I only get 12 hours of battery life (2000 mAh battery, 10s interval, high quality). I’m investigating power save modes now. General approach is to turn off WiFi until battery is fully charged (by solar panel), then do a ‘blast’ of upload. You might be able to do the same.
      I too have tried improving quality, but to no avail. There are other units (“ESP EYE”) and camera (“OV” series) which might be better?

  3. Hi Brett,
    You met me yesterday in a reply to mtnbkr88. I asked a question about accessing power saving modes on my ESP32-CAM. Thanks again for that. My real name is Ed. I’m now trying to find a way to check the voltage of the 18650 battery powering my board and I was sad to find there are no ADC pins available on the AI Thinker ESP32-CAM. I have a 6V 4.5W solar panel connected to a TP4056 board. This board charges the 18650 battery and also provides outputs to power a device. I have these outputs connected to DC to DC boost converter that puts out a steady 5v for my ESP32-CAM as long as the battery voltage is above 1.7v. So now I want a way to check the battery voltage from the ESP32-CAM. Any ideas? Thanks!

    1. Hi Ed. I missed your comment, but don’t have any ideas. I ran into the same problem – no analog pins. If you don’t use the SD card, I think those pin would work.

Leave a Reply

Your email address will not be published. Required fields are marked *