Close
0%
0%

DevPocket

DevPocket — Portable ESP32 Debug Tool with MagSafe & mPCIe

Similar projects worth following
DevPocket is an open-source, open-hardware pocket-sized debugging device based on ESP32-WROOM-32UE. It features a built-in LiPo battery, USB-C charging, a MagSafe-compatible magnetic ring for mounting to phones or any metal surface, and a full-size mPCIe expansion slot for custom modules. Work entirely without a PC — just plug into any Android phone and use micro-REPL.

What is DevPocket?

DevPocket is a compact, battery-powered debugging and prototyping device designed to fit in your pocket and work anywhere — no PC required. The idea was born from the need to have a full-featured microcontroller dev board that you can carry with you, attach to your phone like a MagSafe accessory, and use directly from an Android device via micro-REPL.

The project is fully open-source and open-hardware — schematics, PCB layout, and firmware will all be published.


ParameterValue
MCUESP32-WROOM-32UE (Wi-Fi + BT)
USB-UART BridgeCP2102GM
BatteryLP603048, 900 mAh LiPo
Charging ICTP4056-42-ESOP8 (USB-C input)
Boost ConverterTPS61023DRLR, 5V output
LDOAP2112K-3.3, 3.3V rail
RGB LEDs4× WS2812B-2020 (addressable, configurable)
Buttons2× tactile, user-configurable
ExpansionmPCIe slot (custom modules supported)
GPIO Header30-pin, 2.54mm pitch (3.3V, 5V, UART, SPI, I2C, GPIOs)
USB ConnectorUSB Type-C (charging + data)
ESD ProtectionUSBLC6-2SC6 on USB lines
Supervisor ICSTM6519AHARUB6F
MountingBuilt-in MagSafe-compatible magnetic ring

📡 Expansion Philosophy

The mPCIe slot is the key differentiator. Rather than being limited to cellular modules (as the connector was originally designed for), DevPocket uses it as a universal expansion bus. The slot exposes:

  • UART1 (TX/RX)
  • SPI (CLK/MOSI/MISO)
  • I2C1 (SDA/SCL)
  • 6× GPIO (GPIO2, 4, 5, 12, 14, 15)
  • Switchable 5V / 3.3V / BATT power lines 

This means you can design your own plug-in modules — sensors, motor drivers, displays, radios, or anything else — in the standard mPCIe form factor.

📱 No-PC Workflow
One of the core use-cases is connecting DevPocket directly to an Android smartphone via USB-C. The CP2102GM bridge enumerates as a USB-serial device, and micro-REPL (available on Android) lets you write and execute MicroPython code interactively — no laptop needed. Combined with the magnetic mount, you can literally stick DevPocket to the back of your phone and use them together as a single unit.

DevPocket.pdf

Main Board

Adobe Portable Document Format - 493.43 kB - 04/27/2026 at 19:13

Preview

mPCIe_Sens.pdf

First Module — Air Quality Sensor Board

Adobe Portable Document Format - 98.00 kB - 04/27/2026 at 19:12

