Shinobi 1: A Custom Meshtastic Node

A hand-built, off-grid LoRa mesh communicator built ahead of DEF CON 34

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

ESP32-S3-DEV-KIT-NXR8 GDEY042T81 E-Ink Display SX1262 LoRa CardKB TP4056 NCR18650GA

MCU: ESP32-S3-DEV-KIT-NXR8

Display — HSPI bus

A GDEY042T81 4.2" e-ink panel, wired to its own dedicated HSPI bus:

  • SCK → IO36
  • MOSI → IO35
  • CS → IO5
  • DC → IO17
  • RST → IO16
  • BUSY → IO47

Radio — FSPI bus

An SX1262 LoRa module, on a separate FSPI bus:

  • SCK → IO18
  • MOSI → IO11
  • MISO → IO13
  • CS → 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_qspi with PSRAM disabled
  • USE_EINK_DYNAMICDISPLAY enabled
  • 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

  • spiAttachMISO HSPI 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) →