ESP32: Device Dashboard


This tutorial demonstrates how Mongoose Library can be used to implement a device dashboard on an ESP32. The full source code is at

This tutorial is a hardware example following on the device dashboard tutorial. You should read and follow that tutorial first.

Project structure

This example uses the ESP-IDF 4.x/5.x toolchain, and therefore the project structure follows a standard ESP-IDF CMake-based format:

  • main/ - a "main" component directory which includes application code
    • main/CMakeLists - a standard ESP-IDF component-level project CMake file
    • main/main.c - main application file, contains Mongoose logic
    • main/wifi.c - contains Wifi setup routine, wifi_init()
    • main/mongoose.c - a symlink to repo's mongose.c
    • main/mongoose.h - a symlink to repo's mongose.h
    • main/net.c - a symlink to the common code for this example, net.c
    • main/packed_fs.c - a symlink to the packed filesystem in the common code section, containing the web files to be served, packed_fs.c
  • CMakeLists - a standard ESP-IDF top-level project CMake file
  • partitions.csv - defines a partition table for a 4MB board
  • sdkconfig.defaults - default build values
  • Makefile - mainly invokes Docker to call the IDF utilities

In production code, all project files should be copied to the main/ directory instead of creating symlinks.

Build the project

Before building the project, open the main/main.c file and edit your WiFi network name and WiFi password settings:

The next step is to build the project. It is assumed you're using Linux or Mac as a workstation, you have Docker installed, and your user is able to run it. If in doubt, check

$ docker ps

Start a terminal in the project directory; clone the Mongoose Library repo, and run the make build command:

$ git clone
$ cd mongoose/examples/esp32/device-dashboard
$ make build

In order to flash this recently built firmware to your ESP32 board, plug it in a USB port and execute (change /dev/ttyUSB0 to the actual serial port on your system):

$ make flash PORT=/dev/ttyUSB0

You can also download and unzip esputil, in that case run make flash2 PORT=/dev/ttyUSB0. When done, connect to the serial console. You can use a serial port application like minicom or you can also use esputil, just run esputil -p /dev/ttyUSB0 monitor.

Now start a browser on http://IP_ADDRESS where IP_ADDRESS is the board's IP address printed on the serial console. You should see a login screen.

From here on, please go to the device dashboard tutorial and repeat some of the steps depicted there

Main function

The main() function has three blocks:

  1. Mount a filesystem and write a sample file
  2. Initialise WiFi
  3. Run Mongoose

Mount filesystem

The firmware that has been built does not have a filesystem image flashed, but it has SPIFFS filesystem support. So the following piece of code initialises a filesystem, and writes a file hello.txt using the mg_file_printf() API call.

For this example we've chosen to embed all the web files in a packed filesystem, more information on the embedded filesystem tutorial

Initialise wifi

There we call a wifi_init() function which is defined in main/wifi.c. That is a blocking function, i.e. it does not return until the board gets an IP address:

Run Mongoose

Next goes Mongoose. Note that it should be run after network initialisation is complete - which is true in our case. The logic is standard - initialise the event manager, start a listener on port 80, and fall into an infinite event loop:

We have covered those aspects that are specific to the ESP implementation, for the details on the application and the UI, please see the device dashboard tutorial.

Using SPIFFS to store web files

In case we'd like to hold our web files on a partition using the SPIFFS filesystem, here is an example on how to do it.

This event handler function shows a RESTful handler with the /api/state URI, which reports the amount of free RAM. Other URIs are treated as static server requests:

There is a caveat there - we redefine FS handler. This is done because SPIFFS is a flat file system without directory support. Therefore we create our own filesystem which is derived from a standard POSIX FS but has a stat() function redefined - it returns a "directory" flag for /: