SmallOLED-PCMonitor

Keralots活跃维护

用 ESP32-C3 加小 OLED 屏做桌面硬件监控,配套 Windows/Linux 程序实时推送 CPU、GPU、内存和磁盘占用,电脑休眠时自动切换 12 种复古动画时钟。

ESP32-C3 + OLED desk monitor: live CPU/GPU/RAM/disk stats from a Windows/Linux companion app, and 12 animated retro clock styles when the PC sleeps.

v1.9.0发布于 2026-10-31 16:12 UTC267star45fork同步于 2026-11-10 12:03 UTC

怎么上手

由 README 提炼,执行前请确认
Windows:下载 pc_stats_monitor_v4.exe 双击运行;Linux:cd PC-Companion-App-v4/linux-companion && python3 -m pip install -r requirements.txt && python3 pc_stats_monitor_v4_linux.py
硬件要求按 README 说明

需要 ESP32-C3 SuperMini 开发板,以及 I2C OLED 屏(支持 SSD1306 0.96"、SH1106 1.3"、SSD1309 2.42"、CH1116 1.54");README 未提及显存或 GPU 要求,PC 端仅需运行伴生程序。

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

用 ESP32-C3 加小 OLED 屏做桌面硬件监控,实时显示 PC 的 CPU、GPU、内存和磁盘数据

用 ESP32-C3 加小 OLED 屏做桌面硬件监控,配套 Windows/Linux 程序实时推送 CPU、GPU、内存和磁盘占用,电脑休眠时自动切换 12 种复古动画时钟。

核心能力

  • 配套 Windows/Linux 伴生程序通过 UDP 推送传感器数据
  • PC 休眠时切换为 12 种动画复古时钟样式
  • 支持音频可视化,显示频谱柱或示波器
  • OLED 上可玩 6 款小游戏,用 Xbox 手柄蓝牙操控
  • 浏览器 Web Flasher 刷固件并推送 WiFi 凭据,无需装工具

容易踩的坑

