r/esp32projects

Dual-Zone Peltier Cooler Controller (ESPHome / ESP32) - Architecture and Logic Review
▲ 12 r/esp32projects+2 crossposts

Dual-Zone Peltier Cooler Controller (ESPHome / ESP32) - Architecture and Logic Review

I am building a dual-zone Peltier wine fridge cooling controller using ESPHome on an ESP32. The system regulates two separate thermoelectric cooling (TEC) modules powered by a 13.0V to 14.4V Solar/LiFePO4 battery bank. A Shelly Gen4 unit handles the high-level power control to the main busbars, and the ESP32 receives dedicated power via a USB-C PD board. I am unfortunately at least 2x the cost to replace the darn thing, but I wanted to run the fridge natively on available DC instead of having the inverter run 24x7 to drive dedicated AC 220v controller boards - and one of the original controller boards was fried and driving the zone down to 2°C continously. The fridge was a gift from a good friend who suddenly passed away last January, so I'm defo keeping it...

The primary goal is independent or synchronized thermal management for two zones, using an OLED display and a physical rotary encoder for local management, paired with an MQTT integration into Home Assistant.

The core hardware configuration, current software design, and roadblocks are detailed below. AI disclosure - I have used Gemini to support coding based on my design and components available.

The Hardware Stack

  • Overall power 13.0-14.4v from LiFEPO4 system
  • Shelly Gen4 handling main power control to busbars
  • ESP32 Power supplied thru USBC PD board
  • ESP32 USBC 38-pin
  • 2x Monster Moto controllers, one for each TEC unit, actively cooled
  • 4x NTC thermistors on inside/outside of TEC plates, 10k pullups
  • 3x Dallas DS18B20 3-wire thermal sensor

Control and Actuation: The brains of the operation is a 38-pin ESP32 development board. Actuation is handled by two Monster Moto controllers (one per TEC module) that are actively cooled.

Power Delivery: The system is strictly configured for cooling only. Polarity switching is not planned. Because TEC modules do not tolerate raw high-frequency PWM well, a downstream low-pass filter consisting of a smoothing coil and a 6800uF capacitor is placed after the Moto controller outputs. The LEDC base frequency is configured to 10kHz.

Sensors: Thermal monitoring relies on two distinct sensor types. Four 10k NTC thermistors with 10k pullup resistors track the internal cold plates and the external warm-side heatsinks for both zones. Three Dallas DS18B20 1-wire sensors handle auxiliary monitoring: two sit directly under the Monster Moto MOSFET chips to monitor driver temperatures, and one monitors ambient air temperature under the chassis.

Logic, Safety Watchdogs, and UI State Machine

The firmware uses the ESPHome native PID climate platform to adjust the LEDC output level, capped at a maximum duty cycle of 80%. To filter out voltage noise on the analog lines, all NTC sensors use a median filter window.

Because a thermal runaway or a frozen controller can quickly destroy the components, the code enforces strict safety limits. The system drops into a hard `ERROR` state and cuts PWM duty cycles to 0% if the warm heatsinks exceed 60°C, the Moto drivers exceed 60°C, or an NTC sensor persistently (3 strikes concept) drops offline. There is also a runaway watchdog: if a zone calls for more than 70% power for 5 minutes straight without achieving at least a 2°C temperature drop, the system trips.

The physical interface uses an SH1106 1.3-inch OLED display driven by an internal state machine (`ui_state`). It manages the transitions between:

  1. NORMAL: Displays alternating zone metrics or synchronized statistics.
  2. SET_MODE: Toggles between independent zone control and `SYNC` mode.
  3. SET_TEMP_Z1 / SET_TEMP_Z2 / SET_TEMP_SYNC: Dedicated target temperature adjustment windows using a rotary encoder.

Problems Overcome and Dead Ends

Building this out highlighted several edge cases that required architectural revisions:

Persistent Boot Loops: Storing the system state in persistent global memory introduced a dangerous edge case. If the system crashed due to a critical hardware fault (like a disconnected NTC sensor), it would reboot, attempt to initialize the PID loop in the last known active state, immediately fault out, and restart again. This was resolved by intercepting the boot sequence using a custom `on_boot` lambda. If an `ERROR` flag is detected in flash memory, the standard initialization bypasses the operational loops entirely, keeping the PWM lines firmly locked at zero until a manual reset is triggered.

