This project implements a resource-oriented energy analysis methodology for the Espressif ESP32 microcontroller platform. It provides fine-grained tracing of task execution and resource states to estimate per-task and per-resource energy consumption, enabling developers to identify energy hotspots and optimize IoT firmware for battery-powered deployments.
Traditional energy measurement techniques capture only the total system power. This project extends the analysis by attributing energy consumption to specific software tasks and hardware resources.
The methodology includes:
- Firmware instrumentation for tracing task and resource state changes.
- Protobuf-based message encoding for efficient trace collection.
- Python-based unpacking and modeling tools for energy estimation.
- Grafana dashboards for visualization of power, energy, and resource usage.
ESP32-Energy-Analysis/
├── firmware/ # ESP32 firmware components
│ ├── trace_task/ # Task-level tracing macros and logic
│ ├── trace_resource/ # Resource-level tracing instrumentation
│ ├── ssd1306/ # OLED driver (extended for substate tracing)
│ └── CMakeLists.txt
├── protobuf/ # TraceMessage definitions and generated files
│ └── tracemessage.proto
├── host/ # Host-side scripts for unpacking and visualization
│ └── unpack.py
├── docs/ # Documentation, diagrams, and thesis materials
├── ESP-Tracing.json # Grafana dashboard for visualization
└── README.md # You are here
To reproduce and use the energy analysis workflow, the following software must be installed:
-
Place the following folders under your ESP-IDF project’s
components/directory:trace_resource/ trace_task/ protobuf/ ssd1306/ -
In all source files where resource tracing is required, include:
#include "trace_resource.h"
-
Modify FreeRTOS to enable task-switch tracing:
#ifdef CONFIG_ENERGY_TRACING #include "energy_trace_macros.h" #endif
Insert the above into:
<esp_installation_directory>/components/freertos/tasks.c -
Enable tracing in
menuconfig:- Set
APPTRACE_DEST_JTAG = "JTAG" - Enable
ENERGY_TRACING
- Set
Use the function trace_resource() at each resource state transition:
esp_err_t trace_resource(Resource resource, State state, char *substate);Enumerations:
typedef enum _Resource {
RESOURCE__BH1750 = 0,
RESOURCE__DHT11 = 1,
RESOURCE__LED_EXTERN = 2,
RESOURCE__GPS = 3,
RESOURCE__OLED = 4,
RESOURCE__ULTRASONIC = 5,
RESOURCE__RELAY = 6,
RESOURCE__LORA = 7,
RESOURCE__WIFI = 8,
RESOURCE__NVS = 9,
RESOURCE__ESP32 = 10,
RESOURCE__ESP32_CORE0 = 11,
RESOURCE__ESP32_CORE1 = 12
} Resource;
typedef enum _State {
STATE__UNINITIALIZED = 0,
STATE__INITIALIZING = 1,
STATE__IDLE = 2,
STATE__RUNNING = 3,
STATE__SLEEP = 4,
STATE__ERR = 5
} State;Example:
trace_resource(RESOURCE__DHT11, STATE__RUNNING, "");
esp_err_t ret = dht_read_float_data(CAPS_DHT_TYPE, CAPS_DHT_GPIO, &humidity, &temperature);To ensure complete trace coverage from boot:
while (trace_resource(RESOURCE__ESP32, STATE__RUNNING, "") != ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(50));
}Connect your ESP32 board and ESP-PROG via JTAG according to Espressif’s schematic. Both devices should be connected to your PC via USB.
-
Open terminal 1: Flash and run the firmware:
idf.py -p /dev/ttyUSB0 flash openocd monitor
-
Open terminal 2: Connect to the target via Telnet:
telnet localhost 4444
-
Start trace collection:
esp apptrace start file://trace/trace.log 0 -1 -1 0 0
-
Stop trace collection:
esp apptrace stop
-
Set up InfluxDB and Grafana Follow installation guides:
-
Import Grafana dashboard
- Navigate to Dashboards → Import
- Upload
ESP-Tracing.json
-
Configure Python script
- In
host/unpack.py, edit line 12 to include your InfluxDB credentials.
- In
-
Run unpacking and upload
python3 host/unpack.py trace.log
-
Visualize results Adjust Grafana’s time window to match your trace timestamps (near Unix epoch).
Trace messages are defined in Protocol Buffers:
message TraceMessage {
required Resource resource = 1;
required State state = 2;
required string task = 3;
required uint64 timestamp = 4;
required string substate = 5;
}Each message describes which task set which resource to which state, with an optional substate.
Messages are sent via esp_apptrace_write() and flushed with esp_apptrace_flush() for JTAG communication.
Grafana displays:
- Total system power over time
- Per-task inclusive energy breakdown
- State timelines for tasks and resources (OLED, Wi-Fi, etc.)
- Correlations between program actions and power spikes
The ssd1306 component has been extended to support pixel-based substate tracing.
It overrides the standard pixel-writing methods to count illuminated pixels and report them for energy attribution.