Library / SDK
BojanJurca/Esp32_oscilloscope avatar
BojanJurca/Esp32_oscilloscope

ESP32 Oscilloscope: a signal viewer that runs on the board itself

ESP32 oscilloscope - see the signals through Web browser the way ESP32 sees them

1,084 stars137 forksCMIT

At a glance

What is it?
BojanJurca's ESP32 Oscilloscope turns an ESP32 into a signal viewer that serves its own web page, sampling digital and analog GPIOs and drawing them in a browser. It is a teaching tool with real limits: 736 samples per screen, a sampling rate the README says is not constant, and an ADC that goes away when WiFi is on.
Who is it for?
ESP32 Oscilloscope is worth an afternoon for anyone who wants to see what the pins of a board are actually doing, and it is not a substitute for a bench instrument or for a production logger. Before you commit to it, check which of your GPIOs sit on ADC1, because the ADC2 pins are unavailable while the WiFi radio is on, and read the oscilloscope.html that ships with the sketch, since you are expected to edit it to say which pins are digital and which are analog.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 143 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The web page and the sampler live on the same chip

The idea of this project is simple enough to state in one line: the ESP32 samples its own GPIOs and serves a web page that draws them. There is no serial terminal, no cloud service, and no companion application. Open a browser on the same network and you get the trace.

That design has a consequence worth naming. The thing doing the measuring and the thing doing the serving share one CPU, one set of RAM and one WiFi radio, so the picture on screen is the picture the chip itself sees. The README says it in plain words: the oscilloscope displays the samples as they are taken, which may not be exactly the signal as it is on its input GPIO.

The samples come in two flavours. Digital inputs are represented as the values 0 and 1. Analog inputs are represented as integers from 0 to 4095, which correspond to 0 V to 3.3 V. The 12-bit resolution is the ESP32's own ADC resolution, and the mapping is the one you would expect from the chip's datasheet rather than a calibrated measurement chain.

There is a live demo at jurca.dyn.ts.si/oscilloscope.html over both HTTP and HTTPS, and the repository ships a screenshot of the interface alongside the sketch.

736 samples per screen, and a rate that is not constant

The README is unusually honest about the limits of the measurement, and it deserves to be quoted rather than paraphrased. The oscilloscope takes up to 736 samples per screen, but the sampling rate may not be completely constant all the time, because other processes are running at the same time. The README adds the harder half of the statement: the ESP32 may also not always be able to keep up with the desired sampling frequency.

That is a real constraint on what the display means. A trace drawn from 736 irregularly spaced samples is a picture of a signal, but it is not a sampled reconstruction of a signal in the way a lab instrument gives you. The samples land when the scheduler lets them, so the horizontal axis is roughly time and the vertical axis is the input, but the timing has jitter that scales with what else the chip is doing. The README singles out the case where the oscilloscope is used as part of another project, where the surrounding work is exactly what competes for the CPU.

The consequence for a user is a rule of thumb: this is a tool for answering questions of the shape is this pin pulsing, is there a bit pattern here, is this analogue line drifting, rather than a tool for measuring a rise time or confirming a frequency to a tolerance. The project is explicit that you may modify oscilloscope.html to match your needs, which is where you decide which GPIOs are treated as digital inputs and which as analog inputs, so that the display makes sense for the signals you are monitoring.

ADC2 disappears the moment WiFi turns on

The most consequential hardware fact is in the README's final section, and it is the kind of thing that costs an afternoon if you do not know it.

The ESP32 has two SARs, Successive Approximation Registers, built in. ADC1 covers GPIOs 36, 37, 38, 39, 32, 33, 34 and 35 on the ESP32 board, with other boards such as the S2 and S3 connecting different GPIOs to ADC1. ADC2 covers GPIOs 4, 0, 2, 15, 13, 12, 14, 27, 25 and 26 on the same board. And here is the catch: ADC2 can perform analogReadings only when WiFi is not working. Since the oscilloscope uses WiFi, the ADC2 GPIOs are not available at this time.