Preview

  • Project Log #5 — Rev.1 Bugs and What Changed in Rev.2

    Ilya Egorov4 days ago 0 comments

    Background

    The first real-world testing of DevPocket — connecting to a phone, running scripts, testing the sensor module — worked well functionally. But that is exactly when schematic mistakes surface: not during simulation, not during layout review, but when you actually use the thing. Below is a full breakdown of every issue found in Rev.1 and how each one was fixed in Rev.2.

    Fix 1 — Wrong LDO for a Battery-Powered Device

    Rev.1: The 3.3V rail was regulated by an AMS1117-3.3. It is a widely used part, but it has a high quiescent current and performs poorly at micro-load — which is exactly the operating condition of a device that spends most of its life in deep sleep. Every unnecessary microamp of idle current directly eats into battery life.

    Rev.2: Replaced with AP2112K-3.3 — a true LDO with a very low quiescent current, well-suited for light and intermittent loads. For a battery device this is not a minor detail: a difference of even 100 µA in sleep mode translates to hours of lost standby time.

    (Schematic screenshot: Power sheet — AMS1117 → AP2112K change)

    Fix 2 — No Way to Cut Peripheral Power in Sleep

    Rev.1: Peripheral power rails were always active. The core problem: WS2812B and CP2102GM have no hardware sleep mode and no other way to reduce their consumption. Left powered, they draw enough current to significantly shorten battery life even when the ESP32 itself is in deep sleep.

    Rev.2: A new control signal Peripheral_En driven by an ESP32 GPIO was added. It switches a P-channel MOSFET (AO3401A) that cuts power to the WS2812B chain, the CP2102GM bridge, and the mPCIe slot simultaneously. Before entering deep sleep, the firmware pulls Peripheral_En to disable all peripherals — the device now actually sleeps rather than just having the MCU idle while everything else keeps running.

    (Schematic screenshot: Power sheet — AO3401A peripheral switch)

    Fix 3 — No Battery Voltage Monitoring

    Rev.1: Battery voltage was not measured anywhere in the design. There was no way to display a charge level indicator or implement low-battery protection in firmware.

    Rev.2: A resistor voltage divider was added from the BATT rail to an ESP32 ADC input, exposed as the BATT_ADC signal. The divider scales the LiPo voltage range (3.0–4.2V) into the ESP32's ADC input range. Firmware can now track battery state and warn the user via the OLED or LEDs.

    (Schematic screenshot: Digital sheet — BATT_ADC divider)

    Fix 4 — No Test Points and Unreliable Reset

    Rev.1: There were no test points on critical signals. The practical consequence: to flash MicroPython for the first time you need to hold GPIO0 low during boot to enter download mode — without a test point this is fiddly and unreliable on a compact board.

    Rev.2: Test points TP1–TP3 were added on key signals including GPIO0, making the initial flashing procedure straightforward. Additionally, STM6519AHARUB6F was added as a dedicated reset supervisor — a "smart reset button". Holding the reset button for an extended period forces a guaranteed hardware reset of the MCU. This matters in practice: if a script hangs and stops responding, a software reset won't help. You need the iron guarantee.

    (Schematic screenshot: Digital sheet — TP1–TP3 and STM6519)

    Fix 5 — No Pull-Up Resistors on CHIP_EN and GPIO0

    Rev.1: The CHIP_EN and GPIO0 lines had no pull-up resistors. ESP32 requires CHIP_EN to be held high for normal operation, and GPIO0 must be high at boot for normal firmware execution (low = download mode). Without explicit pull-ups the startup behaviour was unstable and non-deterministic.

    Rev.2: Pull-up resistors to 3.3V were added on both CHIP_EN and GPIO0. Boot behaviour became stable and repeatable.

    (Schematic screenshot: Digital sheet — CHIP_EN and GPIO0 pull-ups)

    Fix 6 — Device Could Not...

    Read more »

  • Project Log #4 — Mechanical Design & Enclosure

    Ilya Egorov05/06/2026 at 18:08 0 comments

    Design Constraints

    From the very beginning, the enclosure had one hard requirement: when DevPocket is magnetically mounted to a smartphone via MagSafe, it must not extend beyond the phone's footprint. This drove the outer dimensions to 64.6 × 74.6 × 20 mm — compact enough to sit behind most modern smartphones without sticking out.


    (Photo : all devpocket mechanics)

    The 20 mm thickness is not arbitrary — it is dictated directly by the internal stack-up. From bottom to top: the LiPo battery sits on the underside of the main PCB, then the board itself, then the mPCIe module plugged in on top. There is no wasted space; the enclosure height is exactly what the electronics require.

    (Screenshot: cross-section view showing the internal stack)

    Fabrication Method

    The enclosure is FDM 3D printed, chosen from the start of the project. FDM is the obvious choice for an open-hardware project: the files are on GitHub in both STEP and STL format, anyone with a printer can reproduce or modify the enclosure without any tooling costs, and iterating on a new revision takes hours rather than weeks.

    Bottom Shell — MagSafe Ring Pocket

    The bottom shell has a dedicated recessed pocket for the magnetic ring. The ring is a standard neodymium magnet ring sold on AliExpress for MagSafe-compatible accessories — it comes with a self-adhesive backing, so installation is simply press-fit into the pocket. No tools required.

    The pocket dimensions match the standard MagSafe ring geometry: 56 mm outer diameter, 46 mm inner diameter. This allows DevPocket to attach magnetically to any MagSafe-compatible phone case, a ring stand, or any ferromagnetic surface.


    (Screenshot: bottom shell with the MagSafe ring pocket)

    Top Shell

    The top shell carries all the user-facing cutouts: the two tactile buttons, the USB-C connector, and the antenna port. It also includes channelled light guide channels — individual tunnels for each of the four WS2812B LEDs, with dividing walls between them to prevent light bleed between channels.

    (Screenshot: top shell showing button cutouts and light guide channels)

    Two variants of the top shell are published on GitHub:

    • Standard top — for bare DevPocket use
    • Sensor module top — with ventilation slots for air circulation around the ENS160/AHT20/BMP280 sensors, plus a slot for the display board that mates with the lid connector automatically when the case is closed

    The top shell is the part you'll most likely customise when designing your own mPCIe modules — the rest of the enclosure stays the same.

    Fasteners and Heat-Set Inserts

    All threaded connections in the enclosure use M2 × 5 × 3.2 brass heat-set inserts pressed in with a soldering iron. Installation temperature should be approximately 10–20 °C above the filament's print temperature — for PLA around 225 °C, for PETG around 245 °C.

    The knurled outer surface of each insert melts into the surrounding plastic and locks permanently as it cools, giving a clean metal thread that survives repeated assembly and disassembly without stripping.

    Two screw types are used:

    ApplicationScrew
    PCB to bottom shell (standoffs)M2 × 4 DIN 912 — socket cap head (hex key) 
    Top shell to bottom shellM2 × 14 countersunk — DIN 965 / ISO 7046, 90° head, Pozidriv drive 

    Using countersunk screws for the shell halves keeps the outer surface completely flat — no protruding heads on any face of the device.

    Light Guides

    The light guides are custom-designed parts, printed on an SLA 3D printer in clear resin. SLA was the right choice here: the smooth, optically clear surface finish of SLA parts transmits light from the WS2812B LEDs far more efficiently than the rough, semi-opaque surface of an FDM print.


    (Photo: light guides separately)

    Each guide is shaped to route light from the LED position to the face of the enclosure, with the dividing walls in the top...

    Read more »

  • Project Log #3 — Portable Air Quality Monitor with Display

    Ilya Egorov04/29/2026 at 17:08 0 comments

    The mPCIe Sensor Module in Action

    In the previous log I introduced the air quality sensor module — now it's time to actually read data from it. The module carries three sensors over a shared I²C bus: BMP280 (temperature + pressure), AHT20 (temperature + humidity), and ENS160 (eCO₂, TVOC, AQI index). All three sit at fixed I²C addresses and are powered through the mPCIe connector from DevPocket's 3.3V rail.

    Reading the Sensors — How the Script Works

    On startup, the script runs an I²C scan and initialises each sensor in sequence, printing the result to the console.The ENS160 is the most demanding sensor to initialise — it requires a hardware reset sequence (RESET → IDLE → CLEAR → STANDARD), and its Part ID (0x0160) is verified before proceeding. Once running in standard mode, it receives live temperature and humidity compensation data from the AHT20 on every reading cycle, which is mandatory for accurate eCO₂ and TVOC figures.Readings are updated once per second. The console microREPL output looks like this:

    (Screenshot: console output with sensor init and live readings)

    While the script is running you can interact with it via micro-REPL or any serial terminal:

    CommandAction
    dataPrint a fresh sensor reading immediately
    statusShow which sensors were found and ENS160 init state
    scanRe-run the I²C bus scan
    helpList available commands

    The four WS2812B LEDs on DevPocket each have a dedicated role in this script:

    LEDMeaning
    LED 0Green — all sensors OK / Red — at least one missing
    LED 1Orange — USB charging in progress / Green — on battery
    LED 2Blue blink — I²C read cycle active
    LED 3Green — air quality normal / Yellow — warning / Red — poor

    Going Fully Standalone — The Display Lid

    When I designed DevPocket I included two dedicated connectors on the main board: one for an OLED display and one for an LED matrix. The idea was to make a PCB that mounts inside the top lid of the enclosure — when you close the case, the connectors mate automatically and the display(LED matrix) is live without any extra wiring.

    (Photo: top lid with the display board glued in)

    The display board uses a standard 128×64 SSD1306 OLED. It connects to the  I²C bus as the sensor module, so the whole system — sensors, display, and main MCU — runs on two wires.
    The OLED layout for the air quality script fits all key data on the 64px height.Temperature and humidity sit on the top line, pressure on the second. Below the divider: AQI, TVOC, eCO₂, and a plain-English air quality description. The bottom status bar shows either a sensor warning (!Sensor miss), charging state, or the button hint (Hold>2s=menu).


    (Photo: DevPocket with the sensor module and display running)

    Returning to the Launcher

    Since this script runs inside the launcher (described in Log #2), exiting back to the script menu is built in. Holding the NEXT button (GPIO13) for more than 2 seconds triggers a clean shutdown: the sensor power rail is cut via the PWR_SENSORS GPIO, the OLED shows "Returning to menu…", the LEDs are cleared, and a KeyboardInterrupt is raised — which the launcher catches and uses to return to the script selection menu. No reboot needed.


    (Photo: DevPocket with display in the script selection menu )

    What This Actually Gives You

    At this point DevPocket is a fully self-contained device: battery powered, display on the lid, no phone or PC required. In practice I carry it as a portable air quality monitor — drop it in a bag, pull it out, and the OLED immediately shows temperature, humidity, pressure, CO₂ level, and an AQI rating for wherever you are. The same unit also doubles as a battery-powered I²C scanner — just launch the scanner script from the menu instead.

    What's Next

    In Log #4 I'll cover the mechanical side — how the enclosure is designed and assembled, and I'll publish the STEP models for the current enclosure revision to GitHub so you...

    Read more »

  • Project Log #2 — First Power-On, First Sketch, First Module

    Ilya Egorov04/27/2026 at 19:04 0 comments

    First Power-On

    The first boot went smoothly — no magic smoke, no unexpected behaviour. I went through the hardware checklist one by one:

    • Power system — the TP4056 charged the LiPo correctly via USB-C, the TPS61023 boost converter brought up the 5V rail cleanly, and the AMS1117-3.3 LDO delivered stable 3.3V to the ESP32
    • Microcontroller — the ESP32-WROOM-32UE enumerated correctly over the CP2102GM USB-UART bridge and responded to flashing without issues
    • WS2812B LEDs — all four addressable RGB LEDs responded to a test pattern
    • Tactile buttons — both GPIOs registered clean transitions with debounce

    DevPocket then connected to an Android phone and was immediately recognised by micro-REPL. One small surprise: the phone started charging the device over USB without any prompt or permission request. This is standard USB host/peripheral negotiation behaviour — the phone detected DevPocket as a device and pushed VBUS. It's not a problem in practice, but worth noting for battery-conscious use cases.


    (Photo: DevPocket during first power-on)

    First Sketch — Script Launcher with Deep Sleep

    For the first real firmware I wanted something immediately useful: a launcher that lets you navigate and run scripts stored on the ESP32's filesystem directly from the two hardware buttons.

    Everything is controlled with two buttons:

    • NEXT — scrolls through the script list
    • RUN (short press) — launches the selected script
    • RUN (hold >2 sec) — sends the device into deep sleep

    When a script runs, it executes inside the launcher's context. When it finishes, DevPocket returns to the menu automatically.


    (Screenshot: micro-REPL session on Android)

    First Module — Air Quality Sensor Board

    The first mPCIe module I designed alongside the main board is an environmental monitoring module — something I've wanted to carry around for a long time to assess air quality wherever I happen to be.


    (Photo: mPCIe sensor module)

    The module fits the standard mPCIe half-size form factor and plugs directly into DevPocket's expansion slot. It carries three sensors on a shared I²C bus:

    SensorMeasuresI²C Address
    BMP280Barometric pressure, temperature0x76 (SDO → GND)
    AHT20Relative humidity, temperature0x38 (fixed)
    ENS160eCO₂, TVOC, AQI0x52 (ADDR → GND)


    Power architecture is a two-rail design. The ENS160 requires a separate 1.8V supply for its VDDIO digital interface, generated by an XC6219B182MR-G LDO. The sensor core VDD runs from 3.3V via a second XC6219B332MR-G LDO, providing local regulation and decoupling independent of the main board's rail. The BMP280 and AHT20 run directly from the module's 3.3V rail.

    All three sensors communicate over I2C1 (SDA/SCL routed through the mPCIe connector from ESP32 GPIO32/33). The ENS160 INT line is routed to IN1 on the connector for interrupt-driven readout when needed.

    I²C Scanner — First Utility Script

    Before writing any sensor code, I ran an I²C scanner to verify that all three sensors were electrically present and at their expected addresses. This is a universally useful tool — any time you're debugging an I²C bus on an unknown device, you just run it on DevPocket.

    (Screenshot: I²C scanner output on Android via micro-REPL)

    The scanner swept addresses 0x08–0x77, and all three sensors responded at their expected addresses: 0x380x52, and 0x76. No bus errors, no address conflicts — the module schematic checked out.

    What's Next

    The next natural step is to read actual data from all three sensors and display it on the OLED — so you can get a full air quality readout with no phone attached at all. That sketch is in progress now, and it'll be the subject of Log #3.

    One more thing: during this testing phase I found several bugs in the Rev.1 schematic. A Rev.2 board is already being prepared. I'll detail exactly what went wrong and how I fixed it — probably in Log #4 or #5.

  • Project Log #1 — Antenna Selection and SWR Testing for DevPocket

    Ilya Egorov04/26/2026 at 10:55 0 comments

    Why a external antenna?

    When I designed DevPocket around the ESP32-WROOM-32UE, I made a deliberate choice: pick the UE (external antenna) variant instead of the standard E variant with a built-in PCB trace antenna. The reason is simple — DevPocket is a universal tool. It goes into a magnet-ringed plastic enclosure, gets mounted to phones, placed near other electronics, and used in wildly different environments. 

    By routing the antenna connection to a standard U.FL/IPEX connector, I leave the door open: you can install a short stubby antenna for desktop use, a high-gain directional antenna for range testing, or a flat flex antenna if you're tight on space. The hardware doesn't dictate the RF strategy — you do.

    What I Actually Chose
    For the reference build I needed an antenna that was:

    Cheap (this is a hobbyist open-hardware tool)

    Compact enough to fit inside or flush against the enclosure

    Tuned for 2.4 GHz (Wi-Fi b/g/n + Bluetooth)

    Available widely (AliExpress, LCSC, Mouser)

    I settled on a small 2.4 GHz PCB antenna with an IPEX MHF1 connector — the kind that costs $1–2 and is commonly used in routers and IoT devices. The real question was: how well does it actually perform once it's inside a plastic enclosure surrounded by a PCB and a LiPo battery?

    That's where the NanoVNA comes in.

    A Quick Primer: What is SWR and Why Does It Matter?
    SWR (Standing Wave Ratio), is a measure of how well an antenna is matched to the transmission line (in our case, the 50Ω trace from the ESP32's RF output to the antenna).

    When RF energy travels down a transmission line and hits an antenna with a different impedance, some of that energy reflects back toward the source instead of radiating into the air. These forward and reflected waves create a standing wave pattern. SWR quantifies this mismatch:

    SWR = 1.0 — perfect match, 100% of power is radiated (theoretical ideal)

    SWR = 1.5 — about 4% of power reflected — excellent for real-world use

    SWR = 2.0 — about 11% reflected — acceptable

    SWR = 3.0 — about 25% reflected — poor, noticeably degrades range

    SWR > 3.0 — the antenna is significantly detuned

    For Wi-Fi at 2.4 GHz, a target of SWR ≤ 2.0 across the band (2400–2500 MHz) is the practical goal. The NanoVNA measures this directly by injecting a swept RF signal and measuring the reflection coefficient (S11).


    Why measure in three conditions?
    An antenna doesn't exist in a vacuum — it exists inside an electromagnetic environment. Its resonant frequency and impedance are affected by everything nearby:

    The enclosure — even plastic changes the effective dielectric constant around the antenna element, shifting its resonant frequency 

    The PCB ground plane — a large copper pour beneath the antenna acts as a reflector and can detune it

    The battery — a LiPo pouch is essentially a lossy dielectric slab that absorbs and scatters RF

    This is why antenna datasheets are largely useless for embedded designs — they measure the antenna in free space on a reference board. Your actual SWR will be different. Testing in three progressive conditions lets you see exactly how much each layer of the design degrades (or shifts) the antenna's performance.

    Measurements

    All measurements taken with a NanoVNA (calibrated with the SOLT standard at the U.FL reference plane). Frequency sweep: 2000–2600 MHz.

    1. Antenna alone, no enclosure
      SWR(2400MHz) - 1.61
    2. Antenna in enclosure, no PCB
      SWR(2400MHz) - 1.13
    3. Antenna in enclosure with full PCB + battery
      SWR(2400MHz) - 1.56

    Takeaways
    The NanoVNA is an indispensable $50 tool for any embedded project with RF. Even if you're not designing the antenna yourself, verifying that the chosen antenna still works inside your specific enclosure with your specific board . 

    What's Next
    Antenna verified. Time to apply power for the first time.

    In Log #2 I'll walk through the first boot of DevPocket: flashing firmware through the CP2102 bridge, what micro-REPL looked like on first...

    Read more »

View all 5 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates