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:
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.
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.
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
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 assemblythe carrier PCBplug-in module
4What the board actually does
Functionally the carrier is four things:
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.
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.
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.
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.
Port
Type
Pin order (1→n)
Goes to
Charger
XH-5, three positions vacant
BATT+ · — · — · — · GND
bq25185 board (cable)
RockBLOCK
XH-5
VBAT · GND · RX · TX · On/Off
modem (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
DS18B20
XH-3
DATA · GND · 3V3 — this order is deliberate keying, keep it
waterproof temp probe
NTC
XH-3, centre pin vacant
IO13-node · — · IO34-node
10 kΩ NTC at battery pack
Leak
XH-3, centre pin vacant
sense · — · GND
two pads on the hull wall
QW1 / QW2
JST-SH 4-pin (Qwiic), SMD
standard Qwiic
QW1 → MAX17048 fuel gauge only; QW2 → GPS. The BME280 is a header board, not Qwiic — see §10
JP1 / JP2
2-pin 2.54 header + shunt
in-line in 3V3 / in the switched modem rail
metering + 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 V
—its 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 pins
—its 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; microamps
—its 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 — unpowered
—its 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 electrolysis
—its 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.
solar → J8 — already recorded in rev. 3. The
DS18B20 port must be fully populated, so it has no dead pin to absorb an offset.
~6.7 V reaches IO4 (3.6 V max) or the 3V3 rail. Mitigated only by
colour-coded housings and by both ends of the solar line being committed.
solar → J6 — new, and previously undocumented.
ADR 0014 gave the modem port a fifth wire; the old matrix cleared the 4- and
5-position ports on the grounds that no same-size partner existed, and never
evaluated a smaller housing going in. ~6.7 V reaches the modem rail
(5.4 V max) or IO16/IO17 (3.6 V max). No mitigation recorded.
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)
Net
From
To
Notes
VBAT
charger port pin 1
F1 and U3 VIN
battery voltage, 3.0–4.2 V. The modem rail taps here, before F1 — see §4
to 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_ONOFF
MCU IO14
RockBLOCK port pin 5
the modem's sleep input; v3.D takes ordinary 3.3 V logic, so the GPIO drives it directly
RB_RX / RB_TX
MCU IO17 / IO16
RockBLOCK port 3 / 4
ESP32 transmits on IO17
GND
single net, back-layer pour
both 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).
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
Two I²C buses is a hard requirement, not tidiness. If
the GPS shared the always-on bus, the bus pull-ups would backfeed
~2 mA through its ESD diodes whenever its rail is off — tripling the
probe's total consumption. I²C1 must reach QW2 and nothing else.
The modem path carries ~500 mA, not 1.3 A.VBAT → U3 → JP2 → RockBLOCK port. The 1.3 A figure in
circulation is the bare 9603N module's burst; the RockBLOCK board hides it
behind its own supercapacitors and the supply never sees more than
470 mA. Size the run for that and keep it short — the whole
point of tapping ahead of F1 is voltage margin, and trace
resistance spends the same margin the polyfuse would have.
Leakage is the enemy everywhere else. No LEDs, no
"power" indicators, no dividers hanging on a rail. Anything that draws
standing current on 3V3 or VBAT blows the µA budget.
R1/R2 pull-downs must be genuinely on the gate nets so
GPS and modem rails stay down with no MCU inserted (bring-up tests this
explicitly).
All SMD on the top side — JLCPCB economic assembly
constraint. Through-hole can go anywhere sensible.
JP1 and JP2 are measurement points, not debug leftovers.
Shunt fitted = normal. Shunt off = rail broken (JP1 doubles as the
"never battery + USB together" interlock). Meter across the pins =
in-line current measurement. Keep them reachable.
Generous pads, silk everything. This is a
parent-and-child co-build; the through-hole side gets hand-soldered by
beginners. Label every port with name and pin-1 marker.
9Mechanical + fab
Outline ≤ 100 × 80 mm (verified to fit the hull with
~26 mm to spare). 2-layer, 1.6 mm FR-4.
4 × M3 mounting holes — pattern must be agreed with the
enclosure side before ordering (an outline + holes DXF is one of your
deliverables; the printed mounting platform is designed against it).
The charger board mounts next to the carrier on its own
standoffs — leave nothing on the carrier for it except the XH-5 port.
Fab plan: JLCPCB, 5 boards, economic PCBA for the SMD side, parts from
the LCSC catalog (TPS22918DBVR and SM04B-SRSS-TB are stocked; verify at
order time). Deliverables: the editable source project in your EDA tool's
native format, Gerbers, BOM CSV, CPL, DXF.
10What is still open (so it doesn't surprise you)
How the BME280 attaches (PROC-17) — found 2026-09-09 and
it touches your layout. The owned board is SparkFun SEN-13905,
with 0.1 in headers — not the Qwiic SEN-15440 formerly
recorded here, a different board. Nothing electrical moves — same sensor,
same 0x77, same I²C0 — but it cannot plug into QW1, which
now carries the MAX17048 alone. Either a Qwiic-to-header cable off that
chain (no board change, but it gives up the keying Qwiic was chosen for),
or a SOCK_BME 4-pin female header alongside
SOCK_BARO — the same treatment the BMP581 already gets, and
nearly free while the board is unfabricated. You will get a
decision, not a guess; assume the socket if you need to place
something now.
Module socket dimensions. We measure the physical
DevKit (30 vs 38 pin, row spacing) and FireBeetle (header spacing,
2.0 mm mounting holes) with calipers and send you the numbers — don't
trust downloaded drawings for these two footprints.
Mounting-hole pattern — settled together with the
enclosure side (see §9).
Charger port size (PROC-16) — the one open item that
touches your layout. Two conductors is settled; the connector family and
size are not, because dropping to two would collide with the solar
cable's keying. See the second warning in §5; you will get a decision,
not a guess.
Charger identity — settled 8 September: bq25185 (#6106).
Irrelevant to your layout either way, since the charger stays a
cable-connected port.
Order gate: before Gerbers go out, the same netlist is
being proven on a hand-wired protoboard. Any change it finds
back-propagates to the net table above — you'll get a diff, not a
surprise.
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:
Continuity: 3V3↔GND, VBAT↔GND not shorted.
JP1/JP2 out, battery on charger port → F1 passes, 3.30 V ± 0.1 at JP1
pin 1. Fit JP1.
No MCU: GPS_EN and RB_EN read 0 V
(pull-downs working).
DS18B20 answers on 1-Wire; NTC reads mid-scale; damp finger across leak
pads drops IO35.
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.