ESP32 WiFi instant Camera

The FS32 is a digital Polaroid that uploads the photo instantly to the cloud

Public Chat
Similar projects worth following
This WiFi instant camera is powered by a 2000mA/hr LiOn battery and Espressif state of the art WiFi "System of a Chip" allowing to be about 15 hours online and take hundreds of pictures. Press the shutter button and the JPEG will be uploaded to a digital gallery in the next 4 seconds. It’s a pure WiFi camera, without a memory card, so you need to be online to use it. The ESP8266 version allows 3MB of SPI Flash system as offline photo storage. The ESP32 version has save on Spiffs disabled since it's slower (Didn't found out why). It supports also a small oled display (128x64 pixels) and the upload API returns a small thumbnail. Any spare ESP board and Arducam OV2640/5642 will make it work. If it sparks your interest, check the files, and make one. This project is sponsored by your Screen manager for ESP32

Todo's first things first:

  1. Make consumption lower. Camera and any display should go to deep sleep after A data from Arducam fifo is read and B after any display shows fore some seconds the thumbnail or the message that the upload is done. UPDATE: Some steps on this direction taken. New versions will use the camera only for the moment to take the picture and then it will be disconnected (VCC off, connected to 3.3v through a P-channel mosfet) I tried to use VEXT on Heltec ESP32 but it does not support 200mA and voltage goes lower than 3v.
    On FS32 esp-32 version of the repository this is already implemented, just set gpioCameraVcc to the gate to your mosfet.
  2. Finish the ESP32 case design and find a good to way to connect power. I'm not satisfied with current Heltec ESP32 Wifi board in terms of battery charging since it drops voltage to a point that after some minutes the Espressif chip resets in a loop.
    UPDATE: Got feedback from the nice people from Heltec automation, the version V2 has this improved, now it's not optimal but it charges battery. Anyways without point 1 is pointless, since there is no battery that can resist 200+ mA of continuous power.

    EXTRA: Make a chunk-uploader to reduce the amount of failed uploads. Not sure if this idea will maturate but sounds challenging and doable. More about this idea here. Working on this next weekend.

    LoRa: There is a design with a Lora Antenna holder in the front. I though that it can be an interesting idea to make a "spy" camera that you can place somewhere as a security measure and will detect movement, take pictures and send a LoRa message. It can be placed remotely and if has no WiFi, can save the images on SPIFFs. Anyone interested ?

A new update is coming in the first weeks of 2020. I want to update the project and it’s dependences so it can be compiled easier in PlatformIO. If you like Espressif projects I recommend also taking a look in Remora addressable LEDs controller.


This project started somewhere around middle Sept, 2018. I was fiddling around with the Wemos D1 and I found out that I could create something to push pictures to the cloud without effort trying a SPI camera. So I just remixed an 3D design I found on Thingiverse and created a very simple WiFI camera. This first version was very raw, it had HTML mixed between C++ lines of code and it did little more than being a point and shoot camera with a one button web UX. This is how it looked after a few design iterations and about 300 grams of PLA wasted:

FS2 print in PETG

But it kick started the feeling that it could be much more.

The pictures where raw like a digital Polaroid, no camera software deciding that I need more light or focus here and multiple shoots. No. Just a raw JPEG delivered as a "best try" to your preferred upload endpoint. That was the beauty I've seen. Simplicity.

But of course not all where Roses and Guns, one of each 10 or 20 pictures, come out like this pictures you can see in the Album broken-uploads.

Then my father, that is an electronic self taught engineer since 20, told me that he wants to take time-lapse pictures of the puzzles he is making. So I started programming this as the first feature that you can preview in this simple gallery pressing the bottom-right Slideshow button.  He later helped me out to try it and kill some bugs.

As an introduction to programming I must say that I'm not a good C++ programmer since I come from a different world professionally, doing mobile API endpoints and Admin-panels for clients here in Germany mostly using PHP and frameworks like Symfony. So I had to first pick a book and digest how this new variable types and strict chars are supposed to work together. It was painful but I got to like it and this project is really my first step on this world of IoT. So please excuse me if you see some horrible coding style there. Just make your own fork and beautify it.

The features that this FS2 camera currently offers are:

  1. WiFi Manager: Turn it up...
Read more »


Second improved version for the Heltec ESP32. This one has a support at the USB side

sla - 439.29 kB - 11/26/2018 at 20:44



If you are planning to use LoRa WiFi then print this to put the antenna in the case, fits the original Heltec ESP 32 Lora ( )

