← SHEET 02 · ASSEMBLIES EL-001

ESP32 Desk Buddy

ELEMBEDDED
LIVE DRAWING — HOVER OR DRAG TO CRANK · BUILT FROM THE REAL PLANT PARAMETERS
PART NOEL-001
MATL / SYSTEMESP32 · SSD1306 OLED · DHT22 · PIR
TOOLSArduino IDE · Wokwi · C++

A small desk-mounted companion built around an ESP32: it watches for you sitting down, greets you with an animated face on a 128x64 OLED, tracks temperature and humidity, and chirps a reminder if you’ve been sitting too long. WiFi/NTP gives it a live clock when a network is available and falls back to an uptime counter when it isn’t. The whole thing is one non-blocking millis() scheduler — five peripherals, five GPIOs, no delay() in the main loop.

OVERVIEW & MOTIVATION

Most desk-gadget builds either block on delay() calls (freezing sensor reads while an animation plays) or hard-fail the moment WiFi drops. This one is built the other way round from the start: every subsystem — display, DHT22, PIR, buzzer, WiFi/NTP — is serviced from its own millis()-based timer inside a single cooperative loop, and the clock view degrades gracefully to an uptime counter instead of hanging or blanking when the network is unreachable. The behavior target: react to presence within half a second, read environment data on a slow 5 s cadence appropriate for a DHT22, and nag (gently) after 45 minutes of continuous sitting.

COMPONENTS & BOM

REFCOMPONENTSPECROLE
U1ESP32 DevKit-C V4dual-core, WiFi/BT, 3.3 V logicmain controller, runs the scheduler
U2SSD1306 OLED128×64, I2C, addr 0x3Cface / clock / env display
U3DHT22 (AM2302)±0.5 °C, ±2 %RH, 1-wire digitaltemperature + humidity
U4PIR motion sensorHC-SR501-style, digital active-HIGHpresence detection
BZ1Passive buzzerpiezo, PWM/tone-drivenchirps and alert tones
R110 kΩ resistorpull-upDHT22 data-line pull-up to 3V3

WIRING

ESP32 DEVKIT-C V4 SSD1306 OLED 128x64 · I2C 0x3C DHT22 TEMP / HUMIDITY BUZZER PASSIVE PIR MOTION HC-SR501-STYLE 3V3 GND D22 D21 3V3 D4 GND D26 GND 5V GND D27 VCC GND SCL SDA VCC DATA GND + - VCC GND OUT I2C bus shared, addr 0x3C tone()-driven, no series R needed OUT is 3.3V-logic-safe; VCC per module (5V or 3V3)
ESP32 PINNETPERIPHERAL PIN
3V33V3 RAILOLED VCC, DHT22 VCC
GNDGND RAILOLED GND, DHT22 GND, PIR GND, BUZZER −
GPIO21I2C_SDAOLED SDA
GPIO22I2C_SCLOLED SCL
GPIO4DHT_DATADHT22 DATA (10 kΩ pull-up to 3V3)
5V5V RAILPIR VCC
GPIO27PIR_OUTPIR OUT
GPIO26BUZZER_DRVBUZZER +

FIRMWARE

sketch.ino runs one cooperative loop: serviceWifi(), serviceDht(), servicePir(), serviceStateMachine(), serviceBuzzer(), and renderUi() each check their own millis() timer and return immediately if it isn’t their turn — nothing in loop() blocks. The UI is a small state machine (STATE_IDLE, STATE_GREET, STATE_REMINDER) driven by PIR presence and a sit-timer, and the buzzer runs its own step sequencer so multi-tone alert patterns don’t need delay() either:

void servicePir(unsigned long now) {
  bool raw = digitalRead(PIN_PIR) == HIGH;
  if (raw != rawPirLast) { rawPirLast = raw; pirLastChangeAt = now; }

  if (now - pirLastChangeAt >= PIR_DEBOUNCE_MS && raw != presence) {
    presence = raw;
    if (presence) {
      sitStartMs = now;
      breakArmed = true;
      if (uiState == STATE_IDLE) enterState(STATE_GREET, now);
    } else {
      sitStartMs = 0;
      breakArmed = false;
    }
  }
}
void serviceBuzzer(unsigned long now) {
  if (!buzzerBusy) return;
  if ((long)(now - buzzerNextAt) < 0) return;
  if (buzzerStep >= buzzerSeqLen) { buzzerBusy = false; return; }
  const ToneStep& s = buzzerSeq[buzzerStep];
  tone(PIN_BUZZER, s.freq, s.durationMs);
  buzzerNextAt = now + s.durationMs + s.gapAfterMs;
  buzzerStep++;
}

The idle view alternates between the face and a clock/temperature/humidity screen every 6 s (IDLE_VIEW_CYCLE_MS). Presence rising-edge triggers STATE_GREET for 4 s with a single chirp; 45 continuous minutes of presence (BREAK_REMINDER_MS) triggers STATE_REMINDER for 6 s with a three-tone chirp pattern, then the sit-timer restarts so it repeats if you’re still there. DHT22 is polled every 5 s (DHT_INTERVAL_MS) and the last good reading is held on a failed read rather than blanking the display.

SIMULATION

The project runs end-to-end in Wokwi against diagram.json — no real hardware involved yet. What the sim shows: the OLED boots to the idle face with blinking eyes, clicking the PIR sensor’s sense control in the part inspector fires the greet chirp and swaps to the “HI!” face for 4 s, and the idle view cycles to a clock/temp/humidity screen every 6 s (falling back to an uptime counter if WIFI_SSID is left blank, since Wokwi’s simulated ESP32 does have real internet access to NTP if credentials are filled in). To run it: open wokwi.com, start a new ESP32 project, paste sketch.ino and diagram.json in over the defaults, and press Play. All five Wokwi part types used (board-esp32-devkit-c-v4, wokwi-ssd1306, wokwi-dht22, wokwi-pir-motion-sensor, wokwi-buzzer) are real parts — no substitutions were needed for this build.

STATUS

Design and firmware are complete and self-consistent (pinout matches across sketch.ino, diagram.json, and this page); the circuit has been exercised in the Wokwi simulator only. No physical hardware has been assembled — no bench measurements, no real DHT22/PIR timing numbers, no photos. Everything above is a design value (pin assignment, polling interval, debounce window, reminder interval) or an expected simulator behavior, not a measured result. Next step: order the BOM parts and bring up the same firmware on real hardware unchanged.

USE CASES & APPLICATIONS

Desk/workstation presence-aware assistants — posture and break reminders for long work sessions, ambient room-condition readout (temp/humidity) without a phone app, and a friendly idle-face status indicator for a home office. The same non-blocking scheduler pattern (millis-timed subsystem services, no delay() in loop()) generalizes to any small ESP32 project mixing a display, a slow analog/digital sensor, an interrupt-ish digital input, and audio feedback — smart mirrors, plant monitors, doorbell-style greeters.

FILES

  • sources/electronics/desk-buddy/sketch.ino — full ESP32 Arduino firmware: non-blocking scheduler, OLED UI state machine, DHT22/PIR/buzzer/WiFi services.
  • sources/electronics/desk-buddy/diagram.json — Wokwi wiring diagram, pinout matches the firmware exactly.
  • sources/electronics/desk-buddy/README.md — how to run the Wokwi sim, library list, and real-hardware build notes.

← BACK TO ASSEMBLIES

NAME ODILBEK MARIMOV
DWG NO. PF-2026
SHEET 01 / 07
DISCIPLINE ROBOTICS / MECHATRONICS
SCALE 1:1
REV A
THIRD-ANGLE PROJECTION
DATE 2026-07-11
UNITS mm