meteo-carrier — PCB design brief

One board that connects an ESP32 module to its sensors, its satellite modem, and an off-board solar + battery power system.

Prepared 2026-08-17, revised 2026-09-08 · for the PCB designer · condensed from the project's carrier specs (2026-08-09-meteo-carrier-pcb-design.md = the electrical contract, 2026-08-15-carrier-pcb-order-and-proto-design.md = the realization). Where this page and those specs disagree, the specs win.

1What this device is, in 60 seconds

An autonomous weather probe sealed inside a Ø200 mm floating sphere. It sleeps almost all the time on a battery, wakes hourly to read sensors, and a few times a day powers a satellite modem to transmit. Because it sleeps for months, the electrical design is dominated by one number: the always-on rail must idle in single-digit microamps. Everything hungry (GPS, modem) sits behind its own power switch.

Three copies of the board fly in probes that can never be serviced again; two more serve the bench. So: five identical boards, boring and reworkable beats clever and dense.

2The key idea: power generation lives OFF the board

This is the part that most needs saying up front. The solar panels, the battery pack, and the charger are three separate physical assemblies that never touch the PCB you are designing:

  1. Solar array — 3 small panels (Voltaic P123, 6 V class, 0.64 W each) mounted in the hull's crown. They are OR-ed through one Schottky diode each on a little combiner perfboard next to the panels. One two-wire cable comes down from it.
  2. Battery pack — 6 × 18650 Li-ion cells (~21 Ah) lying in bays printed straight into the battery platform, low in the hull, with two 10 kΩ NTC thermistors at the pack: one for the charger's TS pin, one for your board. They are separate parts on purpose — see the note in §5.
  3. Charger board — an off-the-shelf Adafruit bq25185 breakout (#6106), mounted on standoffs next to the carrier. The solar cable and the battery leads both land here. It charges the pack (its own TS pin + its own pack NTC blocks charging below 0 °C in hardware) and provides the power path. It also carries a 5 V boost, which this design does not use: its enable pad is tied to GND at the charger so the unused stage cannot come up.
The whole power interface to your board is battery voltage and ground — two conductors: BATT+ · GND. That is all. The 5 V and EN conductors this brief used to specify were deleted in September when the modem moved onto the battery rail. No solar wiring, no cell wiring, no charge current ever crosses the PCB. (Corollary: do not add solar terminals or OR-ing diodes to the board — an earlier revision had them and they were deliberately deleted; a second series diode would cost the array real voltage.)
The charger is the bq25185 (#6106), chosen 8 September. One bench measurement could still send it back to the owned bq24074 — if the #6106 does not idle in microamps. Either board presents the same two conductors, which is why the charger connects by cable to a connector rather than by a footprint. Keep the board charger-agnostic; nothing about the layout turns on which one is fitted.

3The system at a glance

OFF-BOARD (NOT YOUR PCB) 3× solar panels P123 · 6 V · 0.64 W in the hull crown combiner 3× Schottky OR perfboard battery pack 6× 18650 (~21 Ah) + 2× 10 kΩ NTC (TS pin + carrier) charger board bq25185 (#6106) charge + power path TS cold cut-off 5 V boost unused EN pad → GND (fallback: bq24074) SOLAR IN (2-wire) BAT NTC → carrier the second thermistor leak pads 2 screws on hull wall DS18B20 sea-temp probe (1-Wire) THE BOARD YOU DESIGN meteo-carrier 2-layer · ≤ 100 × 80 mm · 4× M3 charger port — 2 conductors BATT+ · GND (size: see §5) F1 polyfuse → MCP1700 LDO always-on 3V3, 1.6 µA Iq JP1 / JP2 metering jumpers 2× MCU socket strips DevKit + FireBeetle, one fitted 2× TPS22918 load switch GPS 3V3 (IO25) · modem VBAT (IO26) QW1 Qwiic — I²C0 always-on QW2 Qwiic — I²C1 switched SOCK_BARO header — I²C0 XH-5 RockBLOCK port VBAT · GND · RX · TX · On/Off XH-3 sensor ports ×3 DS18B20 · NTC · leak (keyed) 0805 passives (fab-placed) pull-downs, pull-up, dividers, caps PLUG-IN MODULES ESP32 module FireBeetle 2 ESP32-E (or DevKit on the bench) I²C0 sensors BME280 (0x77) MAX17048 gauge (0x36) BMP581 baro (0x47) SAM-M8Q GPS I²C1, on the switched rail RockBLOCK 9603 Iridium modem · UART 3.3 V VBAT pin 8 · 470 mA max
Amber = off-board assemblies (exist already; connect by cable). Blue = the PCB being designed. Green = modules that plug into it. The five arrows into the board are its complete external interface: one charger cable, three sensor cables, and the module sockets/ports.
off-board assembly the carrier PCB plug-in module

4What the board actually does

Functionally the carrier is four things:

  1. Makes the always-on 3.3 V rail. BATT+ → F1 polyfuse (1.1 A hold) → MCP1700-3302E LDO (TO-92, 1.6 µA quiescent — this exact part, its Iq is the sleep budget) → JP1 jumper → 3V3 to the MCU sockets, QW1 and SOCK_BARO.
  2. Switches the two hungry rails, with a load switch each. GPS: 3V3 → U2 TPS22918 → QW2, gated by IO25. Modem: VBAT → U3 TPS22918 → JP2 → the RockBLOCK port, gated by IO26. The modem rail is tapped ahead of F1, because a 1.1 A polyfuse carries real resistance and a few hundred mV at 500 mA would eat the margin against the modem's 3.0 V minimum. Both gate lines carry 100 kΩ pull-downs so neither rail can come up during boot, reset, or with no MCU fitted.
  3. Routes the buses. I²C0 (IO21/22) to the always-on sensors; I²C1 (IO18/19) to the GPS only; UART (IO16/17) to the modem port; 1-Wire (IO4) to the DS18B20 port; two gated analog dividers (NTC, leak) into input-only ADC pins.
  4. Seats the modules. Two machined-pin socket strips so either a DFRobot FireBeetle 2 ESP32-E or an ELEGOO ESP32 DevKit drops in (one populated at a time), plus a 2.54 mm header for the BMP581 breakout and two Qwiic (JST-SH) connectors. The BME280 needs a fourth seat that is not yet decided — §10.

5Connectors — the board's entire edge

All wire ports are JST-XH, top-entry, through-hole. The connector sizes double as keying; the two 3-pin sensor ports are additionally keyed by a vacant centre pin.

PortTypePin order (1→n)Goes to
ChargerXH-5, three positions vacantBATT+ · — · — · — · GNDbq25185 board (cable)
RockBLOCKXH-5VBAT · GND · RX · TX · On/Offmodem (3.3 V LVTTL UART — direct, no shifter). The sleep pin is now wired: the owned units are v3.D, which takes ordinary 3.3 V logic
DS18B20XH-3DATA · GND · 3V3 — this order is deliberate keying, keep itwaterproof temp probe
NTCXH-3, centre pin vacantIO13-node · — · IO34-node10 kΩ NTC at battery pack
LeakXH-3, centre pin vacantsense · — · GNDtwo pads on the hull wall
QW1 / QW2JST-SH 4-pin (Qwiic), SMDstandard QwiicQW1 → MAX17048 fuel gauge only; QW2 → GPS. The BME280 is a header board, not Qwiic — see §10
JP1 / JP22-pin 2.54 header + shuntin-line in 3V3 / in the switched modem railmetering + interlock (below)
Why the odd keying: connector sizes are the keying. On a plain 2-pin NTC port a mis-plugged 2-pin cable would put ~6–7 V on an ESP32 pin rated 3.6 V absolute max. With the vacant centre, any offset-inserted smaller housing lands one contact on a dead pin — open circuit, nothing happens. The DS18B20 pin order makes every remaining sensor-harness cross-plug electrically passive. Please don't "clean this up".
The charger port is XH-5 with three dead pins — decided 2026-09-09: this argument used to rest on the only 2-pin XH in the system being the solar cable. The charger port dropped from five conductors to two in September, so a plain XH-2 would have let a solar cable fit a port that feeds F1, the LDO (6 V absolute max) and the modem rail (5.4 V max). It is now an XH-5 body with BATT+ on position 1, GND on position 5 and 2–4 vacant: a 2-position housing spans only adjacent positions, so it can never bridge them, and the charger harness becomes a 5-position body that cannot enter any 3-position sensor port. Positions 2–4 are keying, not spare capacity — do not route to them, and the harness is crimped with its two contacts at the ends, not side by side.

Every cross-plug, and what it does

The keying above is only as good as the table that checks it. Re-derived 2026-09-09 for the port sizes as they stand after ADR 0014; it supersedes the residual cross-plug matrix in the rev. 3 order spec, which was computed when J5 was a populated XH-5 and J6 was XH-4. Both moved.

The whole table rests on one untested assumption: that a smaller JST-XH housing can be pushed into a larger XH shroud. Rev. 3 assumes it for the 3-position ports — that is the entire argument for the vacant centre pin — but never checked it for the 4- and 5-position ports, where it argued only “no same-size partner”. If the assumption is false, every smaller→larger cell below becomes CAN'T FIT and both surviving hazards disappear. Two minutes with connectors already in the drawer, and nothing in the tree records the answer either way.

✕ can’t fit — bigger housing, smaller shroud ○ open — a contact lands on nothing ◆ passive — connects, nothing damaged ▲ damage — a part is over its rating

Harness ↓ into port → J5 chargerXH-5 · live 1, 5 J6 modemXH-5 · all live J7 NTCXH-3 · centre vacant J8 DS18B20XH-3 · all live J9 leakXH-3 · centre vacant
SolarXH-2 · ~6.7 V○ Open1 and 5 never adjacent▲ Damage6.7 V on the modem rail, or IO16/IO17○ Openone contact on the dead centre▲ Damage6.7 V on IO4 or the 3V3 rail○ Openone contact on the dead centre
ChargerXH-5 · 3.0–4.2 Vits own port◆ Passivepack onto the modem rail, which normally carries it; GND onto IO14✕ Can't fit5-position body✕ Can't fit5-position body✕ Can't fit5-position body
ModemXH-5 · 5 wires◆ Passivesupply wire to BATT+, On/Off to GND, the rest on vacant pinsits own port✕ Can't fit5-position body✕ Can't fit5-position body✕ Can't fit5-position body
NTCXH-3 · contacts 1, 3○ Openat most one live pin reached◆ Passivea 10 kΩ thermistor bridging two pins; microampsits own port◆ Passive3V3 at both ends through R3 — no static current◆ Passivea misread; both nets are gated dividers
DS18B20XH-3 · all three○ Openno return path through the vacant pins◆ Passivesensor rated to 5.5 V; the rail is 4.2 V◆ Passivesensor ground on the vacant pin — unpoweredits own port◆ Passivesensor ground on the vacant pin — unpowered
LeakXH-3 · contacts 1, 3○ Openat most one live pin reached◆ Passivetwo hull pads with no source behind them◆ Passivea misread; both nets are gated dividers◆ Passive~0 V across the pads — no electrolysisits own port
Two hazards survive, and neither is about J5. Sizing the charger port closes every cross that involves it and stops the charger harness reaching any sensor port. What it does not touch is the solar line. The solar line is not a carrier port — it runs combiner → charger, and only its free end can wander. architecture-power-and-wiring.md calls that end a JST-XH connector; the rev. 3 spec says it is soldered. Those disagree, and which is true decides how easily either hazard can be reached at all.

6Net list (the contract)

NetFromToNotes
VBATcharger port pin 1F1 and U3 VINbattery voltage, 3.0–4.2 V. The modem rail taps here, before F1 — see §4
VBAT_FF1MCP1700 VIN, C1 (1 µF)fused battery rail
3V3_RAWMCP1700 VOUTC2 (1 µF), C3 (10 µF), JP1.1
3V3JP1.2both MCU sockets 3V3 · QW1 VCC · TPS22918 VINthe board rail
3V3_GPSTPS22918 VOUTQW2 VCCon ~minutes/day
GPS_ENMCU IO25TPS22918 ON + R1 100k→GNDrail off at boot / MCU absent
RB_ENMCU IO26U3 ON + R2 100k→GNDmodem rail must not rise in reset
SDA0/SCL0MCU IO21/IO22QW1, SOCK_BARO, + the BME280 seat (§10)always-on I²C: BME280 0x77, MAX17048 0x36, BMP581 0x47
SDA1/SCL1MCU IO18/IO19QW2 onlyswitched GPS bus — no series parts
OW_DATAMCU IO4DS18B20 port DATA + R3 4.7k→3V31-Wire
SENSE_EXCMCU IO13NTC port pin 1 · R5 100koutput; high only during reads
NTC_SENSEMCU IO34NTC port pin 3 / R4 10k→GND junctioninput-only ADC1
LEAK_SENSEMCU IO35R5 / leak port pin 1 junction + C6 100 nF→GNDinput-only ADC1; C6 fixes source impedance (τ = 10 ms)
VBAT_RBU3 VOUTJP2 pin 1switched modem rail; on ~3–24 min/day
VBAT_RB_SWJP2 pin 2RockBLOCK port pin 1to the modem's pin 8: 3.0–5.4 V straight from the pack. No bulk capacitor — the module's own supercapacitors buffer the transmit burst and must never be removed
RB_ONOFFMCU IO14RockBLOCK port pin 5the modem's sleep input; v3.D takes ordinary 3.3 V logic, so the GPIO drives it directly
RB_RX / RB_TXMCU IO17 / IO16RockBLOCK port 3 / 4ESP32 transmits on IO17
GNDsingle net, back-layer pourboth charger-port grounds join it

Spare MCU pins after this map: IO23 (bidirectional), IO36, IO39 (input-only ADC1) — IO14 left the spare list when the modem's sleep pin was wired. Nothing uses ADC2 — that's deliberate (ADC2 dies when the radio is on).

7Bill of materials on the board

Fab-placed SMD (0805 unless noted)

  • U2, U3 — TPS22918DBVR, SOT-23-6 (two: GPS rail and modem rail)
  • QW1, QW2 — JST-SH 4-pin (SM04B-SRSS-TB)
  • R1, R2, R5 — 100 kΩ · R3 — 4.7 kΩ · R4 — 10 kΩ
  • C1 — 1 µF · C2 — 1 µF · C3 — 10 µF
  • C6 — 100 nF

Hand-soldered through-hole (co-build)

  • U1 — MCP1700-3302E/TO, TO-92 (owned)
  • F1 — polyfuse, 1.1 A hold
  • JP1, JP2 — 2-pin headers + shunts
  • 5× wire ports: the charger port (2 conductors, size per PROC-16), XH-5 for the modem, 3× XH-3 for the sensors. The XH-4 this brief used to specify is gone — check any header order placed against the older list
  • 2× MCU socket strips + SOCK_BARO — machined-pin female, 2.54 mm

8Layout rules that actually matter

9Mechanical + fab

10What is still open (so it doesn't surprise you)

11Bring-up sequence the design should support

This is how every board gets verified — worth knowing while placing parts, because it defines what must be probeable:

  1. Continuity: 3V3↔GND, VBAT↔GND not shorted.
  2. JP1/JP2 out, battery on charger port → F1 passes, 3.30 V ± 0.1 at JP1 pin 1. Fit JP1.
  3. No MCU: GPS_EN and RB_EN read 0 V (pull-downs working).
  4. MCU in → 3V3 at socket → flash.
  5. I²C0 scan finds 0x77 / 0x36 / 0x47; assert IO25 → I²C1 finds the GPS; de-assert → rail collapses.
  6. DS18B20 answers on 1-Wire; NTC reads mid-scale; damp finger across leak pads drops IO35.
  7. RockBLOCK last, meter in series at JP2 (allow ~10 s after the rail comes up — the module spends that charging its supercapacitors before the Iridium side will do anything).

Questions → back to me; the full specs (with every rationale) live in the project repo under docs/superpowers/specs/. This page prints cleanly — File → Print → Save as PDF.