eric 6125130e6a fix(e2e): peer sendText moved to Interface; add RF failure diagnostics
Run 10538 booted the full simulator and ran pytest — both failures were
test-side: the installed meshtastic client moved sendText from Node to the
Interface, and the outbound chunked message never arrived at the peer (cause
still unknown). Fix the sendText call and add in-run diagnostics so the next
failure is self-explaining:

- e2e: outbound-timeout failure now reports what arrived at the peer and the
  simulator log tail; sim now boots with -v (meshtastic debug logging).
- run_e2e.sh: on pytest failure in docker mode, dump per-node meshtasticd
  logs (meshtasticator-nodes.log) before cleanup removes the container.
2026-09-07 21:46:25 -07:00

Meshtastic Node Setup & Web Client Integration

This repository maintains the firmware build artifacts, local CA TLS provisioning, device configuration backups, and Kubernetes deployment integration for the local Meshtastic node.


1. Hardware & Network Overview

  • Hardware: Heltec WiFi LoRa 32 (V4) / ESP32-S3 (16MB Flash, 2MB PSRAM, 0.96" OLED display)
  • Node MAC: f8:5b:1b:a1:bc:60 (Node ID: !1ba1bc60, Name: Meshtastic bc60)
  • Firmware Base: Meshtastic v2.7.26.54e0d8d
  • Network Connectivity:
    • Wi-Fi DHCP IP: 192.168.20.140
    • mDNS Hostname: meshtastic.local
    • TCP Port 4403: Meshtastic Protobuf API (CLI and internal RPC)
    • TCP Port 443: Native HTTPS server serving /api/v1/fromradio and /api/v1/toradio with CORS enabled

2. Architecture & Challenges Solved

A. Mixed Content & Browser Security

The self-hosted Meshtastic Web Client runs on Kubernetes at https://meshtastic-web.ericxliu.local via internal Nginx ingress with TLS. Because the Web Client is a client-side Single Page Application (SPA), the browser makes direct API requests to the radio on LAN:

  • Mixed Content Blocking: The browser forbids plain HTTP calls from an HTTPS origin.
  • Self-Signed TLS Rejection: Stock Meshtastic firmware generates a self-signed certificate (CN=meshtastic.local, O=Meshtastic), which browsers reject with NET::ERR_CERT_AUTHORITY_INVALID.

B. Custom Local CA Provisioning

  • A leaf certificate and private key were issued for DNS:meshtastic.local and DNS:*.meshtastic.local by Eric's private root CA (ericxliu.local, trusted in macOS Keychain).
  • Stock Meshtastic stores its HTTPS key and certificate in ESP32 NVS preferences under the MeshtasticHTTPS namespace (PK and cert).
  • The custom firmware in firmware-custom/ writes the DER-encoded CA-signed certificate and key directly into these NVS keys on startup. Because stock Meshtastic checks for existing keys before generating a self-signed pair, this CA certificate survives future upgrades.

C. Handshake Latency & Web Client Timeout

  • Handshake Bottleneck: In stock firmware (WebServer.cpp), IDLE_INTERVAL_MS was set to 1000ms. The multi-round-trip TLS handshake plus 2048-bit RSA computation took ~4.5 to 5.4 seconds.
  • Hardcoded Client Timeout: The official web client bundle (apps/web/src/pages/Connections/utils.ts) had a hardcoded 2500ms timeout on testHttpReachable. Every test attempt was aborted at 2.5s, marking the device as "Not reachable".
  • The Fix:
    1. Reduced IDLE_INTERVAL_MS in firmware to 50ms (dropping handshake and response time to ~1.34 seconds).
    2. In k8s-flux, added an initContainer in apps/myapp/meshtastic-web/release.yaml that patches testHttpReachable timeout in the bundle from t=2500 to t=15000 (15s).

3. Directory Layout

.
├── README.md
├── certs/
│   ├── meshtastic.local.crt          # Signed leaf certificate (valid to Oct 2027)
│   └── meshtastic.local.csr          # Certificate Signing Request
├── firmware-custom/
│   ├── firmware-heltec-v4-2.7.26.54e0d8d.bin          # Custom app0 image with CA cert + 50ms loop
│   ├── firmware-heltec-v4-2.7.26.54e0d8d.factory.bin  # Full factory image (bootloader + part + app)
│   ├── MeshtasticTlsCertificate.h                     # DER cert & key header embedded into build
│   └── patches/
│       └── WebServer.cpp.patch                        # Diff applied to stock v2.7.26.54e0d8d
├── firmware-2.7.26/                                   # Stock vendor 2.7.26 firmware binaries
│   ├── firmware-heltec-v4-2.7.26.54e0d8d.factory.bin
│   ├── firmware-heltec-v4-2.7.26.54e0d8d.mt.json
│   ├── littlefs-heltec-v4-2.7.26.54e0d8d.bin
│   └── mt-esp32s3-ota.bin
├── backups/
│   ├── aideepen-lora-v4-factory-f85b1ba1bc60.bin      # Original factory 16MB flash dump
│   └── nvs_backup_before_flash.bin                    # Live NVS partition backup (0x9000, 20KB)
├── docs/
│   └── 91Qt4C5SZBL.pdf                                # Heltec V4 board schematic and pinouts
└── scripts/
    ├── flash_custom_firmware.sh                       # Flash custom firmware to app0 over USB
    └── backup_nvs.sh                                  # Backup device NVS partition over USB

4. Maintenance & Operations

Flash Custom Firmware via USB

Connect the Heltec V4 via USB-C:

./scripts/flash_custom_firmware.sh /dev/cu.usbmodem1101

Or directly with esptool:

esptool --port /dev/cu.usbmodem1101 --baud 921600 write_flash 0x10000 firmware-custom/firmware-heltec-v4-2.7.26.54e0d8d.bin

Backup NVS Configuration

./scripts/backup_nvs.sh /dev/cu.usbmodem1101

Verify TLS Handshake & API Endpoints

Verify certificate validity using macOS system trust:

# Must verify without -k / insecure flags
curl -v https://meshtastic.local/api/v1/fromradio

Verify CLI over Wi-Fi:

meshtastic --host meshtastic.local --info

Accessing the Web Client

  1. Open https://meshtastic-web.ericxliu.local.
  2. Select HTTP connection and set URL to meshtastic.local (with Use HTTPS enabled).
  3. Connection tests complete in ~1.3s and save cleanly.
S
Description
Meshtastic node setup, custom HTTPS CA provisioning, backups, and k8s-flux Web Client integration
Readme 6.7 MiB
v0.1.4 Latest
2026-09-08 05:00:46 +00:00
Languages
Python 60.7%
C 32.1%
Shell 7.2%