Circuit Protection Deficiencies: Early iterations exposed the vulnerability of the switching components to voltage spikes generated by inductive feedback. Inductive loads on the driver outputs required proper flyback protection. Implementing dedicated diode protection across the output paths resolved the risk of punching holes through the switching hardware.

Level Shifter Assumptions: Initial designs factored in hardware level shifters for the LEDC outputs to the driver boards. Bench testing proved that the ESP32 pins (GPIO4 and GPIO13) can trigger the logic gates cleanly without the added latency and complexity of unnecessary shifting components.

The Error State Trap: Once the watchdog tripped into an `ERROR` mode, the system locked down. Originally, clearing this required an MQTT command or a full power cycle. This was fixed by mapping a multi-purpose physical hardware escape route via the `Run Mode` button logic. If the system is bricked in an error state, a physical press acts as a diagnostic reset, clearing the global error code back to 0 and restoring `STANDBY` mode.

Current Status and Areas for Input

The MQTT reporting and remote target configurations work correctly for individual zones. The local display properly switches between languages and states based on user interaction arrays.

I am looking for feedback on a few areas:

  1. PID Tuning: The current tuning constants are `kp: 0.02`, `ki: 0.0005`, and `kd: 0.03`. Given the high thermal mass of the cooler chassis combined with the filtering lag of the low-pass LC network, what are the best practices for tuning ESPHome's PID component to minimize overshoot without causing cyclic hunting?
  2. State Machine Optimization: Managing five distinct UI states and dual-loop sync logic purely inside ESPHome lambdas is getting dense. Are there cleaner ways to structure conditional menus and button-hold actions without writing excessive inline C++ within the YAML file?
  3. Failsafe Operation: What other failsafe concepts can I add to ensure that the system can operate unattended for days, reporting back regularly to my Home Assistant system on health and overall operation. I am most concerned about thermal runaway and/or a fried component staying in the "on" state - hence using the multiple kill switches and Shelly Gen4 as a last resort.

Looking forward to hearing your thoughts or seeing similar control loops you have built. I can share the HA ESPHome YAML separately or DM if you are interested. Edit - formatting.

u/800ASKDANE — 9 hours ago
▲ 19 r/esp32projects+1 crossposts

OLED Display driver written for ESP32-C6 / C5 RISC-V LP Core 20MHz (ESP-IDF v6.0+)

I wanted to share a small project I’ve been working on. I couldn't find any ready-made solution to run an OLED screen completely off the LP Core (ULP) while the main HP core is in Deep Sleep, so I wrote a lightweight driver from scratch.