sla - 746.47 kB - 11/25/2018 at 23:04



Improved version to fit a Heltec with Oled (128x64). Needs a screw of 2.3x6 mm (2x5 mm will also work)

sla - 7.80 kB - 11/25/2018 at 22:58



Print 2 of this. One to secure the board and second one for the LiOn battery ( I used this LiOn battery: )

sla - 13.36 kB - 11/25/2018 at 22:58



Corrected version without holes for the ArduCam OV5642 (5MP)

application/sla - 1.42 MB - 11/10/2018 at 11:55


View all 10 files

  • 1 × ESP32 Heltec Development Board GITHUB: board/esp32-oled branch | Used the version with 0.96inch OLED Display (128x64 pixels) LoRa 32 but you can use also the WiFi 32 without LoRa WiFi since both measure the same
  • 1 × Wemos D1 ESP8266 Board (Select one of them) GITHUB: develop branch | Please make sure to upload always the SPIFFS selecting the most bigger size.
  • 1 × ArduCam OV2640 ( 2 Megapixels and SPI version ) Both OV2640 and OV5642 with 5 Megapixels are supported. NOTE: At least SPI connections should be properly soldered otherwise the photo will look like a Mondrian, just without the charme
  • 1 × Adafruit Micro Lipo MicroUSB battery charger + diode Only if you use a Wemos D1 or similar board without battery charger included
  • 1 × 1 mini square shutter button

View all 8 components

  • Making a PlatformIO update

    Martin Fasani01/02/2020 at 18:55 0 comments

    I’ve been really busy with another projects like CALE Eink calendar but I still think that this one can be a good example for anyone dealing with SPI interfaces and is fun to build so I though about making an upgrade so it is:

    • Easier to install using PlatformIO 
    • Only one codebase for both ESP8266 and ESP32 (now that I have a bit more experience using #ifdef)
    • Add zlib compression to send the image in ESP32 version (will reduce at least 3 times upload time)
    • More customizable. Moving all config / SPI and so on into Config and leaving most configuration in a single place

    So that’s it. I wish you all a great start of 2020, build cool stuff and learn a lot in the process

    Martin Fasani

  • Returning a JPG thumbnail as a JSON array

    Martin Fasani01/06/2019 at 12:26 0 comments

    The limit I hit with this is that anything more than 10Kb of Json and Arduino JSON cannot parse it. So I didn't found time to check why it is, I just though about debugging it with PlatformIO with a board that supports debbuging and ordered one. The lines to do this in PHP are not very complicated, we will first reduce the thumbnail using imagemagic to about 60px height (Proportional) and then just read byte by byte and converting it to an integer. The image method does not really care if it's an hexa like "0xFF" or 255. So I prefer to sent 255 since it will generate a smaller Json response.

    switch ($returnType) {
            // JPG bytes
            case 3:
                $jpg = $im->getImageBlob();
                $cleanPixels = array();
                foreach(str_split($jpg) as $char){
                    array_push($cleanPixels, ord($char)); // For HEX image: "0x".strtoupper(bin2hex($char))
                //header("Content-Type: image/jpeg");exit($jpg); // Check JPEG
                $imageObj['jpg']    = $cleanPixels;
    $imageObj['url'] = "http://".$_SERVER['HTTP_HOST']."/".$directoryBase.$directoryDate.$uploadedName;
    $imageObj['hash']= md5_file($uploadedFile);
    $imageObj['folder'] = $getFolder;
    echo json_encode($imageObj);

    That will return a JSON like this (leaving only 5 bytes to avoid pasting an endless sucker here):


     This is how will parse this incoming bytes in C++

    // After successful upload and discarding response headers
     DynamicJsonBuffer jsonBuffer;
      JsonObject& json = jsonBuffer.parseObject(response);
      total_time = millis() - total_time;
      if (!json.success()) {
        printMessage("JSON parse failed", true, true);
        server.send(200, "text/html", "<div id='m'>JSON parse error. Debug:<br>"+response+"</div><br>");
      char imageUrl[300];
      char hash[33];
      char folder[33];
      // WARNING If the json does not contain any of this properties then ESP will reboot
      strcpy(imageUrl, json["url"]);
      strcpy(hash, json["hash"]);
      strcpy(folder, json["folder"]);
      // serverCaptureWifi()
      if (json.containsKey("jpg")) {
        JsonArray& arr = json["jpg"];
        int c = 0;
        const char* tempx;
        for (auto value : arr) {
          image[c] =<unsigned int>();
        // Draw thumbnail coming from json:
    drawArrayJpeg(image, sizeof(image), 0, 11);

    I hope that explains a bit more how is the JPG thumbnail rendering in this project.

    NOTE : If anyone has an advice regarding my 10Kb max JSON String please comment. I also found out that when the response coming from the API is two long, strange numbers appear in the beginning and the end, so I had to clean it up like this:

    // DEBUG: Do some ugly parsing since a big JSON comes with garbage at the beginning like 398f {"jpg":1,2} 0 (And an appended zero?)
    int jsonStart = response.indexOf('{');
    int jsonEnd = response.indexOf('}');
    response = response.substring(jsonStart, jsonEnd+1);

     That is really sub-optimal and I still do not understand why. Is because String has a limit in characters ?

  • Multi SPI with 128x128 color tft-7735 display

    Martin Fasani12/31/2018 at 23:31 0 comments

    Last week I found out some time to make a new model of the camera using a cheap 4€ display st7735.

    The wiring of the ArduCam is defined right after setup() and we use an independent SPI class for the camera. I wrote a short blog post about it and I must say that using an inexpensive wemos ESP32 and the TFT display with a total cost about 9€ I could build a quite decent camera. ( this 9 bucks they do not include camera of course )

    Blog post:

    3D file is still a bit raw. Just tell me if you have the intention to build one of this before I make the extra effort to clean it ;)

    Happy new year 2019! Let your projects see the light and don’t let anyone tell you that it can’t be done ;)

  • ESP32 new version and repository: 2 important additions

    Martin Fasani12/11/2018 at 08:48 0 comments

    ESP32 project has moved here:

    I'm a bit tired of switching branches all the time and I want to make a very basic version just for one camera model. Started using PlatformIO I find it much more versatile than Arduino, but it's compatible anyways, just open the contents of src/ and put the /data folder in the same level of your sketch. Camera firmware in this FS32 new repo is only for model OV5642 since I find it the best to take good pictures and finally after tweaking the code for weeks I'm able to take 19 good pictures out of 20 which is already much more than the previous rate. Stable code is currently merged on master.

    There are two important additions that help to avoid wasting time and disk space:

    1.  Check that the Arducam fifo memory read starts with the JPEG headers 2F / D8 and if not abort upload inmediatly:
    2. Generate an MD5(Arducam_FIFO) and compare to MD5(After_upload)  if it does not match then show a message on the display (Or turn HIGH a digitalWrite to give a signal that upload is corrupt using a LED)
      Optionally you can change the code to save this picture to spiffs only if the upload failed
    3. Point 2 involves returning a JSON string after upload containing:

    {"url": "full_url_to_image.jpg",  "hash": "md5_file(uploaded_file)" }
    Please check upload-xbm.php for a reference, it can be done in any language following that reply model.

    Already with this 2 things is much more versatile and secure to take a picture because you know that it's a JPEG (Also the camera is working good) and also that the upload worked out.
    Additionally there are two functions: cameraInit() and cameraOff() that take care of waking up the camera and switching it off after every photo if the config parameter: camera_mosfet is set to 1.

  • Get consumption down

    Martin Fasani11/26/2018 at 14:14 0 comments

    First 3 TOP actions here would be:

    1. Power the camera via a MOSFET or using VEXT if your board supports it, only power it in the second that you take the picture and then disconnect it the hard way  DONE!
      NOTE: Although some boards like Heltec ESP32 claim that they support up to 200mA in VEXT, at least OV5642 is above that, almost reaching 300mA and then Voltage will go down and it won't work. Use always an external MOSFET unless it's guaranteed that VEXT supports at least 350mA.
    2. Same with OLED display show anything for no more than 8/10 seconds, then make it off (Or sleep NOT DONE)
    3. If you don't do any server.handleClient() action or you don't press the shooter the ESP32 will go into Deep sleep mode ( Not sure if it makes sense a sleepAfterMinutes new setting, for the moment no )

    Starting taking the necessary steps to make the battery last longer: Read this if you are interested in the discussion

  • Finished the ESP32 integration

    Martin Fasani11/09/2018 at 11:38 0 comments

    ESP32 integration and refactoring from the ESP8266 is done. Uses XBM thumbnail rendering as a response from PHP Upload endpoint if you want to use a Board with Oled.  Please refer to this issue to see the JSON example:

    The PHP upload endpoint is here in upload-xbm.php :
    PHP Gallery is also a small Bootstrap 4 photo uploader and mini preview that is ready to receive the WiFi upload from the camera.

View all 6 project logs

View all 7 instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates