Skip to content
Snowbird Power Systems

Reference build

LiSOCl2 ten-year sensor

A water-meter pulse counter on a Snowbird Core 1S soldered to its carrier, running a decade on one ER14505 bobbin cell in primary mode.

A Snowbird Feather 1S resting on frosted dark stone at dawn, its amber charging LED lit, a pouch cell plugged in, winter light catching the gold castellations.

What it does

A pulse counter clipped to a water meter in an unheated utility room, reporting the count over LoRaWAN every six hours. It is installed once and not visited again. The energy store is a single ER14505 lithium thionyl chloride bobbin cell, 2.4 Ah, the kind of cell that sits in utility meters for a decade. Those cells must never see charge current, and Snowbird's primary mode is built for exactly that: the chemistry jumper's PRIMARY position holds the charger's charge-enable inactive in hardware, the firmware refuses any charge-current write, and the BMS overvoltage threshold sits just above the cell's open-circuit voltage so any current into the cell trips the protector. Three independent blocks have to fail before the cell is charged.

The Snowbird Core 1S is the connector-less population, soldered down by its castellations onto a small carrier board that holds the cell clip, the LoRa module and the pulse input. USB-C and solar still power the load through the power path if a technician ever plugs in; the cell is simply left alone.

Parts

Part Role Example
Snowbird Core 1S BMS, gauge, 3.3 V rail, primary-cell mode, as a solder-down module snowbird-core-1s
ER14505 cell, 2.4 Ah Energy store, AA size, bobbin construction Saft LS14500 or Tadiran SL-760
Hybrid layer capacitor Covers the radio burst the bobbin cell cannot Tadiran HLC-1020 on Snowbird's VBAT footprint
LoRaWAN module Uplink Seeed Wio-E5 or a Murata CMWX1ZZABZ
Pulse input The meter Reed switch on the meter's magnet, 100 k pull-up, 100 nF across
Carrier board Holds everything Two-layer, 50 × 40 mm, castellation pads for the Core
Enclosure Dust and the occasional drip ABS box, IP54

Wiring

Snowbird pin Device pin Note
3V3 castellation Carrier 3V3 plane LoRa module and MCU run from Snowbird's 3.3 V rail
GND castellations Carrier ground All of them, for the return path
SDA, SCL castellations MCU I2C Snowbird at 0x36
INT castellation MCU interrupt input Carries the TEMP_CUTOFF and BMS events; no jumper on the Core, it is a pad
EN5V castellation not connected The 5 V rail is never enabled; the internal pull-up keeps it off
VBAT pad, NTC pad, GND Cell clip +, thermistor, cell clip − The 10 k thermistor is taped to the cell
HLC footprint Hybrid layer capacitor Across VBAT, polarity marked
Chemistry jumper PRIMARY Set before the cell goes in. Charging is then disabled in hardware
USB-C pads not populated The Core ships without the connector; a technician's USB pads are on the carrier instead
Solar pads not populated

With the Core there is no Feather host and no handoff to think about: the carrier's MCU is the only load and Snowbird's rail is the only supply.

Power budget

Load Duty Average current Daily energy
MCU sleeping, counting pulses on an interrupt 100 % 2.1 µA 0.00018 Wh
LoRaWAN uplink, 14 dBm, 1.2 s four a day 1.1 µA 0.00010 Wh
Snowbird idle, no advertising 100 % 28 µA 0.0024 Wh
Cell self-discharge, 1 % a year 2.7 µA equivalent 0.00024 Wh
Total 34 µA 0.0030 Wh

The ER14505 holds 2.4 Ah at 3.6 V, about 8.6 Wh. At 34 µA that is 70,000 hours, a little over eight years; derated for the cell's own capacity loss over a decade at room temperature it comes out at 7.5 to 8 years, and at 20 µA with Snowbird's supervisor in its low-report mode (one gauge update an hour, which this application can live with) the arithmetic reaches eleven years. The gauge is told the capacity at install, counts every microamp-hour out, and the time-to-empty it reports is the number the maintenance schedule uses.

Sketch

#include <Wire.h>
#include <Snowbird.h>
#include <LoRaWAN.h>

Snowbird pmic;
volatile uint32_t pulses = 0;

void onPulse() { pulses++; }

void setup() {
  Wire.begin();
  pmic.begin(Wire);

  // Primary cell. The jumper is in PRIMARY; this call confirms it and the
  // library refuses every charge-current write from here on.
  pmic.setChemistry(Chem::LiSOCl2);
  pmic.setCapacity_mAh(2400);                 // the gauge counts out from this
  pmic.setReportInterval(3600);               // one gauge update an hour
  pmic.set5V(false);
  pmic.setTempLimits(TempLimits::discharge(-40, 85));

  // First power-up on a shelf-aged cell: a short depassivation load so the
  // gauge does not read the voltage dip as an empty cell.
  if (pmic.firstBoot()) {
    pmic.depassivate(/*mA*/ 30, /*seconds*/ 20);
  }

  pmic.onEvent(TEMP_CUTOFF | BMS_TRIP, [](uint32_t ev) {
    LoRaWAN.sendAlert(ev);
  });

  pinMode(PULSE_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PULSE_PIN), onPulse, FALLING);

  LoRaWAN.begin(US915);
  LoRaWAN.joinOTAA(APP_EUI, DEV_EUI, APP_KEY);
}

void report() {
  noInterrupts();
  uint32_t count = pulses;
  interrupts();

  Uplink u;
  u.pulses = count;
  u.soc = pmic.soc();
  u.voltage_mV = pmic.voltage_mV();
  u.timeToEmpty_h = pmic.timeToEmpty();
  u.cell_C = pmic.batteryTemp_C();
  LoRaWAN.send(&u, sizeof(u));                 // ~1.2 s; the HLC supplies the burst
}

void loop() {
  report();
  deepSleep(6 * 3600);                         // wakes on the pulse interrupt too
}

Field notes

The first cell out of the drawer had been on a shelf for three years. On first power-up its voltage dipped to 3.1 V under a 30 mA load and recovered to 3.6 V over about fifteen seconds: passivation, the lithium chloride film that forms on a stored thionyl chloride cell. Without the depassivation step the gauge would have logged that dip as a near-empty cell on day one. With it, the gauge saw a full cell and the time-to-empty started where it should.

The hybrid layer capacitor is not optional. A bobbin cell is happy at 100 mA continuous and unhappy at the 400 mA a LoRa transmit at 14 dBm pulls for a second. The first carrier was built without the capacitor to see what would happen: the 3.3 V rail held, because Snowbird's regulator is a buck-boost and rides the cell down to 2.0 V, but the cell voltage sagged to 2.4 V during each uplink and the gauge's current reading swung. With the capacitor fitted the cell sees a 90 mA average over the burst and the voltage barely moves.

The temperature window is wide on purpose. LiSOCl2 is rated to minus fifty-five; the board's own parts limit it to minus forty, and the firmware's discharge limits are set to that. In the test room, which touched minus eight in February, nothing happened, which is the result.

Fourteen months in, the gauge reads 88 % and the time-to-empty reads 8.1 years. The counted charge out matches the budget to within 4 %, with the difference being the uplink retries during a week when the gateway was down.

Primary mode is the one setting on the board that cannot be changed from software, and that is deliberate. A technician with a USB-C cable can power the node, read the gauge and update the firmware; they cannot, from any interface, put current into the cell.