It currently supports three display variations (SSD1306 0.96", SSD1306 0.91", and SSD1312 1.09") using the same unified API.

Key Technical Details:

  • Framework: ESP-IDF v6.0+ (master)
  • Peripherals: Uses hardware LP_I2C (no bit-banging or assembly).
  • RAM Footprint: Total runtime consumption scales to ~6-8 KB (including framebuffer and stack), leaving about 50% of the 16 KB LP SRAM free.
  • Features: Basic graphics API (lines, rectangles, circles, capsules, fill) and 5x7 ASCII text engine with scaling.
  • Configuration: Auto pin-mapping for C6/C5 at compile-time. Switching between displays very easy.

Project on github: https://github.com/SODAVK/SSD1306_OLED_RISC-V_LP-Core

The library is entirely C-based with static allocation. I’m just leaving it here in case anyone is working on ultra-low-power devices or always-on remote sensors and needs something similar. Demo work on LP core C6 20Mhz, consumption ~500-700 µA per display + board together

u/SODAVK — 20 hours ago
▲ 45 r/esp32projects+2 crossposts

Yoshi’s Island on esp32 P4

First of all I apologize for my game play, I was recording the game with my phone and playing from an extreme angle so my reflection wouldn’t show. That’s my excuse.

I got Yoshi’s Island and Super Mario RPG both run on an esp32 P4/C6 board with a personally modified version of Retro-Go. Using a 7in Elecrow 1024x600 P4/C6 screen.

I got normal snes games running at full speed, added SA-1 support and some Super FX support. I can run Mario RPG at near full fps with no issues, so far testing is 100 playable but i haven’t made it past a few level ups. Yoshis island gameplay is near full FPS as well, when it gets bogged down in game it usually drops frames (looks choppier) but doesn’t lose game timing. The intro island is still a bit too heavy for it so it clearly slows down but so far the game is also 100% playable.

I also got starfox to load but it’s a mess at the moment.

u/Plenty_Candle_6161 — 1 day ago
▲ 198 r/esp32projects+8 crossposts

Wait..what !? 12 AI applications running entirely on a $5 ESP32. No cloud, no internet. Universal installer + Open source Github + Huggingface available. Test it yourself.

For years, edge AI has promised intelligence everywhere. In practice, most "edge AI" still means sending data to the cloud, relying on large Linux systems, or requiring expensive accelerator hardware.

SuperESP changes that.

Built on Atome LM v2, SuperESP transforms a standard ESP32 into a tiny AI appliance capable of running twelve practical applications entirely offline.

No GPUs.

No subscriptions.

No datacenter.

Just a microcontroller that costs less than a cup of coffee.

Every claim is verifiable and tied to a script.

What SuperESP Actually Is

SuperESP is not another chatbot squeezed onto a microcontroller.

It is a collection of specialized ternary AI models designed to classify events, patterns, behaviors, and anomalies directly on the device.

The current release includes:

Agriculture monitoring

Voice commands

Motion recognition

Gesture detection

Sound event classification

Machine anomaly detection

Air quality analysis

Energy monitoring

Occupancy estimation

Wearable activity tracking

Water leak detection

Predictive maintenance

It comes also with :

+ ESP32 OS

+ Universal Installer

Check out everything :

https://github.com/TilelliLab/atome-lm

u/themoroccanship — 2 days ago
▲ 149 r/esp32projects+1 crossposts

Fried my ESP32 S3

Well, as the title says, I tried to use 3.7v battery to my ESP and got it fried. The details are in the picture of both ESP and the battery. Can you guys please tell me what might be the mistake

u/Additional-Car-7059 — 2 days ago
▲ 26 r/esp32projects+3 crossposts

Made an open-source app that runs my Flipper and ESP32 gear from one dashboard

I go by LxveAce and everything I make is open source.

I got sick of every board on my bench needing its own flasher. The Flipper had qFlipper, my ESP32s had like five different web flashers, and none of it talked to anything else. So I built one app to run all of it, with the devices able to actually communicate. On the Flipper side it flashes the custom firmwares through qFlipper. The point is the Flipper stops being a silo. It's in the same dashboard as the ESP32 stuff, and you can pass targets and results between devices instead of them living in separate apps.

doesn't have to run on a laptop, either. There's a Pi build, so if you're putting a It Flipper into a cyberdeck or a portable rig, this can be the thing that actually runs the setup, and there's a web mode if you'd rather drive it from your phone.

There's also a standalone flasher and a headless version for screenless setups, plus some smaller bits. All open source.

Links:

- The app + downloads: https://cybercontroller.org

- Source: https://github.com/LxveAce/cyber-controller

- Discord: https://discord.gg/lxveace

u/DrinkPissWater — 1 day ago
▲ 4 r/esp32projects+1 crossposts

Will this esp32 based schematic work without burning down my house?

Currently working on my first esp32project but since i cant post on r/esp32 for some reason ill try my luck here.

The 4potis on the left controll the indiviual volumes of 4 tracks playing at the same time, the other 2controll panning and stereo, which gets an output to an Aux cable. Its supposed to be a very rudimentary audio mixer for an art exhibition.

What should i add or change?

Also i need the pinout double-checked because i dont have the time to order new components.

Any help would be greatly appreciated:)

u/Account_the_Seccond — 1 day ago
▲ 359 r/esp32projects+1 crossposts

I Built a Custom Game Boy from Scratch — Huge Project Update!

Howdy, members of this awesome community!

️All photos are in the comments due to Reddit’s post limitations

It’s been a while since my last post, where I shared the original concept and asked a couple of questions.

Today I’m back with a huge update on my UWU Game Boy project. Let’s jump right into it.

What’s this project about?

(Skip this part if you’ve seen my previous post.)

My goal is to build a portable game console that’s easy to customize, with completely custom firmware written from scratch by me.

What’s inside?

• ESP32-WROOM
• TP4056 charging module
• 1000mAh Li-Ion battery
• 7 tactile buttons
• KY-023 joystick
• 2.0” TFT display
• Passive buzzer

What’s the killer feature?

