Shinobi 1 (SHN1) is a hand-built Meshtastic node — a battery-powered, off-grid LoRa mesh communicator with an e-ink display and a physical keyboard for text input. It was built and brought up ahead of DEF CON 34.
Hardware
MCU: ESP32-S3-DEV-KIT-NXR8
Display — HSPI bus
A GDEY042T81 4.2" e-ink panel, wired to its own dedicated HSPI bus:
SCK→ IO36MOSI→ IO35CS→ IO5DC→ IO17RST→ IO16BUSY→ IO47
Radio — FSPI bus
An SX1262 LoRa module, on a separate FSPI bus:
SCK→ IO18MOSI→ IO11MISO→ IO13CS→ IO10
Input
A CardKB physical keyboard, connected over I2C (SDA → IO7, SCL → IO6).
Power — Mark II revision
A TP4056 charge controller feeding an NCR18650GA 18650 cell, with an SPDT slide switch for power control and a 100kΩ/100kΩ voltage divider into IO1 for battery voltage sensing.
Splitting the display and radio onto separate SPI buses (HSPI and FSPI) rather than sharing one bus was a deliberate choice to keep the two peripherals from contending with each other.
Firmware
Running a custom fork: mkrohn-meshtastic 2.8.0.35b0590.
Key build/config settings:
board_build.arduino.memory_type=qio_qspiwith PSRAM disabledUSE_EINK_DYNAMICDISPLAYenabled- Bluetooth pairing PIN set to
123456 - Region: US, channel preset: LongFast
What Worked
- LoRa mesh connectivity — confirmed working via channel pairing against a T-Echo node. This was the core functional milestone: proof that the radio, antenna, and firmware config could actually join a mesh and exchange with another device in the field.
- Split-bus SPI architecture — running the e-ink display and the LoRa radio on independent SPI buses (HSPI vs. FSPI) avoided the bus-contention issues that can come from sharing one SPI peripheral between a slow display and a timing-sensitive radio.
- Power system (Mark II) — the TP4056/18650/voltage-divider combination gave the node standalone battery power with the ability to monitor its own charge level via IO1.
What Didn't (Yet) — Open Issues
spiAttachMISOHSPI warning — an unresolved warning tied to the HSPI bus configuration. Not confirmed to be causing a functional problem, but flagged as something to run down rather than ignore.- IntelliSense grey-out of
EInkDisplay2.cpp— a development-environment annoyance where the editor's IntelliSense stops indexing this file properly, making it harder to navigate/edit with full tooling support. - Node naming not yet persistent — setting the node's name ("Shinobi 1" / "SHN1") isn't yet baked into a single binary flash. Right now it likely requires a separate post-flash configuration step rather than surviving a single reflash.
Next Steps
Build a second unit, which will also serve as a way to shake out whether the open issues above are one-offs or systemic to the build.
A companion carrier board is already designed in KiCad — a 100mm × 100mm, 4-layer board integrating the ESP32-S3, GDEY042T81 display, SX1262 LoRa, GPS, CardKB, and TP4056 charging, with a proper ground plane and power layer in the stackup and RF keep-out zones around the antenna. It also required a custom footprint for the ESP32's non-standard 22.86mm pin spacing. That board work is currently paused pending physical verification of pinouts against the working breadboard/dev-kit build documented above — closing out the open issues here is effectively the prerequisite for unpausing it.
View Firmware on GitHub (Coming Soon) →