So the practical set of usable analog inputs is the ADC1 list only, and it is shorter on other boards. The README is careful not to generalise across hardware, which is a point in its favour, since the S2 and S3 have different pin assignments to both converters. Anyone planning a measurement has to check the ADC1 assignment for their specific board, not just copy a pin list from the classic ESP32.

The second half of the section is about the digital side, which does not have this problem, and about how you tell the firmware which pins to treat as analog. That mapping lives in oscilloscope.html, which the README invites you to edit.

The setup is: edit the sketch, pick a partition scheme, then FTP three files over

Installation is a manual sequence rather than a package. The README lists the steps, and the essentials are the WiFi credentials, the file system choice and the upload of the web assets.

You copy the package into an Esp32_oscilloscope directory, open Esp32_oscilloscope.ino in the Arduino IDE, and replace YOUR-STA-SSID and YOUR-STA-PASSWORD in the Esp32_servers_config.h file with your own. You then select one of the SPIFFS partition schemas under Tools | Partition scheme, because the oscilloscope uses the LittleFS file system. Boards without a flash disk are handled by commenting out the line `#define FILE_SYSTEM FILE_SYSTEM_LITTLEFS`, and the sketch then stores oscilloscope.html in progmem instead of the file system.

The first compile and flash formats the flash disk with LittleFS, and the README warns that everything previously stored in the ESP32 flash memory will be lost at that point.

The web assets are then uploaded over FTP to the /var/www/html directory, with the command line utility or Windows Explorer, and the README says no user name or password is required:

bash
C:\esp32_oscilloscope>ftp YOUR-ESP32-IP
Connected to 10.0.0.3.
220-ESP32 FTP server - everyone is allowed to login
User (10.0.0.3:(none)):
331 enter password
Password:
230 logged on, use "/" to refer to your home directory "/"
ftp> put android-192-osc.png /var/www/html/android-192.png
226 /var/www/html/android-192-osc.png transfer complete
ftp> put apple-180-osc.png /var/www/html/apple-180.png
226 /var/www/html/apple-180-osc.png transfer complete
ftp> put oscilloscope.html /var/www/html/oscilloscope.html
226 /var/www/html/oscilloscope.html transfer complete

With that done, you open http://YOUR-ESP32-IP/oscilloscope.html in a browser and the trace appears. The three files are the favicons for Android and Apple and the page itself.

The HTTP server was moved out into a separate Arduino library

The structural change in the latest release is the removal of the HTTP server from this project. The README states that the new version no longer includes the HTTP server directly and instead depends on the separate Arduino library ESP32_Multitasking_Network_Suite, which can be installed through the Arduino IDE or downloaded from GitHub.

That split is the reason the dependency list looks like it does. Besides the network suite, the sketch draws on ThreadSafeFS, a thread safe file system wrapper for ESP32, and LightweightSTL, a lightweight standard template library for Arduino, both from the same author. If the HTTPS server is used, the list also includes WolfSSL through the Arduino-wolfSSL library. The repository tree itself is small, with Esp32_oscilloscope.ino, oscilloscope.h, server_config.h, an amber directory, an html directory and the screenshot.

The background explains the split. The oscilloscope was first meant as a demonstration of the capabilities of the author's larger Multitasking-Esp32-HTTP-FTP-Telnet-servers-for-Arduino project, and the README says it is still fully included there. The author judged it better off on its own, with only the functionality an oscilloscope needs. In other words, this repository is a focused example carved out of a larger multitasking framework, and the framework remains the place where the server side lives.

I2S mode buys a faster single channel and costs you the second channel

There is one hardware option in the setup that changes what you can measure, and it comes with an explicit trade-off in the README.

If the board supports the i2s interface, as the ESP32 DevKitC and NodeMCU-32S are named examples, you can choose to use it. The benefit is a higher sampling frequency and better quality on a single analog signal. The drawback is that you cannot use more than one analog oscilloscope channel at a time. That is a straight trade of parallelism for resolution, and it is the right choice when you are characterising one signal carefully and the wrong one when you need to compare two lines against each other.