Unlike many DIY handheld projects that permanently stack multiple perfboards together, mine can be split into two separate modules simply by unscrewing a few nuts (check out one of the first photos).

The two halves reconnect using simple wire connectors, so I can easily take the console apart for upgrades, repairs, or modifications.
In other words, I wanted to solve the classic DIY problem of “once you solder everything together, you never want to touch it again”

What does the firmware do right now?

At the moment it’s mainly a hardware test.

As you can see in the videos, every button and joystick movement is detected and displayed on the screen in real time. The firmware also monitors and displays the current battery level.

Nothing fancy yet - but it’s a great milestone because all the hardware is finally working together

What’s planned for the firmware?

One thing I really want to avoid is turning this into a giant spaghetti-code nightmare.

My plan is to build a central system service that handles all hardware management, while games interact with a simple interface instead of dealing with the hardware themselves.

This service will be responsible for:
• Battery monitoring
• Making sure every component is working correctly
• Managing the main game loop
• Giving games access to hardware components
• Rendering notifications, pause menus, the main menu, and other system UI

Hopefully this will make developing games for the console much easier later on.

That’s everything for now!

I’d love to hear your thoughts, suggestions, or ideas for improving the project.

P.S. If you like what you see, an upvote would absolutely make my day. ❤️

And remember…

There is only one rule: DO NOT EVER ASK WHY IT’S CALLED “UWU GAME BOY”.

u/MichaelCelestial — 3 days ago
▲ 9 r/esp32projects+1 crossposts

SPIXWATCH - Hardware customization capable opensource smartwatch

I'm currently developing SPIXWATCH, an open-source smartwatch designed to be more than just another wearable. The idea is to make it a platform that developers, makers, and hardware enthusiasts can truly customize.

Current hardware:

- ESP32-S3

- 1.69" 240×280 capacitive touch display (ST7789)

- QMI8658C 6-axis IMU for motion and gesture recognition

- BLE 5.0

- 400 mAh battery with battery management

- Vibration motor

- Low-power firmware designed for long battery life

One feature I'm particularly excited about is hardware expansion through pogo pins. Instead of being locked into the hardware that's inside the watch, the pogo pin interface allows external modules to be attached. That means you could build and connect your own hardware—whether it's extra sensors, LoRa, NFC, GPS, environmental monitoring, biometric sensors, debugging tools, or something completely custom.

The software is also fully open source, so the goal is to let anyone create custom apps, watch faces, firmware modifications, and hardware modules without being restricted by a closed ecosystem.

I'm curious what the community would actually build with a platform like this.

If you had an open-source smartwatch with both firmware customization and hardware expansion through pogo pins, what would you use it for?

What modules would you design? What features would you add that current smartwatches don't offer? I'd love to hear practical ideas as well as the completely crazy ones—they might end up becoming part of SPIXWATCH. Look into www.spixinnov.com for more details

u/jinkhazama566 — 2 days ago
▲ 6 r/esp32projects+1 crossposts

ESP32-S3 TFT Feather + Adalogger Wing: SD Card initialization failing despite perfect soldering/formatting

Hi everyone, I am very new to microcontrollers. I really need help with the ESP32-S3 TFT Feather and the Adalogger Wing, because I'm hitting a wall with the SD card reader.

I'm building a project and using:

  • Adafruit ESP32-S3 TFT Feather (with the built-in screen)
  • Adalogger FeatherWing (RTC + MicroSD)
  • A 30GB Micro SD card

The Problem: My code consistently fails at SD.begin(). It cannot mount or initialize the SD card no matter what I try. The RTC on the Adalogger works perfectly, but the SD card side is completely dead.

What I've done/verified so far:

  • Soldering: I have the boards stacked and soldered together. I double-checked all my solder joints (especially MOSI, MISO, SCK, and CS on pin 10) and they are solid and clean.
  • Formatting: I confirmed the 30GB SD card is formatted to FAT32.
  • Libraries: I've tried using the standard #include <SD.h> library, and I've also tried the heavier SdFat library. Both fail to initialize.
  • Connections: The Adalogger Wing defaults to Pin 10 for Chip Select (CS), which is what I'm using in the code (SD.begin(10)).

Please help me.

u/SwitchStatus6293 — 1 day ago
▲ 4 r/esp32projects+1 crossposts

Wifi Radio Help

Hello cherished Arduino Community!