Windows 上要显示温度、风扇、GPU 和功耗,需先以管理员身份运行 LibreHardwareMonitor;LibreHardwareMonitor 0.9.5+ 的 WMI 后端已损坏,必须勾选 Web server 选项走 REST API;部分廉价 ESP32-C3 板存在硬件级 WiFi 问题,且 GPIO 8 上的板载 RGB LED 无法用软件关闭。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.9.0
  1. v1.9.0最新正式版2026-10-31 · 2026-10-31 16:12 UTC

    Download Instructions

    Make sure you download the correct version for your screen size!

    Use CaseFile to Download
    New device (first time flashing)firmware-v1.9.0-OLED_0.96inch.bin, firmware-v1.9.0-OLED_1.3inch.bin or firmware-v1.9.0-OLED_1.54inch.bin
    Existing device (OTA update via web interface)OTA_ONLY_firmware-v1.9.0-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.9.0-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.9.0-OLED_1.54inch.bin
    New ESP32-S3 devicefirmware-v1.9.0-ESP32-S3-OLED_0.96inch.bin, firmware-v1.9.0-ESP32-S3-OLED_1.3inch.bin or firmware-v1.9.0-ESP32-S3-OLED_1.54inch.bin
    Existing ESP32-S3 deviceOTA_ONLY_firmware-v1.9.0-ESP32-S3-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.9.0-ESP32-S3-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.9.0-ESP32-S3-OLED_1.54inch.bin

    0.96" SSD1306 and 2.42" SSD1309 share the 0.96inch image. 1.3" SH1106 and 1.54" CH1116 each have their own image - do not mix them up. ESP32-S3 boards (SuperMini or any S3 with 4MB+ flash) take the ESP32-S3 images only; the wiring is the same as on the C3.

    PC companion app

    No changes since v1.7.0. pc_stats_monitor_v4.exe is attached to this release as well. Linux users run it from source: PC-Companion-App-v4/linux-companion/.

    You can also flash directly from your browser (no tools to install): https://smalloled.stolaris.dev/

    Older devices need one USB re-flash. Devices still on the original partition layout (first flashed before v1.5.1 and only updated over the air since) cannot take this build over OTA. Export your config, re-flash once with the browser flasher, then import the backup.

    v1.9.0 - Changelog

    New

    • Weather clock. Current conditions from Open-Meteo (free, no account or API key): an animated icon (sun, moon and stars, drifting clouds, rain, snow, fog, lightning, gusts when it is windy), the temperature, today's high and low, humidity and sunrise/sunset. Five layouts: classic, or current weather next to the next three days (as rows or columns), a 12-hour temperature curve with rain chances, or tomorrow in focus. Find your city on the web page, Celsius or Fahrenheit. It can also join the clock rotation.
    • Update notice. When a newer release is out, the web page shows a badge in the top bar, and the Maintenance page names the update file that matches your board and display.

    Fixes

    • Settings could be changed from other websites. A page open in your browser could make it send a save, factory reset or firmware upload to the device. These requests now need a header that only the device's own page sends. If you update or save settings from your own scripts, add -H "X-SmallOLED: 1" (for example curl -H "X-SmallOLED: 1" -F "[email protected]" http://smalloled.local/update). The PC companion app is not affected.
    • Clock rotation cut animations short. With "Cycle All Styles", a minute change that started near the end of a clock's turn was cut off, most visibly on Snake, Tetris and Dino when the hour changed. The rotation now waits for the animation to finish.
    • Brisbane and Darwin jumped an hour in October. Queensland and the Northern Territory do not use daylight saving time, but the only matching regions (Sydney, Adelaide) do. Both now have their own region without it, and the timezone list is sorted by UTC offset.
  2. v1.8.02026-10-02 · 2026-10-02 22:34 UTC
    查看更新说明

    Download Instructions

    Make sure you download the correct version for your screen size!

    Use CaseFile to Download
    New device (first time flashing)firmware-v1.8.0-OLED_0.96inch.bin, firmware-v1.8.0-OLED_1.3inch.bin or firmware-v1.8.0-OLED_1.54inch.bin
    Existing device (OTA update via web interface)OTA_ONLY_firmware-v1.8.0-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.8.0-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.8.0-OLED_1.54inch.bin
    New ESP32-S3 devicefirmware-v1.8.0-ESP32-S3-OLED_0.96inch.bin, firmware-v1.8.0-ESP32-S3-OLED_1.3inch.bin or firmware-v1.8.0-ESP32-S3-OLED_1.54inch.bin
    Existing ESP32-S3 deviceOTA_ONLY_firmware-v1.8.0-ESP32-S3-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.8.0-ESP32-S3-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.8.0-ESP32-S3-OLED_1.54inch.bin

    0.96" SSD1306 and 2.42" SSD1309 share the 0.96inch image. 1.3" SH1106 and 1.54" CH1116 each have their own image - do not mix them up. ESP32-S3 boards (SuperMini or any S3 with 4MB+ flash) take the ESP32-S3 images only; the wiring is the same as on the C3.

    PC companion app

    No changes since v1.7.0 - keep using pc_stats_monitor_v4.exe from the v1.7.0 release. Linux users run it from source: PC-Companion-App-v4/linux-companion/.

    You can also flash directly from your browser (no tools to install): https://smalloled.stolaris.dev/

    Older devices need one USB re-flash. Devices still on the original partition layout (first flashed before v1.5.1 and only updated over the air since) cannot take this build over OTA. Export your config, re-flash once with the browser flasher, then import the backup.

    v1.8.0 - Changelog

    New

    • Game mode. Pair an Xbox Wireless Controller over Bluetooth and play six games on the OLED: Falling Blocks, Snake, Bricks, Space Rocks, Runner and Defenders. High scores are saved. Start it from the web page ("Game mode") or with a triple tap on the touch button. The controller needs a recent firmware (BLE capable, update it with the Xbox Accessories app).
    • Game of Life clock. A Conway colony lives around the digits; a changed digit dissolves into the colony and the survivors form the new one.
    • Dragon Ball clock. Goku trains, spars and fights visitors, then blasts the changed digit with a Kamehameha.
    • Custom clock rotation. "Cycle All Styles" is now your own list: pick the clocks, their order and how long each one stays.
    • Configurable touch pin. The touch button GPIO is now a setting, no reflash needed.
    • LED control over HTTP. The night light can be switched and dimmed through the API.
    • ESP32-S3 support. Separate S3 images for every display, also in the browser flasher. Same wiring as the C3.

    Fixes

    • Tap also toggled the LED. A quick tap on the touch button could switch the night light on top of its normal action.
    • Metric layout wiped on save. Saving or importing settings before the PC sent any data reset positions, companions and progress bars.
    • Wrong display type reported. The web page header and /api/info always said SSD1306, whatever panel was fitted.
    • Animated clocks stuck on an old minute. Switching back from the stats screen or the visualizer near the end of a minute could leave the clock counting from the wrong time.
  3. v1.7.02026-09-09 · 2026-09-09 17:04 UTC
    查看更新说明

    Download Instructions

    Make sure you download the correct version for your screen size!

    Use CaseFile to Download
    New device (first time flashing)firmware-v1.7.0-OLED_0.96inch.bin, firmware-v1.7.0-OLED_1.3inch.bin or firmware-v1.7.0-OLED_1.54inch.bin
    Existing device (OTA update via web interface)OTA_ONLY_firmware-v1.7.0-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.7.0-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.7.0-OLED_1.54inch.bin

    0.96" SSD1306 and 2.42" SSD1309 share the 0.96inch image. 1.3" SH1106 and 1.54" CH1116 each have their own image - do not mix them up.

    PC companion app

    pc_stats_monitor_v4.exe (Windows) is attached to this release - download and double-click it, no Python needed. It sends your PC's sensors to the device and gives you a web-style config window (1:1 OLED preview, drag-and-drop layout, sensor picker) that lives in the system tray. Linux users run the same app from source, no build step: PC-Companion-App-v4/linux-companion/.

    Full setup guide - LibreHardwareMonitor, sensor picking, autostart and troubleshooting: win-companion README.

    Update the app together with the firmware this time - the audio visualizer needs the new companion to send the sound data.

    First run: the exe is unsigned, so Windows SmartScreen may show "Windows protected your PC". Click More info -> Run anyway. This is normal for small unsigned tools and not a sign of anything wrong with the download.

    You can also flash directly from your browser (no tools to install): https://keralots.github.io/SmallOLED-PCMonitor/

    Older devices need one USB re-flash. This build no longer fits the app slot on devices still using the original partition layout - that means anything flashed for the first time before v1.5.1 and updated only over the air ever since. The OTA update will refuse it with a size error. Export your config from the Maintenance page, re-flash once with the browser flasher (this updates the storage layout for you), then import your backup. OTA updates work normally from then on. Devices flashed with the browser flasher at v1.5.1 or later are already on the newer layout and are not affected.

    v1.7.0 - Changelog

    New

    • Audio visualizer. The device now reacts to whatever your PC is playing. The companion app captures the sound coming out of your speakers and streams it over. Three styles: Classic EQ, Mirror EQ (bars growing from the centre) and an Oscilloscope trace, with solid / segmented / outline bars, optional peak-hold dots and an optional corner clock. It steps aside for the clock when the room goes quiet and comes straight back when sound returns. Turn it on in the companion app's Audio page.
    • TRON clock. A new clock face inspired by the light-cycle arena, side-profile or overhead bike, with the arena grid and border each switchable.
    • Custom NTP servers. Point the clock at your router or a local time source instead of the public pools. A Test button probes each server and reports them individually. Leave a field blank to keep the default.
    • The stats port is now a setting. The UDP port the device listens on (4210) used to be baked into the firmware - if something on your network already used it, you had to edit the source and reflash. It is now a normal setting, applied without a reboot.
    • Linux load average. The Linux companion can send the 1-minute load average as a metric. Thanks to @taintedkernel (#62).

    Fixes

    • Setup WiFi network invisible on some ESP32-C3 clones (#61). Cheap "SuperMini" clone boards ship with a mis-tuned antenna and a weak regulator that can
  4. v1.6.32026-08-15 · 2026-08-15 13:51 UTC
    查看更新说明

    Download Instructions

    Make sure you download the correct version for your screen size!

    Use CaseFile to Download
    New device (first time flashing)firmware-v1.6.3-OLED_0.96inch.bin, firmware-v1.6.3-OLED_1.3inch.bin or firmware-v1.6.3-OLED_1.54inch.bin
    Existing device (OTA update via web interface)OTA_ONLY_firmware-v1.6.3-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.6.3-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.6.3-OLED_1.54inch.bin

    0.96" SSD1306 and 2.42" SSD1309 share the 0.96inch image. 1.3" SH1106 and 1.54" CH1116 each have their own image - do not mix them up.

    PC companion app

    pc_stats_monitor_v4.exe (Windows) is attached to this release - download and double-click it, no Python needed. It sends your PC's sensors to the device and gives you a web-style config window (1:1 OLED preview, drag-and-drop layout, sensor picker) that lives in the system tray. Linux users run the same app from source: PC-Companion-App-v4/linux-companion/.

    Full setup guide - LibreHardwareMonitor, sensor picking, autostart and troubleshooting: win-companion README.

    First run: the exe is unsigned, so Windows SmartScreen may show "Windows protected your PC". Click More info -> Run anyway. This is normal for small unsigned tools and not a sign of anything wrong with the download.

    The companion app is versioned separately from the firmware; this exe is the current build and works with any 1.6.x device.

    You can also flash directly from your browser (no tools to install): https://keralots.github.io/SmallOLED-PCMonitor/

    Heads up for older devices: the firmware has grown and is now close to the OTA size limit on devices still using the original partition layout. If an OTA update ever fails with a "size" or "no space" error, export your config from the Maintenance page, re-flash once with the browser flasher (this updates the storage layout automatically), then import your backup. After that, OTA updates work normally again.

    v1.6.3 - Changelog

    New

    • Half-hour and quarter-hour timezones: added the regions that sit on :30 and :45 UTC offsets and were previously missing from the list - UTC+3:30, UTC+4:30 (Kabul), UTC+5:45 (Kathmandu), UTC+6:30 (Yangon) and UTC-3:30 (Newfoundland). If your region uses a half-hour offset and you couldn't find it before, it's in the list now.
    • Timezone list shows the UTC offset: every entry in the Timezone dropdown is now prefixed with its offset, e.g. (UTC+03:30) ..., so you can locate your zone by number instead of hunting through country names.

    Fixes

    • Night-time wake-up: a single bad clock reading could briefly pull the panel out of scheduled night mode and light it up. One glitchy reading no longer wakes the display at night.
  5. v1.6.22026-08-05 · 2026-08-05 16:49 UTC
    查看更新说明

    Download Instructions

    Make sure you download the correct version for your screen size!

    Use CaseFile to Download
    New device (first time flashing)firmware-v1.6.2-OLED_0.96inch.bin, firmware-v1.6.2-OLED_1.3inch.bin or firmware-v1.6.2-OLED_1.54inch.bin
    Existing device (OTA update via web interface)OTA_ONLY_firmware-v1.6.2-OLED_0.96inch.bin, OTA_ONLY_firmware-v1.6.2-OLED_1.3inch.bin or OTA_ONLY_firmware-v1.6.2-OLED_1.54inch.bin

    0.96" SSD1306 and 2.42" SSD1309 share the 0.96inch image. 1.3" SH1106 and 1.54" CH1116 each have their own image - do not mix them up.

    PC companion app

    pc_stats_monitor_v4.exe (Windows) is attached to this release - download and double-click it, no Python needed. It sends your PC's sensors to the device and gives you a web-style config window (1:1 OLED preview, drag-and-drop layout, sensor picker) that lives in the system tray. Linux users run the same app from source: PC-Companion-App-v4/linux-companion/.

    Full setup guide - LibreHardwareMonitor, sensor picking, autostart and troubleshooting: win-companion README.

    First run: the exe is unsigned, so Windows SmartScreen may show "Windows protected your PC". Click More info -> Run anyway. This is normal for small unsigned tools and not a sign of anything wrong with the download.

    The companion app is versioned separately from the firmware; this exe is the current build and works with any 1.6.x device.

    You can also flash directly from your browser (no tools to install): https://keralots.github.io/SmallOLED-PCMonitor/

    Heads up for older devices: the firmware has grown and is now close to the OTA size limit on devices still using the original partition layout. If an OTA update ever fails with a "size" or "no space" error, export your config from the Maintenance page, re-flash once with the browser flasher (this updates the storage layout automatically), then import your backup. After that, OTA updates work normally again.

    v1.6.2 - Changelog

    Fixes

    • Scheduled night mode at boot: if the device restarted during its scheduled dim hours, the panel used to light up at full brightness for up to a minute before correcting itself. It now applies the dimming schedule immediately at boot, and skips the 5-second boot IP screen when the schedule wants the panel dark - so a restart in the middle of the night no longer lights up the room.
    • Cycle All Styles clock: when the clock rotated to the next style every 5 minutes it switched the instant the block changed, clipping the outgoing minute-change animation every time. The switch now waits a few seconds for the animation to finish before moving on.

    Internal

    • Pinned the build platform to [email protected] (arduino-esp32 2.0.17) so the firmware builds reliably regardless of which ESP32 platform version happens to be installed.
    • Fixed a follow-up to the boot dimming change where the schedule check could briefly stall the main loop (laggy web UI, dropped touch presses, frozen frames) when WiFi was connected but the time had not synced yet.
    • /api/status now reports the display's actual on/off state - scheduled dimming could drive the panel to 0 while the status still claimed it was on.
    • /api/info now includes resetReason, so an unexplained restart can be traced after the fact.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    PC Stats Monitor - ESP32 OLED Display

    Youtube Video

    3D Printable case: 0.96": https://makerworld.com/en/models/2051935

    1.3": https://makerworld.com/en/models/2185211

    2.42" https://makerworld.com/en/models/2341351

    Be aware that there are different sizes of the same SSD1306 (0.96") OLED screen on aliexpress. Im using this one "Original" version (do not purchase dual color, it won't work): It seems that there is also "New" screen version which comes in another 2 sizes. So be sure to pick correct 3D printable case from link above. https://aliexpress.com/item/1005006262908701.html

    For 1.3" OLED (SH1106) I have used this version: https://aliexpress.com/item/1005009757205826.html

    For 2.42" OLED (SSD1309) I have used this version: https://aliexpress.com/item/4000002579405.html

    For 1.54" OLED (CH1116) I have used this version: https://aliexpress.com/item/1005006579037427.html

    ESP32-C3 SuperMini: https://aliexpress.com/item/1005008988143743.html

    HOW TO Video assembly (you can ignore LED if you are not going to use it):

    Version with LED based on 2n2222: https://www.youtube.com/watch?v=umV7xA0mp5I

    Version with LED based on LDO6AJSA https://www.youtube.com/watch?v=M2Oa4PDUUgE

    I have noticed that some of the cheap ESP32-C3 boards have WiFi related issues on hardware level. After some additional implementations to the code in attempt to fix issues (v1.2.1), some of those issues cannot be fixed as they are on hardware level. What has helped a bit: Soldering 2 pins to the side of antenna. Check video assembly where I'm sixing that issue. Some of those faulty boards have antenna too close to other components. Like in this example (left side with 3.5mm gap is better)

    Note: Some ESP32-C3 SuperMini boards (especially the external antenna variant) have a very bright built-in RGB LED (WS2812) on GPIO 8. Since GPIO 8 is used for I2C SDA, this LED cannot be turned off via software. If it bothers you, desolder the LED or cut its data trace on the PCB.

    A real-time PC monitoring system that displays CPU, RAM, GPU, and disk stats on a small OLED screen using ESP32 and a companion Python script.

    Custom PCB, sponsored by PCBWay

    There is now a 27 x 27 mm carrier PCB that holds the ESP32-C3 SuperMini, the OLED header and the optional filament LED driver on one board, instead of wiring it by hand. PCBWay sponsored this project and manufactured the boards, SMT assembly included, shown below and in the assembly video.

    Finished SmallOLED builds next to unpopulated carrier PCBs

    Features

    • Dual Display Modes:
      • PC Online: Real-time stats with customizable metrics and positions
      • PC Offline: Animated clock (Mario, Space Invaders, Arkanoid, Pac-Man, Snake, Tetris, Asteroids, Dino Runner, TRON, Game of Life, Dragon Ball, Weather, Standard, or Large styles, plus a Cycle All mode)
    • Audio Visualizer: Live spectrum bars or an oscilloscope driven by whatever your PC is playing, streamed by the companion app
    • Game Mode: Six small games on the OLED (Falling Blocks, Snake, Bricks, Space Rocks, Runner, Defenders), played with an Xbox Wireless Controller over Bluetooth LE
    • PC Companion App (v4, Windows + Linux):
      • Web-style config window that mirrors the device portal 1:1
      • Live 1:1 OLED preview with drag-and-drop layout
      • Sensor picker with live values, up to 20 metrics
      • Custom labels (max 10 characters), number formats, quick templates
      • Optional audio visualizer stream, with auto-switch when music starts
      • Runs in a native window + system tray; Start with Windows autostart
      • Windows prebuilt exe (no Python) or Linux from source
    • Web Configuration Portal: Customize all settings via browser
      • 5-row (spacious) or 6-row (compact) display modes
      • Large 2-row and 3-row modes for readability at a distance
      • Progress bars for visual representation
      • Clock styles and animation settings
      • Automatic timezone with DST support (56 regions)
      • Display brightness control and scheduled night dimming
      • Export/Import configuration
      • OTA firmware updates
    • Browser Web Flasher (Preferred): Install firmware and push WiFi credentials entirely from the browser over USB - no tools to install
    • WiFi Portal: Easy first-time setup without code changes (fallback / build-from-source path)
    • mDNS Discovery: Access your device via http://smalloled.local (configurable name)
    • Optimized Performance: Minimal CPU usage on PC (<1%)
    • Persistent Settings: All preferences saved to ESP32 flash memory

    Quick Start for Beginners

    Never done this before? Here's the simple version:

    1. Flash ESP32 - Open the SmallOLED Web Flasher in desktop Chrome or Edge, pick your OLED, and click Install (no installation needed!)
    2. Connect ESP32 to WiFi - Right after flashing, use the flasher's Configure WiFi step to send your network to the device over USB. (No web flasher? Join the "PCMonitor-Setup" network and open 192.168.4.1.)
    3. Install LibreHardwareMonitor (Windows only) - Download from GitHub, run as Admin (needed for temps/fans/GPU/power)
    4. Get the companion app (v4 - recommended on both Windows and Linux):
      • Windows (easiest): download pc_stats_monitor_v4.exe from the latest release and double-click it - no Python needed. v4 gives a polished web-style config window (1:1 device preview, drag-and-drop layout, sensor picker, number formats, quick templates) that lives in the system tray. On the first run Windows SmartScreen may say "Windows protected your PC" - the exe is unsigned, so click More info -> Run anyway. This is normal for small unsigned tools.
      • Linux: cd PC-Companion-App-v4/linux-companion, then python3 -m pip install -r requirements.txt and python3 pc_stats_monitor_v4_linux.py (no build step). Same UI; opens a native window or your browser.
    5. Configure in GUI - Enter ESP32 IP address, select the sensors you want, click "Save & Start"
    6. Position metrics - use the app's Layout & preview page, or open the ESP32 IP in a browser and drag metrics on the device's own preview

    Done! Your PC stats will now appear on the OLED display.

    For detailed instructions, keep reading below.

    Hardware Requirements

    ESP32 Setup

    • ESP32-C3 Super Mini or ESP32-S3 Super Mini (or any ESP32-C3 / ESP32-S3 board with 4MB+ flash). The S3 has its own firmware images, but the wiring below is identical for both chips.
    • OLED Display (128x64, I2C):
      • SSD1306 0.96" (most common)
      • SH1106 1.3" (larger, recommended)
      • CH1116 1.54" (SH1106-compatible, own firmware)
      • SSD1309 2.42" (largest, uses same firmware as 0.96")
    • TTP223 Touch Sensor (optional - for physical button control)
    • Wiring (I2C):
      • SDA → GPIO 8
      • SCL → GPIO 9
      • VCC → 3.3V
      • GND → GND
      • TTP223 Signal → GPIO 7 (optional)
      • LED Transistor Base or LDO6AJSA PWM → GPIO 1 (optional)

    Wiring

    Touch Button (Optional)

    Wiring for optional filament led and TTP223 sensor

    This wiring is for 2.42" OLED. Use the same firmware as for 0.96" OLED for flashing. No need to change firmware, TTP223 and LED will work.

    If you are using 2N2222 and resistors for led here is the wiring:

    If you are using LDO6AJSA here is the wiring:

    The firmware supports an optional TTP223 capacitive touch sensor for physical control of the display and LED night light:

    Button Gestures:

    GestureDurationAction
    Quick tap< 500msPC online: Toggle metrics/clock. PC offline: Cycle clock styles. In game mode: leave it
    Triple tap3 quick tapsStart game mode
    Medium press500ms-1s, releaseToggle LED night light on/off
    Long hold> 1s, keep holdingRamp LED brightness up (if off) or down (if on). Release to keep.

    Taps are counted until 350ms after the last release, so a single tap acts with that short delay.

    Hardware Setup:

    • Connect TTP223 signal pin to GPIO 7
    • Power the TTP223 with 3.3V and GND

    Configuration (in src/config/user_config.h):

    #define TOUCH_BUTTON_ENABLED 1      // 1 = enabled, 0 = disabled
    #define TOUCH_BUTTON_PIN 7          // GPIO pin (default: 7)
    #define TOUCH_DEBOUNCE_MS 50       // Debounce delay (default: 100ms)
    #define TOUCH_ACTIVE_LEVEL HIGH     // HIGH for TTP223 (active HIGH)
    

    Software Setup

    1. ESP32 Firmware

    Option A: SmallOLED Web Flasher (Preferred - No Installation Needed)

    A dedicated browser flasher that picks the right firmware for your OLED, installs it over USB, and then hands your WiFi to the device in the same tab. No separate flashing tool and no captive portal needed.

    1. Open the SmallOLED Web Flasher in desktop Chrome or Edge (Web Serial is required, so Firefox, Safari and mobile won't work).
    2. Connect your ESP32-C3 or ESP32-S3 via USB. If it constantly connects/disconnects, hold the BOOT button, connect to USB while still holding it, then release after connecting. Alternatively, hold BOOT, press RESET while holding BOOT, then release both buttons.
    3. Pick your OLED (0.96" SSD1306, 1.3" SH1106, 1.54" CH1116, or 2.42" SSD1309) from the ESP32-C3 or ESP32-S3 group, matching your board, and click Install. It erases and writes the full image at 0x0 in ~30 seconds.
    4. When the install finishes, use the Configure WiFi step to send your home network to the device over USB. If you miss it, join the PCMonitor-Setup hotspot and open 192.168.4.1 instead.
    5. The device reboots, joins your WiFi, and shows its IP address on the OLED.

    The same page has a built-in serial monitor (section 04) for grabbing boot logs if you ever need them for a bug report.

    Option B: Manual Pre-built Binary (Optional)

    Prefer to flash the raw binary with your own tool? Download it from the latest release and flash the full image at 0x0.

    Download the latest release: grab the full image for your OLED size from the Releases tab.

    Generic web flasher (esptool-js):

    1. Visit ESP Web Flasher
    2. Connect your ESP32-C3 or ESP32-S3 via USB (use the BOOT/RESET trick above if it won't stay connected).
    3. Click "Connect" and select your port
    4. Click "Choose File" and select the full image for your display, e.g. firmware-<version>-OLED_0.96inch.bin
    5. Make sure you pick firmware for correct OLED size version! It may initially work but you will get black screen after you reconnect device. ESP32-S3 boards need the ESP32-S3 images, e.g. firmware-<version>-ESP32-S3-OLED_0.96inch.bin.
    6. Set Flash Address to 0x0
    7. Click "Program" and wait ~30 seconds
    8. Done! Then set up WiFi via the PCMonitor-Setup hotspot (see below).

    Other methods:

    • Windows: Run flash.bat and follow prompts
    • Linux/Mac: Run ./flash.sh and follow prompts
    • Manual: esptool.py --chip esp32c3 --port COM3 --baud 460800 write_flash 0x0 firmware-<version>-OLED_0.96inch.bin
    • Manual (ESP32-S3): esptool.py --chip esp32s3 --port COM3 --baud 460800 write_flash 0x0 firmware-<version>-ESP32-S3-OLED_0.96inch.bin
    Option C: Build from Source

    Prerequisites:

    Installation:

    1. Clone this repository
    2. Open the project in PlatformIO
    3. Connect your ESP32 via USB
    4. Build and upload:
      pio run --target upload
      
    First-Time WiFi Setup

    Flashed with the SmallOLED Web Flasher (Option A)? You can skip this - set WiFi from the browser's Configure WiFi step right after flashing. The access-point method below is the fallback, and the path when you build from source.

    1. After uploading, the ESP32 will create a WiFi access point
    2. Connect to the network: PCMonitor-Setup
    3. Open your browser to 192.168.4.1
    4. Configure your WiFi credentials
    5. The ESP32 will connect and display its IP address on the OLED
    Web Configuration Portal

    Once connected to WiFi, access the full configuration page:

    1. Open a browser and navigate to the ESP32's IP address (shown on OLED) or http://smalloled.local

    ESP32 Web Portal - Clock Settings

    1. Clock Settings:

      • Idle clock style (Mario, Space Invaders, Arkanoid, Pac-Man, Snake, Tetris, Asteroids, Dino Runner, TRON, Game of Life, Dragon Ball, Weather, Standard, or Large, plus a Cycle All mode)
      • Time format (12/24 hour)
      • Date format (DD/MM/YYYY, MM/DD/YYYY, or YYYY-MM-DD)
    2. Display Layout:

      • Choose between 5-row (spacious, 13px) or 6-row (compact, 10px) modes
      • Large 2-row and 3-row modes for double-size text
      • Enable progress bars for visual representation
      • Row 6 positions automatically hidden in 5-row mode
    3. Timezone:

      • Select your region from 56 timezone presets
      • Automatic DST transitions (no manual toggle needed)
    4. Visible metrics (custom labels & placement):

      • Give each metric a custom label (max 10 chars) shown on the OLED - e.g. relabel a pump RPM sensor as "PUMP", "FAN" or "COOLER"
      • Drag a metric chip onto the live OLED preview (or tap a chip then a slot) to place it
      • Pair two metrics on one row and add progress bars
      • Labels can also be set from the companion app
    5. Configuration:

      • Export configuration to JSON file (backup)
      • Import configuration from JSON file (restore)
      • Reset to factory defaults

    2. PC Stats Sender

    Recommended (v4, Windows + Linux): the v4 companion gives a web-style config window that mirrors the device portal 1:1 - live OLED preview, drag-and-drop layout, sensor picker, number formats, quick templates, pull/push and backup - all from the desktop, hosted in a native window + system tray.

    Installing Python (only if you run from source)

    The Windows exe bundles its own Python, so skip this unless you run the app from source (always the case on Linux). For Windows download e.g. this version Check both checkboxes on installation screen (to use admin rights and add python.exe to PATH)

    At the end of installation, if asked to remove characters limit for path, agree on it.

    Installing LibreHardwareMonitor
    1. Download from LibreHardwareMonitor
    2. Extract and run LibreHardwareMonitor.exe as Administrator
    3. Windows defender may block it from running. This is false/positive, just add it to exception.
    4. Check following options. First 4 from the top:

    For version 0.9.5 and above check Web server option: lhw-webserver

    LibreHardwareMonitor 0.9.5+ broke its WMI backend. The companion app detects that and falls back to the REST API, which is what the Web server option above serves - so on 0.9.5+ that option is not optional.

    Set up the companion app

    The recommended v4 companion (Windows exe or Linux from source, see above) opens its config window automatically and also lives in the system tray - right-click the tray icon to reopen it or quit.

    System tray icon

    Step 1: Launch the app

    Windows: double-click pc_stats_monitor_v4.exe. First run may trip Windows SmartScreen (unsigned exe): More info -> Run anyway.

    Linux:

    cd PC-Companion-App-v4/linux-companion
    python3 -m pip install -r requirements.txt
    python3 pc_stats_monitor_v4_linux.py
    
    Step 2: Connect to your ESP32

    Companion app - connection

    On the Connection page:

    1. Enter the ESP32 IP Address - shown on the OLED at boot.
    2. UDP Port (default 4210) and Update Interval (default 3s) - leave unless you changed them.
    3. Sensor source - leave on Auto (prefers the REST API, falls back to WMI). Only force a mode if you have a reason to.
    4. Click Test connection to confirm the device answers, then Save connection.
    5. Autostart (optional). On Windows, tick Start with Windows - saved instantly, launches minimized to the tray at login (per-user, no admin) and waits 10s for LibreHardwareMonitor to come up first. On Linux, python3 pc_stats_monitor_v4_linux.py --autostart enable installs a smalloled-companion.service systemd user unit (--autostart disable removes it).
    Step 3: Pick the sensors to display

    Companion app - sensor picker

    On the Sensors page:

    1. Make sure LibreHardwareMonitor is running (Windows) for temps, fans, GPU and power - CPU / RAM / Disk work out of the box. In Auto source mode the app reads LibreHardwareMonitor over its REST API and falls back to WMI, so 0.9.5+ (with broken WMI) works fine.
    2. Browse the categories: System, Temperatures, Fans, Loads, Clocks, Power, Network Data, Network Throughput. Hit Rescan sensors if something is missing.
    3. Live current values are shown next to each sensor so you can identify them.
    4. Tick the sensors you want - up to 20 metrics.
    5. Give any sensor a Custom label (max 10 chars) to show on the OLED - e.g. relabel a pump RPM sensor "PUMP". Leave empty for the auto name.
    6. Click Save & push to device. The Layout & preview page then lets you drag each metric onto a 1:1 OLED preview.
    Step 4: Position Metrics on ESP32 Display

    Companion app - layout and preview

    After the companion app starts sending data (arrange metrics in its Layout & preview page, or in the device's own web portal as below):

    1. Open your ESP32's IP address in a web browser
    2. Open the Visible metrics page
    3. You'll see all metrics received from your PC as draggable chips under a live OLED preview
    4. Drag a chip onto a slot (or tap a chip then a slot) to place it; optionally pair it with a companion metric. E.g. "CPU: 10% 40C" > shows usage and temperature of CPU.
    5. Use progress bars for visual representation (optional)
    6. Choose between 5-row (more spacing), 6-row (compact) or the large 2/3-row display modes on the Display layout page

    TIP: Start with 1-2 metrics initially and slowly build entire layout.

    ESP32 Web Portal - Visible metrics

    The display will update in real-time as you arrange metrics!

    Usage

    Normal Operation

    1. ESP32 should be powered and connected to WiFi
    2. LibreHardwareMonitor must be running on your PC
    3. Companion app should be running

    The OLED will display:

    • PC Online: Real-time stats (CPU, RAM, GPU temp, disk, fan speed)
    • PC Offline: Animated clock (choose from 11 styles in the web portal, or a Cycle All mode that rotates through them)

    Display Modes

    When PC is Online (receiving stats):

    There are four stats layouts, switchable in the web portal under Display layout. All of them take custom labels, paired companion metrics and progress bars. Each clip below runs the same workload cycle - idle, load, cool down - so you can compare them.

    5-row stats layout5 rows - 13px spacing, positions 0-9. The default, and the easiest to read.6-row stats layout6 rows - 10px spacing, positions 0-11. One more row of metrics.
    Large 3-row stats layoutLarge 3 rows - double-size text, single column, 3 metrics.Large 2-row stats layoutLarge 2 rows - double-size text, 2 metrics, readable across a room.
    • Real-time monitoring display with customizable labels
    • Shows CPU usage/temp, RAM usage, GPU temp, Disk usage, Fan/Pump speed
    • Progress bars for visual representation
    • The 5-row mode drops to 11px spacing when the clock is centered, to keep all five rows on screen
    • Automatically switches when PC sends data

    When PC is Offline (idle mode):

    Every clock below is captured at the 09:59 -> 10:00 rollover, the busiest case, since all four digits change at once.

    Mario ClockMarioSpace Invaders ClockSpace InvadersArkanoid ClockArkanoid
    Pac-Man ClockPac-ManSnake ClockSnakeTetris ClockTetris
    Asteroids ClockAsteroidsDino Runner ClockDino RunnerTRON ClockTRON
    Game of Life ClockGame of LifeDragon Ball ClockDragon BallStandard ClockStandard
    Large ClockLargeWeather ClockWeather
    • Mario Clock: Animated pixel Mario that jumps to "hit" digits when time changes
    • Space Invaders Clock: Invader/ship shoots lasers to change digits
    • Arkanoid Clock: Breakout-style ball physics destroy and rebuild digits
    • Pac-Man Clock: Pac-Man eats pellet-based digits
    • Snake Clock: A Nokia-style snake roams the screen chasing food and steering around the digits and its own body. On each minute change the changed digits crumble into pellets that the snake hunts down one by one before the new digit drops in. Optional arena border and date row.
    • Tetris Clock: Block-grid digits sit low on the screen with the occasional tumbling tetromino. On each minute change the changed digits are rebuilt one at a time, either as drop-in slabs or as falling dots. Optional date row at the top or bottom.
    • Asteroids Clock: A wireframe vector clock - the ship drifts with inertia and splits tumbling rocks while idle, then aims at and shoots each changed digit into spinning line shards at the minute change. Optional date row.
    • Dino Runner Clock: A Chrome T-Rex homage - the dino runs and auto-jumps cacti over a scrolling ground with parallax clouds; at the minute change a pterodactyl swoops in, carries off the old digit, and the new one drops in from above. Optional clouds and date row.
    • TRON Clock: Two light cycles duel around the digits, leaving trails behind them (one solid, one dotted, so you can tell them apart). At the minute change one cycle is dispatched to retrace the changed digit stroke by stroke. Optional arena grid and border, and a choice of side-profile or overhead bike sprite.
    • Game of Life Clock: Conway's Game of Life runs around the digits. At the minute change the old digit dissolves into the colony, evolves for a moment, and the surviving cells fly back together into the new digit, which then fires off a glider. Long-lived cells erode and fresh gliders keep arriving, so nothing burns in. Adjustable speed and density, optional date row, and a small-clock mode (top, centre or bottom) that leaves most of the screen to the colony.
    • Weather Clock: Current conditions from Open-Meteo (free, no account or API key). Five layouts: classic (clock, animated icon - sun and moon with stars, drifting clouds, rain, snow, fog, lightning, gusts when it is windy - temperature, and today's high/low and humidity alternating with sunrise/sunset), or current weather on the left with a forecast on the right: three days as rows, three days as columns, a 12-hour temperature curve over rain chances, or tomorrow in focus. Same layouts as on AnimatedPixelClock. Find your city in the web settings (the lookup runs in your browser), Celsius or Fahrenheit. The device fetches every 10 minutes, only while the clock is on screen or in the rotation.
    • Dragon Ball Clock: Goku lives on the ground below the time - he walks, runs kata, spars with his afterimage, rides the Flying Nimbus, collects Dragon Balls (seven summon Shenron) and now and then fights a visiting Vegeta or Piccolo. At the minute change he fires a Kamehameha that eats the old digit from below; when three or four digits change he goes Super Saiyan, the old digits crumble and lightning strikes in the new ones. Idle tricks can be switched off, leaving him to just walk.
    • Standard Clock: Simple centered clock with date and day of week
    • Large Clock: Extra-large time display with date
    • Cycle All Styles: Rotates through every clock style automatically, switching every 5 minutes.

    Change clock style anytime via the web portal or touch button!

    Customizing Display Labels

    Via Web Portal (Recommended):

    1. Open ESP32's IP address in browser
    2. Go to the Visible metrics page
    3. Expand a metric and set its Custom label to match your setup:
      • relabel a pump RPM sensor "PUMP", "FAN" or "COOLER"
      • give CPU, RAM, GPU, Disk metrics your own labels too
    4. Changes apply live in the preview; click Save & apply to keep them

    Customizing Monitored Sensors

    The companion app lets you select any sensor available on your system:

    Available Sensor Categories:

    • System Metrics: CPU%, RAM%, Disk usage (using psutil)
    • Temperatures: CPU cores, GPU, motherboard, drives
    • Fans & Cooling: All detected fan speeds
    • Loads: CPU/GPU load percentages
    • Clocks: CPU/GPU clock speeds
    • Power: Power consumption sensors
    • Network Data: Total uploaded/downloaded (in GB)
    • Network Throughput: Current upload/download speeds (in KB/s or MB/s)

    How to Select Sensors:

    1. Make sure LibreHardwareMonitor is running (Windows) for temps/fans/GPU/power. The app falls back to its REST API on 0.9.5+.
    2. Open the companion app - double-click pc_stats_monitor_v4.exe, or right-click the tray icon and choose open
    3. Go to the Sensors page and browse the categories
    4. Live current values are shown next to each sensor to help you identify them
    5. Tick the sensors you want to monitor (up to 20)
    6. Set custom labels if desired (max 10 characters)
    7. Click Save & push to device - the OLED updates live

    ESP32 Web Portal Example

    Tips:

    • The GUI shows live sensor values when you open it
    • Use the search box to quickly find specific sensors
    • Network metrics automatically distinguish between upload and download
    • You can select up to 20 different metrics
    • Labels set in the companion app override the default names on the ESP32

    Audio Visualizer

    The display can show what your PC is playing: 32 spectrum bars or an oscilloscope trace, updated about 25 times a second.

    Classic EQClassic EQMirror EQMirror EQOscilloscopeOscilloscope

    This is a forced mode, not a clock style. It needs a live audio stream, so it is switched on deliberately rather than sitting in the clock rotation, and it drops back to your normal screen about 10 seconds after the audio stops.

    Turning it on

    1. In the companion app (Connection page), tick Audio visualizer stream. The companion captures whatever your PC is playing (WASAPI loopback on Windows, PulseAudio monitor on Linux) and sends it to the same UDP port the stats already use.
      • Windows: no extra setup.
      • Linux / running from source: needs soundcard and numpy (pip install soundcard numpy). The app tells you if they are missing.
    2. Show it on the device, in any of three ways:
      • Tick Start the visualizer when music plays in the companion, and it switches the display for you once sound has been playing for the start delay, then hands the display back after the quiet period.
      • Press Show visualizer on the device's Audio visualizer page.
      • Tap the touch button while audio is playing. Tap again to leave.

    If the panel says "No audio data...", the device is in visualizer mode but no stream is arriving - check the companion is running with the stream enabled.

    Settings (device web portal, Audio visualizer page)

    SettingWhat it does
    VisualizerClassic EQ (bars from the bottom), Oscilloscope, or Mirror EQ (bars split around a centre line)
    Bar textureSolid, Segmented (a dark row every third row - reads as an LED ladder), or Outline
    Frame rate15-60. See the note below
    Peak holdA marker that hangs at each band's last peak and falls back under gravity
    Corner clockSmall HH:MM in the top right; costs the top 12 rows
    Vertical gainOscilloscope trace height, 50-200%
    Ghost traceDotted echo of the previous waveform
    GraticuleOscilloscope grid. Off by default - it is the same white as the trace, so it competes with it
    Fill to centreFills between trace and centre line; goes solid when loud

    About the frame rate. These OLED controllers have no double buffering: the firmware writes straight into the panel's memory while the panel is scanning it out. Drawing faster than the panel can show it does not look smoother, it looks torn. The whole 1024-byte framebuffer also has to cross the I2C bus every frame, which on the stock 400 kHz bus measures 37 fps on a 0.96" SSD1306 and 33 fps on a 1.3" SH1106 - so those are the real ceilings, whatever the setting says. The 30 fps default sits comfortably below both. Raise it if you want; if the picture tears, come back down.

    Advanced users can raise the bus itself with DISPLAY_I2C_CLOCK in src/config/user_config.h (default 400000). 800 kHz roughly halves the transfer time, but it is above what these controllers are specified for and some panels or longer wiring will corrupt the image rather than fail cleanly. Change it only if you can watch the panel while you test.

    Oscilloscope needs a recent companion

    The waveform is an extra 128 bytes appended to each packet. An older companion sends only the spectrum, and the oscilloscope will say "Update PC companion for the waveform". The bar styles work with either.

    Game Mode

    Pair a controller and play on the OLED. Like the visualizer, this is a forced mode: it takes over the display until you leave it, then the device goes back to its normal screen.

    GameControls
    Falling BlocksLeft/right move, up hard-drops, down soft-drops, A rotates one way, B or X the other, LB/RB hold
    SnakeD-pad or stick steers; every bite grows the snake and speeds it up
    BricksStick or d-pad moves the paddle, A launches the ball
    Space RocksLeft/right turn, up or RT thrusts, A or RB fires
    RunnerA or up jumps (hold for a higher jump), down ducks
    DefendersStick or d-pad moves, A, RB or RT fires; one shot in the air at a time

    Every game shows its controls on the start screen. The Menu button pauses, View in the pause screen goes back to the game list, View in the list leaves game mode. Best scores are kept per game.

    What you need

    • An Xbox Wireless Controller with Bluetooth LE: model 1708 (Xbox One S) or the current Series X|S pad (1914), on controller firmware 5.x or newer.
    • The ESP32-C3 only speaks Bluetooth LE. Older pad firmware is Bluetooth Classic only and the device will never see the pad. Update it once with the Xbox Accessories app (Windows or Xbox console).

    Playing

    1. Start game mode from the device web page (Game mode -> Start game mode), with a triple tap on the touch button, or with /api/game/start.
    2. The first time, hold the pad's pair button for 3 seconds. A paired pad reconnects later with the Xbox button.
    3. Pick a game with the d-pad and press A.

    Game mode ends on its own if no pad connects within 2 minutes, if the pad is lost for 1 minute, or after a set time without input (5 minutes by default, configurable, or never). A quick tap on the touch button, /api/game/stop or any /api/mode/* call also ends it. The display stays at normal brightness while you play, even inside the night dimming window.

    Settings (device web portal, Game mode page)

    SettingWhat it does
    Falling Blocks starting level1-10
    RumblePad vibrates on hits, drops, cleared lines and game over
    Falling Blocks: stick up hard-dropsOff: only d-pad up drops, so a nudge on the stick never slams a piece down
    Falling Blocks: landing previewDots mark where the falling piece will land. Off by default
    Auto exitMinutes without input before game mode ends (0 = never)

    The same page shows the pad status and battery, lists the best scores with a reset button for each, and has Forget paired pad. Best scores are part of the configuration export, so a backup restores them.

    Building without it

    Game mode pulls in the NimBLE Bluetooth stack (about 240 KB of flash). To leave it out, set GAMEPAD_ENABLED to 0 in src/config/user_config.h; the Game mode page then disappears from the web portal as well.

    HTTP Control API

    The firmware exposes a small set of HTTP endpoints for remote control and home automation (e.g. Home Assistant, Node-RED, or a simple curl from a script). This is handy for turning the display off while you're away to extend OLED lifetime, forcing the clock display, dimming on your own schedule, or rebooting the device remotely.

    All endpoints are plain HTTP GET (easy to call from any tool), return JSON, and have no authentication - anyone on your local network can call them, so keep the device on a trusted LAN.

    Note: These controls are runtime-only - they are not saved to flash and reset to your normal configured behavior after a reboot or power cycle. This is intentional: it avoids flash wear from automations toggling frequently, and lets an external scheduler own the state. To change defaults permanently, use the web configuration portal.

    Replace smalloled.local in the examples with your device's mDNS name (configurable) or its IP address.

    Endpoints

    MethodEndpointDescription
    GET/api/statusReturn current display/mode state as JSON
    GET/api/display/offTurn the display off (panel powered down)
    GET/api/display/onTurn the display back on
    GET/api/display/brightness?value=0-100Set display brightness (percent)
    GET/api/mode/clockForce the animated clock, even when the PC is online
    GET/api/mode/autoResume automatic mode (PC stats when online, clock when offline)
    GET/api/clock/style?id=<id>Switch the clock animation
    GET/api/mode/vizShow the audio visualizer (needs the companion's audio stream)
    GET/api/viz/style?id=0-2Switch the visualizer style
    GET/api/game/startStart game mode (waits for a pad)
    GET/api/game/stopLeave game mode
    GET/api/game/statusPad link, battery, paired state and each game's best score
    GET/api/game/forgetForget the paired pad
    GET/api/game/hiscore/reset[?id=N]Clear one game's best score (index from games[] in the status), or all of them
    GET/api/rebootSoft-restart the device (does not erase settings)

    Clock style IDs: 0 = Mario, 1 = Standard, 2 = Large, 3 = Space Invaders, 5 = Arkanoid/Pong, 6 = Pac-Man, 7 = Snake, 8 = Tetris, 9 = Cycle All Styles, 10 = Asteroids, 11 = Dino Runner, 14 = Weather, 16 = TRON, 18 = Game of Life, 19 = Dragon Ball. (The ids are a fixed set, not a range - the gaps are reserved so style numbers stay aligned with the sister project.)

    Visualizer style IDs: 0 = Classic EQ, 1 = Oscilloscope, 2 = Mirror EQ.

    Write endpoints used by the web page (/save, /reset, /update, /api/import) only accept POST requests that carry the header X-SmallOLED: 1 (/api/import also accepts any request sent as Content-Type: application/json). This stops other websites open in your browser from changing settings or flashing firmware behind your back. Scripts just add the header, for example:

    curl -H "X-SmallOLED: 1" -F "[email protected]" http://smalloled.local/update
    

    Examples

    # Turn the display off (e.g. when leaving home) and back on
    curl http://smalloled.local/api/display/off
    curl http://smalloled.local/api/display/on
    
    # Dim the display to 30%
    curl "http://smalloled.local/api/display/brightness?value=30"
    
    # Always show the clock, then go back to automatic
    curl http://smalloled.local/api/mode/clock
    curl http://smalloled.local/api/mode/auto
    
    # Switch to the Pac-Man clock
    curl "http://smalloled.local/api/clock/style?id=6"
    
    # Show the audio visualizer, then pick the oscilloscope
    curl http://smalloled.local/api/mode/viz
    curl "http://smalloled.local/api/viz/style?id=1"
    
    # Check current state
    curl http://smalloled.local/api/status
    

    A /api/status response looks like:

    {
      "displayOn": true,
      "forcedOff": false,
      "mode": "clock",
      "forcedClock": true,
      "brightness": 100,
      "clockStyle": 0,
      "pcOnline": false,
      "weatherValid": true,
      "weatherAgeSeconds": 212
    }
    
    FieldMeaning
    displayOnfalse when the panel is off (forced off, or brightness 0)
    forcedOfftrue if the display was turned off via /api/display/off
    mode"metrics" or "clock" - what is currently being shown
    forcedClocktrue if clock mode is being forced via /api/mode/clock
    brightnessCurrent brightness, 0-100%
    clockStyleActive clock style ID (see list above)
    pcOnlinetrue if the PC sender is currently sending stats
    weatherValidtrue once the Weather clock has fetched data for the saved location
    weatherAgeSecondsSeconds since that fetch (only present when weatherValid is true)

    Home Assistant example

    Add this to your configuration.yaml to expose the display on/off controls as commands:

    rest_command:
      oled_display_off:
        url: "http://smalloled.local/api/display/off"
      oled_display_on:
        url: "http://smalloled.local/api/display/on"
    

    You can then call rest_command.oled_display_off / oled_display_on from an automation - for example, turn the display off when everyone leaves home and back on when someone arrives.

    Troubleshooting

    ESP32 Issues

    Display not working

    • Check I2C wiring (SDA=GPIO8, SCL=GPIO9)
    • Verify I2C address is 0x3C (common for SSD1306)
    • For SH1106 (1.3"): change DEFAULT_DISPLAY_TYPE to 1 in user_config.h
    • For CH1116 (1.54"): change DEFAULT_DISPLAY_TYPE to 2 in user_config.h
    • For SSD1309 (2.42"): use DEFAULT_DISPLAY_TYPE 0 (same as 0.96", no change needed)

    Can't connect to WiFi portal

    • Make sure you're connected to "PCMonitor-Setup" network
    • Try accessing 192.168.4.1 in your browser
    • Reset WiFi settings via web interface

    ESP32 keeps restarting

    • Check power supply (use quality USB cable)
    • Monitor serial output at 115200 baud for error messages

    Companion App Issues

    The config window doesn't open

    • Windows: the exe is unsigned, so SmartScreen may hold it on the first run - More info → Run anyway. Once it is running, right-click the tray icon to reopen the window.
    • Linux: a native window needs the system GTK/WebKit libraries (sudo apt install gir1.2-webkit2-4.1 python3-gi). Without them the app still runs and serves the same UI in your browser at http://127.0.0.1:8737.

    Hardware sensor errors (Windows)

    • Make sure LibreHardwareMonitor is running as Administrator - without admin it reports no temps, fans or power
    • Check that the WMI service is running: services.msc → Windows Management Instrumentation

    No sensors showing (Windows)

    • Start LibreHardwareMonitor before the companion app, and give it a few seconds
    • On LibreHardwareMonitor 0.9.5+, enable Options → Remote Web Server → Run. Its WMI backend is broken; the app falls back to the REST API, which that option serves
    • Leave Sensor source on Auto unless you have a reason to force a mode, then hit Rescan sensors

    No data on ESP32 display

    • Verify the ESP32 IP address on the Connection page matches the one shown on the OLED, and use Test connection
    • Check Windows Firewall isn't blocking UDP port 4210
    • Ensure both PC and ESP32 are on the same network
    • Open the ESP32 web interface and check the Visible metrics page - metrics arrive unplaced until you position them

    Autostart not working (Windows)

    • The Start with Windows tick box writes an HKCU Run entry; check Task Manager → Startup
    • It launches minimized to the tray, so look for the tray icon rather than a window

    Autostart not working (Linux)

    • Check service status: systemctl --user status smalloled-companion
    • View logs: journalctl --user -u smalloled-companion -f
    • Make sure systemd is available on your system
    • Enable lingering (optional): loginctl enable-linger $USER

    Network metrics not showing (Linux)

    • Network metrics use psutil's net_io_counters()
    • Upload/download speeds are calculated from byte deltas
    • First reading will always be 0, wait for next update cycle

    Audio visualizer says "No audio data..."

    • The device is in visualizer mode but nothing is arriving - tick Audio visualizer stream on the companion's Connection page
    • Linux / running from source also needs soundcard and numpy, and a PulseAudio/PipeWire monitor source for the default output

    Custom labels not appearing on ESP32

    • Set them on the companion's Sensors page (max 10 characters), then Save & push to device
    • They can also be set per metric in the device's own Visible metrics page

    Technical Details

    Communication

    • Protocol: UDP
    • Port: 4210 (configurable)
    • Format: JSON
    • Update Rate: 3 seconds (configurable in the app)
    • Max Metrics: 20
    • Audio stream: same UDP port, ~25 packets/s, spectrum plus an optional 128-byte waveform

    Companion App Internals

    • JSON configuration in %APPDATA%\SmallOLED-Companion\monitor_config.json (Windows) or ~/.config/smalloled-companion/monitor_config.json (Linux)
    • Dynamic sensor discovery - detects every sensor the system exposes
    • REST API fallback - automatic support for LibreHardwareMonitor 0.9.5+ (broken WMI)
    • Network metrics calculated in real-time (upload/download speeds)
    • Export/Import configuration for easy backup and sharing
    • Systemd integration (Linux) for proper service management

    Libraries Used

    ESP32:

    • WiFiManager (tzapu)
    • Adafruit SSD1306 / Adafruit SH110X
    • Adafruit GFX
    • ArduinoJson
    • NimBLE-Arduino (game mode controller link)

    Companion app (Windows):

    • psutil (system stats & network)
    • pywin32/wmi (LibreHardwareMonitor integration)
    • pywebview (native window hosting the local web UI)
    • pystray/pillow (system tray)

    Companion app (Linux):

    • psutil (system stats, temps, fans, network)
    • pywebview (native window, falls back to the browser)
    • soundcard/numpy (audio visualizer - optional)

    File Structure

    PC-Companion-App-v4/
      companion-common/     # shared UI, server and protocol code
      win-companion/        # Windows app, source of pc_stats_monitor_v4.exe
      linux-companion/      # Linux app, run from source
    monitor_config.json     # per-user config (auto-generated, see path above)
    

    Advanced / Optional Features

    These features are disabled by default and require recompilation. They are configured in src/config/user_config.h and are intended for advanced users who build from source.

    Display Type Selection

    Change DEFAULT_DISPLAY_TYPE to match your OLED:

    ValueDisplaySizeNotes
    0SSD13060.96" / 2.42"Default. Works for both 0.96" SSD1306 and 2.42" SSD1309
    1SH11061.3"132x64 RAM with 2-column offset
    2CH11161.54"SH1106-compatible, no column offset (example panel)

    SPI Display Interface

    By default, displays connect via I2C (2 wires). For faster refresh rates (useful for smooth animations), you can use SPI instead.

    #define DISPLAY_INTERFACE 1          // 0 = I2C (default), 1 = SPI
    

    SPI pin assignments (ESP32-C3):

    SignalGPIONotes
    MOSI (SDA)6Data
    SCK4SPI Clock
    CS5Chip Select
    DC3Data/Command
    RST10Reset (-1 if not connected)

    LED PWM Night Light

    Drive a filament LED (or any LED) via a 2N2222 transistor on GPIO 1. Controlled via TTP223 touch gestures (medium press toggles, long hold ramps brightness with gamma correction).

    #define LED_PWM_ENABLED 1            // 0 = disabled (default), 1 = enabled
    #define LED_PWM_PIN 1                // GPIO pin (default: 1)
    

    See the wiring diagram for the transistor circuit.

    QR Code WiFi Setup

    Show a scannable QR code on the OLED during WiFi AP setup instead of text instructions. Useful for mobile phone setup.

    #define QR_SETUP_ENABLED 1           // 0 = text instructions (default), 1 = QR code
    

    BLE WiFi Provisioning (Experimental)

    Bluetooth Low Energy setup for the SmallOLED Android app (currently in development). Instead of the WiFi AP portal, the ESP32 advertises as a BLE device. The Android app discovers it, sends WiFi credentials over BLE, and the device connects automatically.

    #define BLE_SETUP_ENABLED 1          // 0 = AP mode (default), 1 = BLE provisioning
    #define BLE_DEVICE_NAME "SmallOLED"  // BLE advertised name
    

    How it works:

    1. On first boot (no saved WiFi), device starts BLE advertising
    2. Android app scans and finds "SmallOLED"
    3. App sends your home WiFi SSID + password over BLE
    4. Device connects to WiFi and saves credentials
    5. Subsequent boots connect silently (no BLE needed)
    6. If BLE times out (2 min) or fails, falls back to AP mode automatically

    Requirements:

    • min_spiffs.csv partition table (already set in platformio.ini)
    • NimBLE library (already included in platformio.ini)
    • Android app (in development, not yet publicly released)

    Scheduled Display Dimming

    Automatically dim the display during nighttime hours. Configured via the web interface under Display Settings:

    • Enable/disable scheduled dimming
    • Start/end hours (e.g., 10 PM to 7 AM)
    • Dim brightness level (0-255)

    OTA Firmware Updates

    Upload new firmware wirelessly through the web interface at http://<device-ip>/update. No need to physically connect USB after the initial flash. When a newer release is out, the web page shows a badge in the top bar and names the matching OTA_ONLY file on the Maintenance page (your browser checks GitHub, the device does not).

    License

    This project is open source. Feel free to modify and share!

    Credits

    Created for monitoring PC stats on a small OLED display. Mario animation inspired by classic pixel art.

    Trademarks

    SmallOLED is an independent open-source project. It is not affiliated with, endorsed by or sponsored by Nintendo, Bandai Namco, Taito, The Tetris Company, Microsoft or any other company. Game and character names are used only to describe the style of an animation; all trademarks belong to their respective owners. Every sprite and animation is original low-resolution pixel art drawn by the code in this repository; no artwork, sprite sheets, ROM data, fonts, sounds or music from any commercial game are copied or distributed here, and the firmware does not emulate any of those games.