ESP32-CAM with Capacitive Touch Buttons and OLED

3D Printed ESP32 Camera

A 3D printed camera with an OLED display, saving to SD card and capacitive touch button controls.

ButtonCam 3D Printed Model

I designed the camera in Tinkercad. The front and back look like this:

TinkerCad Camera Front
TinkerCad Camera Rear

The 3D files need to flipped upside down in the slicer before printing:

Cura Camera Front
Cura Camera Rear

The final 3D prints look like this:

Button Cam Front 3D Print
Button Cam Back 3D Print


In addition to the ESP32-CAM. The project requires a microSD card, an SSD1306 OLED, three TTP223 capacitive touch switches, 15 dupont cables, a voltage booster, a 18650 battery and holder.

Project Components

The 18650 battery, holder and booster could be replaced with anything that can supply 5v to the ESP32-CAM.

Wiring Diagram

ESP32-CAM with OLED Wiring


It should be easy to install all the components as shown in the video. If you use a different part or something doesn’t fit, you can snap off the clips and just glue or Blu Tack the part in place.

The Code

C++ Code on the ESP32

In the Arduino loop, frames are constantly requested from the camera. Each JPG frame is decoded and the pixels converted to grey scale while saving into an array. This array is then processed a second time to create to a dithered monochrome array that is output to the OLED screen.

While this camera data is being streamed to the OLED the ESP32 also listens for button presses from the three capacitive touch buttons. If the trigger button is pressed, the camera switches to a higher resolution, captures a frame and this is saved to the microSD card and also briefly shown on the OLED screen.

If the left or right buttons are pressed the ESP32 reads the files before or after the current image on the microSD card and again, shows this on the OLED.

The HTML and JavaScript Code

In addition to the above, the ESP32 is also running a web server. This serves the page you see if you connect to the IP address shown on startup. The page contains a basic slide-show that is populated by images taken on the camera. When a new photo is taken, the Arduino code sends a websocket request containing the image ID of the new image to the web server. JavaScript on the web server then creates a new slide in the browser, requests the JPG file from the microSD card and displays it.

Demonstration Video

Fully assembled the project looks and functions like this:

Dithering Video for Monochrome Displays

Video passed directly from a camera to a monochrome screen can be difficult to make out. It needs to be dithered using error diffusion to break up the solid black and white areas. The Arduino code processes the image using the Floyd-Steinburg dithering algorithm.

When the frame size is set to QQVGA2 it is easy to decode the top part of the 128×160 frame to give 128×64 pixels to display on the OLED screen. The problem is that only the top part of the camera frame is shown on the screen.

I wanted to use frames from the full sensor so I set the resolution to QQVGA (160 × 120) and resampled the camera frames to create an array with the same resolution as the screen. However I discovered later than the minimum resolution that the ov2640 sensor outputs at full frame is CIF (352 x 288 pixels). I need to investigate this further.

OLED QQVGA2 No Dithering
128×160 resolution without dithering
OLED QQVGA No Dithering
160 × 120 resolution without dithering
OLED QQVGA2 Floyd-Steinburg Dithering
128×160 resolution with Floyd-Steinburg dithering
OLED QQVGA Floyd-Steinburg Dithering
160×120 resolution with Floyd-Steinburg dithering

It’s easier to see how effective using dithering can be with monochrome screens in the video below which shows the same two resolutions as above but with a moving image.

Monochrome Dithering Demonstration

ButtonCam MKII

Mark II of this project will have a power switch, the camera will be relocated and the code improved. The slide-show will probably be replaced with an image browser.

Code, 3D models, STL and Wiring Diagram

Front 3D model in Tinkercad:
Rear 3D model in Tinkercad:
Back 3D model with extra depth:
For the STL files, just click the Export button in the pages above.

The Arduino code is here:

You need to copy both files into new directory named ButtonCam with your other Arduino sketches. Use the following settings when uploading:

Upload Settings

Helpful Resources

Best guide to dithering I found –
Basic Floyd-Steinburg pseudocode –

33 Replies to “ESP32-CAM with Capacitive Touch Buttons and OLED”

  1. Robert Gwozdz says:

    sorry … my false of course … you wrote // 16 when psram off
    I forgot about it, now it starts up properly … 🙂

    1. WordBot says:

      My fault… I should have made it more obvious about pin 16. I’ll add a screenshot of the tools settings to the tutorial.

  2. Shubham Bhatt says:

    Hi i am not able to compile your code I install all the libraries still I get this
    Multiple libraries were found for “WiFi.h”
    C:\Users\hello\OneDrive\Documents\Arduino\libraries\ESPAsyncWebServer-master\src/ESPAsyncWebServer.h:33:22: fatal error: AsyncTCP.h: No such file or directory
    compilation terminated.
    Used: C:\Users\hello\OneDrive\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi
    Not used: C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.51.0_x86__mdqgnx93n4wtt\libraries\WiFi
    exit status 1
    Error compiling for board AI Thinker ESP32-CAM.

  3. Shubham Bhatt says:

    Also where can i get these files.
    #include “FS.h”
    #include “SD_MMC.h”
    #include “lcdgfx.h”
    #include “esp_camera.h”

    1. WordBot says:

      Oh sorry, looks like the tutorial doesn’t mention the libraries you need to install. It needs
      The ESP32 Hardware libraries: +
      I think that is all the libraries you need. Let me know if it’s not working.

      1. Shubham Bhatt says:

        For some reason it starts displays ip address on the screen and output the again reset?? any idea why.

        1. WordBot says:

          Did you disable PSRAM on upload? There was a screenshot missing for the upload settings from the tutorial.

          1. Shubham Bhatt says:

            I dont see psram ram setting in arduino IDE. How to disable it.

          2. Summer says:

            How to disable PSRAM in Arduino IDE?

              1. Summer says:

                Thank you WordBot for help me solved the problem of ESP32CAM + TFT of the pin used on SD card and lost function. this resulted me of this project here you used SD card and also sign the same pins for other use, how can that work? does the pins works time-sharing?

                1. WordBot says:

                  Which pins are used twice? I know on one of the tutorials the SD card is set in 1-line mode. I noticed that this one uses the Arduino SD card library so maybe that’s it.

  4. Shubham Bhatt says:

    Never mind its working now

    1. Finn Bonnen says:

      How did you solve it? i currently got the same problem and i can’t get it working.

      1. WordBot says:

        Which problem do you have? Did you switch off the PSRAM in the tools menu?

        1. Finn Bonnen says:

          no bc when i do so it sais frame buffer malloc failed and cam_dma_config failed. but when i turn the psram on it would just restart when i press the trigger.

          but i removed the display from the code bc i dont need it.

          1. WordBot says:

            Should work with or without PSRAM if you don’t have anything connected to io16 and the code doesn’t use it.

            Which version of the ESP32 hardware library are you using?

  5. Finn Bonnen says:

    i have installed the most recent i guess. its v2.0.2.

    1. WordBot says:

      I don’t think the code will work with that version. A lot has changed. Try with 1.0.4

      1. Finn Bonnen says:

        I tried v1.0.4 but for some reason it wouldn’t even compile. so i tried 1.0.6 which compiled but the board also rebooted after i pressed the trigger and after that it says Failed to get the frame on time !

        1. WordBot says:

          Did you get an compilation error? Are you using the script from Github?

          1. Finn Bonnen says:

            no not in 1.0.6 and i used the script linked in thins tutorial but i removed jpeg conversion and the oled support.

  6. Finn Bonnen says:

    no not in 1.0.6 and i used the script linked in thins tutorial but i removed jpeg conversion and the oled support.

  7. Volker Stark says:

    Hi i am not able to compile your code
    because TJpg_Decoder.h can not find LittleFS.h

    I am working with this boards:

    1. WordBot says:

      Looks like something has changed in the TJpg_Decoder library – maybe try an earlier version?

      1. Summer says:

        My board is OK to upload code to ESP32 Dev Module, but OLED does’t show picture, and the: just shown a green screen with two arrows. pressed trig button does’t do any thing, nor left right button.
        happened some time if the trig button pressed at a ‘GOOD’ time, one picture taken and saved to TF card, nothing else that I checked TF card known.
        what can be?
        Thank you for any help please.

        1. WordBot says:

          I’m not sure. Do you see anything in serial? It’s quite a hard project for the ESP32 to run because it’s doing so much but you should at least be able to see the image on the OLED.

          1. Summer says:

            Thank you for help.
            I’ll check the serial.
            BTW. does ESP32CAM be able to wire up a TFT display by SPI?
            Best to you.

              1. Summer says:

                Yes, like that one, but which can’t conduct success, even not show any thing on display.

                1. WordBot says:

                  Is it the same screen? Best start with the basics for this one to check the screen is OK. If you connect the screen as in the tutorial and then try one of the TFT_eSPI demos. It’s a little fiddly to set up because you have to edit the User_Setup.h file for the screen.

  8. alvaro says:


    im trying to test the project but im having troubles displaying the images taken. the images dont display on the entire screen, just it shows a line at the top. any suggestions?

    im using the same code of your project


    1. WordBot says:

      Hi, Have you tried the example demos for the TFT library just to check the screen is OK and set with the correct settings?

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

scroll to top