I'm currently working on an ESP32 D1 Mini powered internet radio and i'm stuck at a dead end. I've been following this tutorial https://projecthub.arduino.cc/zetro/diy-esp32-internet-radio-4353a4. I currently don't have a Wroom laying around, so i picked the D1 Mini. It is connecting to Wifi, but the radio stations aren't loading.

I'm positive the hardware connections are fine, so it must be a code-related issue. I also added a transformer to cancel out any noise that might be caused. I think the issue lays with the links to the stations?

It's my birthday and my only wish is to make this work. pls help

#include <WiFi.h>  // Include WiFi library for ESP32's WiFi functionality
#include <VS1053.h>  // Include library to control the VS1053 MP3 decoder
#include <U8g2lib.h>  // Include library for controlling the OLED display

// Define the VS1053 MP3 decoder pins
#define VS1053_CS     32  // Chip Select for VS1053
#define VS1053_DCS    33  // Data Command Select for VS1053
#define VS1053_DREQ   35  // Data Request pin for VS1053

// Button pins to switch between radio stations
#define BUTTON_NEXT  16  // Pin for the 'next station' button
#define BUTTON_PREV  17  // Pin for the 'previous station' button

// OLED Display setup with I2C communication
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Create OLED display object

// WiFi settings: replace with your own network credentials
const char *ssid = "removed for reddit";  // Your WiFi network name
const char *password = "removed for reddit";  // Your WiFi network password

// Radio station details
const char* stationNames[] = {"OE1", "Al Jazeera"};  // Array of station names
const char* stationHosts[] = {"audioapi.orf.at", "aljazeera.com"};  // Host URLs for the stations
const char* stationPaths[] = {"/oe1/json/4.0/broadcasts?_o=oe1.orf.at", "/audio/live/:1"};  // Paths to the radio streams
int currentStation = 0 ;  // Index of the currently playing station
const int totalStations = sizeof(stationNames) / sizeof(stationNames[0]);  // Calculate the number of available stations

// VS1053 MP3 player object
VS1053 player(VS1053_CS, VS1053_DCS, VS1053_DREQ);  // Create VS1053 object to control MP3 playback
WiFiClient client;  // WiFi client object to connect to the radio stream

// Variables for scrolling text on the OLED display
int textPosition = 128;  // Initial text position for scrolling
unsigned long previousMillis = 0;  // Store the last time the display was updated
const long interval = 50;  // Time interval for updating the display (50 ms)

void setup() {
    Serial.begin(115200);  // Start the serial monitor for debugging

    // Wait for VS1053 and PAM8403 amplifier to power up
    delay(3000);

    u8g2.begin();  // Initialize the OLED display
    u8g2.setFlipMode(1);  // Flip the display 180 degrees
    u8g2.setFont(u8g2_font_ncenB08_tr);  // Set font for OLED display

    // Display startup messages on OLED
    u8g2.clearBuffer();
    u8g2.drawStr(0, 16, "Starting Radio...");  // Initial message
    u8g2.sendBuffer();
    delay(2000);

    u8g2.clearBuffer();
    u8g2.drawStr(0, 16, "Starting Engine...");  // Second message
    u8g2.sendBuffer();
    delay(2000);

    u8g2.clearBuffer();
    u8g2.drawStr(0, 16, "Connecting to WiFi...");  // WiFi connection message
    u8g2.sendBuffer();

    Serial.println("\n\nSimple Radio Node WiFi Radio");  // Debug message in the serial monitor

    SPI.begin();  // Initialize SPI communication for VS1053

    player.begin();  // Start the VS1053 decoder
    if (player.getChipVersion() == 1.2 ) {  // Check for correct version of VS1053
        player.loadDefaultVs1053Patches();  // Load patches for MP3 decoding if needed
    }
    player.switchToMp3Mode();  // Switch VS1053 to MP3 decoding mode
    player.setVolume(100);  // Set the volume (range: 0-100)

    Serial.print("Connecting to SSID ");
    Serial.println(ssid);  // Debug message: attempting WiFi connection
    WiFi.begin(ssid, password);  // Start WiFi connection

    // Disable WiFi power saving mode for a more stable connection
    WiFi.setSleep(false);

    // Attempt to connect to WiFi with retries
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 20) {
        delay(500);
        Serial.print(".");  // Print dots to indicate connection progress
        attempts++;
    }

    // Check if WiFi connection is successful
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println("WiFi connected");
        Serial.println("IP address: ");
        Serial.println(WiFi.localIP());  // Print the assigned IP address

        // Display success message on OLED
        u8g2.clearBuffer();
        u8g2.drawStr(0, 16, "Connected Yay!");
        u8g2.sendBuffer();
        delay(2000);
    } else {
        // Display failure message on OLED if WiFi connection fails
        Serial.println("WiFi not connected");
        u8g2.clearBuffer();
        u8g2.drawStr(0, 16, "Not Connected");
        u8g2.sendBuffer();
        delay(2000);
    }

    // Initialize button pins with pull-up resistors
    pinMode(BUTTON_NEXT, INPUT_PULLUP);
    pinMode(BUTTON_PREV, INPUT_PULLUP);

    // Set font for displaying station names
    u8g2.setFont(u8g2_font_profont17_mr);

    displayStation();  // Display the initial station name on the OLED
    connectToHost();  // Connect to the radio station stream
}