Separately, the README explains an annoyance that looks like a hardware fault. Some ESP32 boards present inverse analog signals, and the fix is to comment or uncomment the compiler directives INVERT_ADC1_GET_RAW and INVERT_I2S_READ in oscilloscope.h, respectively. So the polarity of a channel is a compile-time decision rather than a runtime setting, and it is made in the header rather than in the web page, which is a slightly odd split given that the page is where you choose the pins.

Two decisions, then, live in code: which pins are analog and digital, and whether a channel is inverted. Both are made before the measurement rather than during it, and the README's advice is to edit oscilloscope.html so the display reflects the signals you are actually monitoring.

MIT licensed, released for IDF 5, and a small project with a long history

The licence is MIT, with the LICENSE file in the repository root, which lets you reuse the code as long as you keep the copyright notice.

The release history is short but tells a story about the platform rather than about the project. The tags are v2.04 from 2024-06-16 and v3.0.5, labelled For IDF 5, from 2026-05-21, and the last push to the repository was on 2026-06-02. The v3 line is the one that dropped the bundled HTTP server for the dependency on the network suite library, and the IDF 5 label ties it to a specific version of the Espressif toolchain. Anyone building this on a different ESP-IDF version should expect to adapt rather than to install.

The scale of the codebase is the other thing to keep in view. This is a sketch plus a header plus a configuration file, and the README states plainly that only the functionality an oscilloscope needs is used. That is a virtue when you want to read the whole thing, and a limit when you want features the author deliberately left out. There is no calibration, no trigger, no persistence and no measurement analysis, and the README does not document them. The project is a scope you drive, not a laboratory instrument you configure.

Editorial conclusion

ESP32 Oscilloscope is worth an afternoon for anyone who wants to see what the pins of a board are actually doing, and it is not a substitute for a bench instrument or for a production logger. Before you commit to it, check which of your GPIOs sit on ADC1, because the ADC2 pins are unavailable while the WiFi radio is on, and read the oscilloscope.html that ships with the sketch, since you are expected to edit it to say which pins are digital and which are analog. If your signal needs a stable, known sample rate, this project is the wrong instrument and the sampling jitter described in its own README is the reason.

Frequently asked questions

How do I set up the ESP32 Oscilloscope?

Copy the package into an Esp32_oscilloscope directory, open Esp32_oscilloscope.ino in the Arduino IDE, set YOUR-STA-SSID and YOUR-STA-PASSWORD in Esp32_servers_config.h, select a SPIFFS partition scheme, flash the board once to format LittleFS, then FTP the image files and oscilloscope.html into /var/www/html and open http://YOUR-ESP32-IP/oscilloscope.html.

How many samples does the ESP32 Oscilloscope show and what is the sampling rate?

The README states the oscilloscope takes up to 736 samples per screen, that the sampling rate may not be completely constant because other processes run at the same time, and that the ESP32 may not always keep up with the desired sampling frequency.

Why can I not use ADC2 pins on the ESP32 Oscilloscope?

The ESP32 has two SARs, and ADC2 can perform analogReadings only when WiFi is not working. Since the oscilloscope uses WiFi, the ADC2 GPIOs are not available, so analog inputs have to come from ADC1.

What is the benefit of using the i2s interface with the ESP32 Oscilloscope?

On boards that support it, such as the ESP32 DevKitC and NodeMCU-32S, the i2s interface gives a higher sampling frequency and better quality for a single analog signal. The drawback is that you cannot use more than one analog oscilloscope channel at a time.

What does the ESP32 Oscilloscope need to be built with?

It depends on the separate Arduino library ESP32_Multitasking_Network_Suite, since the HTTP server is no longer included directly, along with ThreadSafeFS, LightweightSTL, and WolfSSL if the HTTPS server is used. The most recent tag is v3.0.5, labelled For IDF 5.

Official sources

  1. BojanJurca/Esp32_oscilloscope on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bojanjurca-esp32-oscilloscope.svg)](https://hysenlabs.com/projects/bojanjurca-esp32-oscilloscope)

Was this useful?