void loop() {
    // Reconnect if the WiFi client is disconnected
    if (!client.connected()) {
        Serial.println("Reconnecting...");
        connectToHost();  // Attempt to reconnect to the stream
    }

    // Read data from the radio stream and send it to the VS1053 decoder for playback
    if (client.available() > 0) {
        uint8_t buffer[32];
        size_t bytesRead = client.readBytes(buffer, sizeof(buffer));  // Read data from stream
        player.playChunk(buffer, bytesRead);  // Play the received audio data
    }

    handleButtons();  // Check if buttons are pressed and switch stations accordingly
    scrollText();  // Scroll the station name on the OLED display
}

void connectToHost() {
    // Connect to the current radio station's server
    Serial.print("Connecting to ");
    Serial.println(stationHosts[currentStation]);

    if (!client.connect(stationHosts[currentStation], 80)) {
        Serial.println("Connection failed");  // Display error if connection fails
        return;
    }

    // Send HTTP request to the server to get the radio stream
    Serial.print("Requesting stream: ");
    Serial.println(stationPaths[currentStation]);

    client.print(String("GET ") + stationPaths[currentStation] + " HTTPS/1.1\r\n" +
                 "Host: " + stationHosts[currentStation] + "\r\n" +
                 "Connection: close\r\n\r\n");

    // Skip the HTTP headers in the response
    while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") {
            break;  // End of headers
        }
    }

    Serial.println("Headers received");  // Debug message: headers successfully received
}

void handleButtons() {
    static bool lastButtonNextState = HIGH;  // Track the previous state of the 'next' button
    static bool lastButtonPrevState = HIGH;  // Track the previous state of the 'previous' button

    bool currentButtonNextState = digitalRead(BUTTON_NEXT);  // Read current state of 'next' button
    bool currentButtonPrevState = digitalRead(BUTTON_PREV);  // Read current state of 'previous' button

    // If 'next' button is pressed (LOW), switch to the next station
    if (lastButtonNextState == HIGH && currentButtonNextState == LOW) {
        nextStation();
    }
    // If 'previous' button is pressed (LOW), switch to the previous station
    if (lastButtonPrevState == HIGH && currentButtonPrevState == LOW) {
        previousStation();
    }

    lastButtonNextState = currentButtonNextState;  // Update the last state for the 'next' button
    lastButtonPrevState = currentButtonPrevState;  // Update the last state for the 'previous' button
}

void nextStation() {
    currentStation = (currentStation + 1) % totalStations;  // Move to the next station (wrap around)
    displayStation();  // Update the OLED display with the new station name
    connectToHost();  // Connect to the new station
}

void previousStation() {
    currentStation = (currentStation - 1 + totalStations) % totalStations;
    displayStation();
    connectToHost();
}

void displayStation() {
    textPosition = 128;  // Reset text position to start from the right
    u8g2.clearBuffer();
    u8g2.drawLine(0, 0, 127, 0);
    u8g2.drawLine(0, 31, 127, 31);
    u8g2.setCursor(textPosition, 22);
    u8g2.print(stationNames[currentStation]);
    u8g2.sendBuffer();
}

void scrollText() {
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
        textPosition--;  // Move text to the left
        if (textPosition < -u8g2.getUTF8Width(stationNames[currentStation])) {
            textPosition = 128;  // Reset position to start from the right again
        }

        u8g2.clearBuffer();
        u8g2.drawLine(0, 0, 127, 0);
        u8g2.drawLine(0, 31, 127, 31);
        u8g2.setCursor(textPosition, 22);
        u8g2.print(stationNames[currentStation]);
        u8g2.sendBuffer();
    }
}
u/Unable_Candle_7132 — 2 days ago

I built a portable ESP32 voice assistant with real speech-to-text, AI replies, OLED emotions, and PCM audio output

Hi everyone! I’m working on a small DIY project called Oracle OS, a portable desk-buddy style voice assistant built around an ESP32.

The goal is to make a tiny assistant that feels alive: it can listen through a microphone, send the audio to a web backend, process it with AI, speak back through a speaker, and show expressions on a small OLED display.

The current setup uses:

  • ESP32-WROOM
  • 0.96 inch I2C OLED display
  • MAX4466 microphone module
  • PAM8403 amplifier
  • small 4 ohm speaker
  • push button for push-to-talk
  • WiFiManager for WiFi setup
  • Render-hosted FastAPI backend
  • AssemblyAI for speech-to-text
  • Groq / Llama model for AI replies
  • VoiceRSS for text-to-speech
  • PCM 8-bit audio streamed back to the ESP32
  • ESP32 DAC output on GPIO25

The hardest part so far was audio output. I tried MP3, WAV, SAM local speech, and several ESP32 audio libraries, but most of them produced buzzer-like noise through the PAM8403. The solution that finally worked was having the backend convert the TTS audio into raw 8-bit PCM and then streaming it directly to the ESP32, where I play it with dacWrite() through GPIO25.

Right now, the assistant can:

  • Record my voice while holding a button
  • Send the audio to the server
  • Transcribe speech
  • Generate a short AI answer
  • Display the answer on the OLED
  • Speak the answer through the speaker
  • Show animated eyes and expressions
  • Show a clock / desk buddy mode
  • Open a simple OLED menu
  • Run small games like Dino Jump and Reflex
  • Reset WiFi through the button at boot

It is still very much a prototype, but it finally works.

I’d love feedback from the community on:

  • Better ways to reduce audio noise from the ESP32 DAC into the PAM8403
  • Better filtering ideas using only basic components
  • Improving the OLED animations and “personality”
  • Making the menu system smoother with only one button
  • Making the backend faster and lighter
  • Whether I should move to ESP32-S3 with PSRAM later
  • Better enclosure ideas for a small desk companion

I’m trying to keep the project low-cost and build it mostly with parts I already have. Any advice, criticism, or ideas for future updates would help a lot.

I’ll keep updating the project as I improve the audio, animations, enclosure, and features.

Thanks!

reddit.com
u/Bandidoski14 — 3 days ago
▲ 101 r/esp32projects+5 crossposts

Built a $13.80 AR heads-up display that clips onto any glasses frame

Been working on this for a few months. AR glasses are either $700 or locked down. Wanted something open and cheap so I built one. I would really appreciate comments on your genuine feedback, don't worry criticism is also accepted!!!!

How it works:
ESP32-C3 drives a 0.42" OLED. A 90° prism redirects the light upward into a piece of teleprompter glass — the same semi-reflective glass used in TV studios. That overlays the image on your view of the world. Whole optical chain costs under $5.

Right now it can:
Turn-by-turn navigation arrows and notifications over BLE from your phone. Full day battery on a 500mAh LiPo. Clips onto any existing glasses frame.

BOM:
ESP32-C3 + OLED $6.90 , prism $1.50, teleprompter glass $0.90 , 3D printed housing $1.20maybe less, misc $1.50 = $13.80 total

https://preview.redd.it/zj431l0swoah1.png?width=340&format=png&auto=webp&s=63b906f2c7a847bbdfd872c0c1ceabd29edce829

Still testing daylight visibility — that's the biggest unsolved problem. Everything else works.

Putting firmware on GitHub under GPL v3 and hardware files under CERN OHL v2 later on, making it open source.

What would you build on top of this? And also, do you think it would be reasonable to spend approx 30-40 euros on this? Been thinking of making some money on the side, being a student, just want to get some feedback if there even is a market for this.

https://preview.redd.it/vcjpls7twoah1.png?width=426&format=png&auto=webp&s=38434ba213c6e4cb7149322204f16ed26ce88f66

reddit.com
u/Ok_Flower5151 — 4 days ago
▲ 2 r/esp32projects+1 crossposts

Made my first PCB! It's an esp32 board

I've just got my first board printed with jlcpcb. I've accidentally used a mixture of 0805 and 0603 components. Does anyone know where I can get the components cheap as ordering separately is expensive?

List of components:

1x esp32 chip (already got 1)

1x usb-c female connector

1x ams 1117

1x ch340c

4x 0803 led

1x shottsky diode

A couple of 0803 and 0603 capacitors and resistors.

Any help would be greatly appreciated as I'm on a really tight budget as a student.

reddit.com
u/RolledSteelJoist — 3 days ago
▲ 11 r/esp32projects+1 crossposts

Looking for an ESP32/Embedded Engineer to build an IoT prototype

Hi everyone, I'm a software developer but completely new to embedded systems and electronics. As a hobby project, I'm trying to build my first IoT device and I'm looking for someone experienced with ESP32 to help me bring it to life. The prototype will roughly include: ESP32 4G SIM module GPS Temperature sensor Accelerometer Magnetic door sensor Small camera (event-based images) Battery-powered operation The firmware should: Read sensor data Send data to my backend API Trigger alerts based on events (motion, door opening, temperature, etc.) Capture an image during important events Be reasonably power efficient I'll provide all the hardware/components required. My budget is around ₹10,000, which I know isn't a huge amount, so I'm hoping to find someone who's interested in embedded systems and would enjoy working on an interesting project. If the scope needs to be adjusted to fit the budget, I'm happy to discuss that. If you're interested, please DM me with: Your experience with ESP32 or embedded systems Any previous projects (GitHub, photos, videos, etc.) Where you're based Your preferred framework (ESP-IDF, Arduino, MicroPython, etc.) I'm also happy to learn throughout the process rather than just handing everything off, so if you enjoy explaining things as we build, that's a huge plus. Thanks!

reddit.com
u/Gloomy_Team8580 — 4 days ago
▲ 13 r/esp32projects+2 crossposts

Built a lightweight HAL framework for ESP32/Arduino to make embedded dev a bit less painful — just open sourced it (Beta)

Hey everyone,

I've been building embedded projects on ESP32 for a while now, and kept rewriting the same boilerplate for pin control, non-blocking delays, and communication setup across projects. So I built a HAL framework called AERL.h to clean that up, and just open sourced the beta.

A few things it does:

  • Non-blocking pin control — AERL.glow(pin, duration), AERL.flash(pin, duration) instead of manually juggling millis() timers everywhere
  • Clear separation between non-blocking and blocking delay (AERL.delay() vs AERL.bcdelay())
  • Simple UART/I2C/SPI activation and send/receive wrappers
  • Basic sleep/wake handling for power management
  • Beginner-friendly compile-time error messages (e.g. it'll tell you clearly if you pass a String where it expects a number)

It's genuinely beta — I've flagged a few known issues (sleep can be flaky on some boards, WiFi/BLE support is coming in about a week), and I'd rather be upfront about that than oversell it.

MIT licensed, built on top of Arduino.h. If anyone's interested in trying it out, breaking it, or has feedback on the API design, I'd genuinely appreciate it — this is exactly the stage where outside eyes catch things I can't see anymore.

GitHub: https://github.com/AERL-Official/AERL-C-Framework#

Thanks for reading, and happy to answer any questions about the design decisions.

u/progrm-1122 — 5 days ago
▲ 2 r/esp32projects+2 crossposts

HOW TO INTERGRATE THE SH1107 SPI OLED SCREEN TO THE XIAOZHI AI

I am working on an ESP32-S3 project using Xiaozhi AI. By default, the system is designed to support an I2C OLED display. However, I modified the project to use a 1.5-inch SPI SH1107 OLED instead of the default I2C display.

I have already updated parts of the code to support SPI, and the project builds successfully without errors. The AI system itself is working correctly — it boots up and I can interact with it through voice conversation as expected.

However, the OLED display is not working. The screen remains blank and does not show any output even though the system is running normally.

Help Needed

I need help with:

  • Proper configuration for using an SPI SH1107 OLED instead of the default I2C OLED
  • Identifying what I may have missed in the display driver or initialization code
  • Ensuring the display output is correctly mapped and initialized in Xiaozhi AI
  • Any working reference or example for SPI OLED integration with this system
u/Opposite-Spread1442 — 5 days ago