Repository navigation
Add low-power pump-handle odometer counter #6
Description
Activity
Sourcing note for the counter IC:
Best current bare-IC source looks like DigiKey for
S-35770E01I-K8T2U:- DigiKey product page: https://www.digikey.com/en/products/detail/ablic-inc/S-35770E01I-K8T2U/9974496
- DigiKey part numbers:
1662-3409-1-NDcut tape,1662-3409-6-NDDigi-Reel,1662-3409-2-NDtape and reel - Manufacturer: ABLIC Inc.
- Description:
Counter IC Binary Counter 1 Element 24 Bit 8-TMSOP - Confirmed stock seen: 1,036 units
- Small-quantity price seen: about $6.29 each, with lower pricing at 10/25/100 qty
Mouser also appears to list the same MPN, but DigiKey's page was directly accessible and showed stock/price clearly.
For a quicker bench prototype, MikroE's
Counter 2 Clickboard is also worth considering because it is based on the S-35770 and already provides a small module:- https://www.mikroe.com/counter-2-click
- Search result showed it in stock around $23
Recommendation: order a handful of bare ICs from DigiKey plus one Counter 2 Click module if we want to validate firmware/I2C behavior before spinning or hand-wiring a tiny breakout.
Circuit/BOM note:
For a first custom breakout around
S-35770E01I-K8T2U, the minimal circuit is small, but the input conditioning matters because a reed switch can bounce and the counter will be awake even when the ESP32 is asleep.Likely required parts:
S-35770E01I-K8T2Ucounter IC.- TMSOP-8 breakout or small PCB footprint.
- 0.1 uF ceramic decoupling capacitor from VCC to GND placed close to the IC.
- I2C pull-ups on SDA and SCL to 3.3 V. Start with 4.7k-10k for normal I2C; higher values may work at slower bus speeds if lowering current is important.
/RSTpull-up to 3.3 V, suggested starting range 30k-100k. Optionally also route/RSTto an ESP32 GPIO for firmware-controlled counter reset.CLKINpull-up to 3.3 V for a passive reed-switch input. Start around 100k if low current while the switch is closed matters; adjust after testing edge reliability.- Connector pads/header for sensor input, 3.3 V, GND, SDA, SCL, and optional reset/loop lines.
Strongly recommended / design-dependent parts:
- Input debounce or conditioning for reed switch / mechanical contact input. Without this, one pump stroke may count as several edges. Options include:
- RC filter on
CLKINusing the pull-up plus a small capacitor to GND, validated on a scope. - A low-power Schmitt-trigger buffer after the RC filter if the S-35770 input dislikes slow edges.
- A dedicated debounce IC only if the current budget allows it.
- RC filter on
- Small series resistor on the external
CLKINline, roughly 100 ohm-1k, for input protection/noise damping. - ESD/TVS protection if the sensor wire is long, exposed, or routed outside the enclosure.
- Optional
LOOPconnection to an ESP32 input for overflow detection. Otherwise leave it unconnected as suggested. - Test pads for SDA, SCL, CLKIN, RST, VCC, and GND.
Open design cautions:
- If the sensor is an IR module instead of a reed switch, it likely consumes far more than the 10 nA counter IC and may dominate the sleep-power budget unless duty-cycled or otherwise designed for always-on use.
- The CLKIN pull-up value is a tradeoff: lower resistance gives sharper edges/noise immunity, higher resistance reduces closed-switch current.
- Debounce should be bench-tested with real pump-handle motion or a representative switch, because the counter will count bounce pulses while the ESP32 is asleep.
Draft S-35770 Counter Breakout Schematic
This is a first-pass schematic-style wiring sketch for a bare
S-35770E01I-K8T2Ubreakout connected to the Lilygo / ESP32 at 3.3 V.+3.3 V | +-------------------------------+ | | C1 0.1 uF | | | GND | | U1: ABLIC S-35770E01I-K8T2U | +--------------------------------+ | | | | +3.3 V --| 8 VCC GND 4|--------+---- GND | | | | +3.3 V --/\/\/--+---------------- /RST 1 | R3 30k-100k | | o optional ESP32 reset GPIO | | | | +3.3 V --/\/\/--+---------------- CLKIN 3 | R4 about 100k | | | | +----/\/\/----o sensor input | R5 100R-1k reed switch / open-drain pulse | closes or pulls low to GND ----- C2 optional ----- debounce cap | GND | | ESP32 SDA o----+---------------- SDA 6/7 | | | +3.3 V --/\/\/-- | R1 4.7k-10k | | ESP32 SCL o----+---------------- SCL 6/7 | | | +3.3 V --/\/\/-- | R2 4.7k-10k | | optional ESP32 input <----------- LOOP 5 | | NC / leave open -------------------- NC 2 | | | +--------------------------------+ Optional front-end for long or noisy sensor leads: sensor input o----/\/\/----+-----> CLKIN node above R5 100R-1k | +---- TVS/ESD clamp ---- GND | ----- optional C2 ----- debounce cap | GND If the RC edge is too slow or bounce is still visible: sensor / RC node ----> low-power Schmitt trigger ----> U1 CLKINPin / Net Table
S-35770 pin Net Draft connection 1 /RSTReset Pull up to 3.3 V with 30k-100k; optionally route to ESP32 GPIO for firmware reset.2 NCNot connected Leave open. 3 CLKINStroke input Pull up to 3.3 V; sensor pulls low through optional series/protection/debounce network. 4 GNDGround Common ground with Lilygo / ESP32. 5 LOOPOverflow flag Leave open, or route to ESP32 input/test pad if overflow detection is desired. 6/7 SDA/SCLI2C Connect to ESP32 I2C pins with pull-ups to 3.3 V. Confirm exact pin order from datasheet footprint before layout. 8 VCCSupply 3.3 V rail, with 0.1 uFceramic cap to GND close to the IC.Draft BOM
Ref Part Starting value / note U1 ABLIC counter IC S-35770E01I-K8T2U, 8-TMSOP.C1 Decoupling capacitor 0.1 uFceramic, close to U1.R1 SDA pull-up 4.7k-10kto 3.3 V.R2 SCL pull-up 4.7k-10kto 3.3 V.R3 /RSTpull-up30k-100kto 3.3 V.R4 CLKINpull-upStart around 100k; tune for edge reliability vs. closed-switch current.R5 CLKINseries resistor100 ohm-1k, optional but useful for damping/protection.C2 Debounce capacitor Optional; size by bench test with the real switch and stroke speed. U2 Schmitt trigger buffer Optional low-power part if RC debounce creates slow edges. D1 ESD / TVS protection Optional, recommended for long or exposed sensor wires. J1 Lilygo connector 3.3 V, GND, SDA, SCL, optional RST, optional LOOP. J2 Sensor connector Sensor input and GND; optionally 3.3 V if using an active sensor. Layout / Test Notes
- Keep C1 very close to U1 VCC/GND.
- Put test pads on
SDA,SCL,CLKIN,/RST,VCC, andGND. - If the handle sensor is a passive reed switch, debounce must be validated so one stroke does not become several counts.
- If the handle sensor is an IR module, budget its always-on current separately; it may dominate sleep power.
- Confirm the exact
SDA/SCLpin numbering from the datasheet/package before PCB layout.
Planning update from the Counter 2 Click / IR handle-stroke discussion:
Desired event model
The external counter should behave as a handle-stroke odometer that keeps counting while the ESP32 sleeps:
- User starts pumping. The IR/reflection/break-beam sensor produces one pulse per handle stroke, and the counter increments without waking the ESP32.
- Float switch rises when water starts flowing. ESP32 wakes, logs start time, reads the current handle-stroke odometer, and records how many strokes it took to reach flow.
- ESP32 sleeps again while water continues flowing. Handle strokes keep accumulating in the external counter.
- Float switch drops when flow ends. ESP32 wakes, logs stop time, reads the odometer again, computes flow duration, computes handle strokes during flow, and derives strokes/min during the water-flow interval.
- ESP32 reports raw/delta stroke counts plus derived metrics, then sleeps until the next cycle.
This accepts that a few failed/play strokes before water starts may inflate “strokes to water” occasionally. Reporting/backend should treat those as field noise rather than assume every priming count is perfectly meaningful.
Counter 2 Click findings
MikroE’s open-source
Counter 2 Clickdriver confirms this is an I2C-type Click board based onS-35770E01I-K8T2U:- I2C address:
0x32. - Counter read: 24-bit value over I2C.
- Overflow/rollover threshold:
16,777,216counts. - mikroBUS pins used by the driver:
SCL,SDA,RST, andINTasLOOP. - The driver does not map SPI or UART pins for this Click.
- The driver does not use a mikroBUS pin for the pulse input, so the IR/reed/break-beam signal should feed the counter board/chip input directly, not an ESP32 interrupt pin.
Source:
MikroElektronika/mikrosdk_click_v2,clicks/counter2/lib_counter2/include/counter2.handsrc/counter2.c.WaterPAL / Lilygo IO audit from current firmware
Current firmware pin allocation:
- GPIO 34: float switch wake input.
- GPIO 32: DHT sensor.
- GPIO 4: SIM7000 power control.
- GPIO 25: SIM7000 DTR.
- GPIO 26/27: SIM7000 UART via
Serial1(PIN_RX/PIN_TX). - GPIO 21/22: listed as default
WireSDA/SCL in config comments; no current firmware use ofWirefound. - GPIO 33 and 35 are listed/commented as open in the config comments.
Answer to the first IO question: yes, we appear to have the needed IO for Counter 2 Click.
Recommended first wiring:
- Counter 2
SDA-> ESP32 GPIO 21. - Counter 2
SCL-> ESP32 GPIO 22. - Counter 2
3.3VandGND-> Lilygo 3.3V/GND. - Counter pulse input -> IR sensor output/open-drain output directly into the counter board/chip input, with appropriate pull-up/conditioning.
- Optional Counter 2
RST-> an available ESP32 output such as GPIO 33, or leave under board/pull-up control if the board supports that and use software reset over I2C when sufficient. - Optional Counter 2
LOOP/mikroBUSINT-> an available ESP32 input such as GPIO 35 if we want overflow tracking. Overflow is probably rare, but this gives a clean path to lifetime odometer accounting.
Serial-line concern: Counter 2 Click does not need mikroBUS UART. The WaterPAL modem already occupies GPIO 26/27 on
Serial1, while USB debug uses the primarySerial. Since this Click only needs I2C plus optional reset/loop GPIO, it should not conflict with the USB debugger or modem serial lines. If we build a full mikroBUS adapter later, leave mikroBUSTX/RXunconnected or route them only to clearly unused pins, not 26/27.Planning implications
For the first bench prototype, I would not wire a full mikroBUS socket one-to-one. A small adapter harness is enough: 3.3V, GND, SDA, SCL, optional RST, optional LOOP, and the separate sensor input to the counter board. This keeps us off the SIM7000 UART pins and avoids unnecessary SPI/UART routing.
Firmware work needed next:
- Add a
waterpal_countermodule using ArduinoWireon GPIO 21/22. - Read the 24-bit count from I2C address
0x32on every wake before/after float-edge handling. - Persist last counter readings in RTC memory:
- count at flow start
- count at flow end / last seen count
- optional last LOOP state
- On float rising/start-flow wake: save
flow_start_time_sandflow_start_stroke_count. - On float falling/end-flow wake: compute
flow_duration_s,flow_stroke_delta, andstrokes_per_min = delta * 60 / duration. - Add daily/reporting fields for at least raw lifetime/daily stroke delta; optionally add per-flow metrics once backend schema is ready.
- Decide whether to ever reset the hardware counter. My leaning is to avoid routine resets and treat it as a monotonic odometer, handling 24-bit wrap in firmware.
Hardware validation needed:
- Confirm the physical Counter 2 Click pulse input connector/pad and whether the board already includes
CLKINpull-up/debounce. - Measure IR module current. Commodity reflective obstacle modules can draw far more than the counter IC, so always-on IR sensing may dominate sleep power.
- Bench-test the chosen sensor arrangement for one clean pulse per handle stroke. If the output chatters, add pulse shaping/debounce before the counter input.
- Verify Counter 2 readout from ESP32 at 3.3V using 100 kHz I2C first; lower I2C speed only if pull-up/current choices require it.
Click Snap follow-up:
Counter 2 Click advertises a snap-off counting module with access to the relevant signal pins. Based on MikroE's driver pin map, WaterPAL does not appear to need anything from the full-size mikroBUS carrier except prototype convenience:
- Required host signals are
3.3V,GND,SDA,SCL. - Optional host signals are
RSTandLOOP/INT. - The handle sensor/pulse line feeds the counter input directly.
- SPI and UART pins on the full mikroBUS footprint are unused for this Click.
Recommendation:
- For bench bring-up, keep the full Counter 2 Click intact. The larger board is useful as a labeled, mechanically stable breakout and makes probing/wiring easier.
- For an installed WaterPAL prototype or final-ish build, prefer the smaller Click Snap module if inspection confirms it retains the counter IC, decoupling, pull-ups/required passives,
CLKIN/pulse input access,RST,LOOP, I2C, power, and ground. - The larger carrier does not appear electrically necessary for WaterPAL unless it contains support circuitry not present on the snapped module, such as pull-ups, level shifting, input conditioning, or a more convenient sensor connector. That should be verified by schematic/continuity check once the board is in hand.
Practical path: buy/use the full board for first firmware validation, but plan the harness/PCB around the Snap module pinout so we are not forced to carry the full mikroBUS footprint into the enclosure.
- Required host signals are
Click Snap follow-up:
Counter 2 Click advertises a snap-off counting module with access to the relevant signal pins. Based on MikroE's driver pin map, WaterPAL does not appear to need anything from the full-size mikroBUS carrier except prototype convenience:
- Required host signals are
3.3V,GND,SDA,SCL. - Optional host signals are
RSTandLOOP/INT. - The handle sensor/pulse line feeds the counter input directly.
- SPI and UART pins on the full mikroBUS footprint are unused for this Click.
Recommendation:
- For bench bring-up, keep the full Counter 2 Click intact. The larger board is useful as a labeled, mechanically stable breakout and makes probing/wiring easier.
- For an installed WaterPAL prototype or final-ish build, prefer the smaller Click Snap module if inspection confirms it retains the counter IC, decoupling, pull-ups/required passives,
CLKIN/pulse input access,RST,LOOP, I2C, power, and ground. - The larger carrier does not appear electrically necessary for WaterPAL unless it contains support circuitry not present on the snapped module, such as pull-ups, level shifting, input conditioning, or a more convenient sensor connector. That should be verified by schematic/continuity check once the board is in hand.
Practical path: buy/use the full board for first firmware validation, but plan the harness/PCB around the Snap module pinout so we are not forced to carry the full mikroBUS footprint into the enclosure.
- Required host signals are
Click Snap pin-label caution from board photo:
The underside photo shows the Click Snap section exposing what appear to be
GND,VCC,SDA,SCL,NC,NC,LP, andRST.Important interpretation:
LPis probably the S-35770LOOPsignal, not the pulse/count input. This matches MikroE's driver, which mapsLP/LOOPto mikroBUSINTand treats it as the rollover/loop output. It should be useful for detecting 24-bit counter rollover, but it is not the normal handle-stroke pulse input.That means the remaining hardware question is: where is
CLKINexposed for the external handle sensor?From the photo alone, the Snap header gives us nearly all host/readout signals, but I do not see a clearly labeled
CLK,CNT,IN, orCLKINpin on the Snap section. Before committing to the snapped-off module, verify continuity/schematic for S-35770 pin 3 (CLKIN) to one of:- a Snap header pin, possibly one of the
NC-labeled pads if the silkscreen is generic/ambiguous; - a full-size mikroBUS pin such as
CS, if MikroE used it as an unmanaged pulse input; - a separate pad, button, terminal, or test point on the board.
Updated recommendation: the Snap module still looks excellent for the ESP32 side (
VCC,GND, I2C, optionalRST, optionalLOOP), but it only gives us everything we need ifCLKINis accessible for the IR/reed/break-beam sensor. IfCLKINis only available on the full carrier or an inconvenient pad, we should either keep the full board for prototypes or solder directly to the counter input/test pad.- a Snap header pin, possibly one of the
Click Snap top-side photo follow-up / correction:
The top-side photo appears to answer the earlier
CLKINquestion. The Snap section has a clearly labeledINpad near the top-left of the small module. That is very likely the external pulse/count input to the S-35770 (CLKIN).So the snapped-off module appears to expose the complete set of signals WaterPAL needs:
GNDVCCSDASCLRSTLP/LOOProllover outputINpulse input for the handle sensor
The full carrier board still appears useful for bench work because it provides the mikroBUS headers, larger solder/probe points, voltage-selection convenience, and visible indicators such as
PWR/LOOP. It may also include carrier-side parts for LEDs, level/voltage selection, or interface convenience.For WaterPAL deployment, the carrier-side features are probably not useful and may be undesirable:
- WaterPAL is a 3.3 V system, so 5 V/mikroBUS voltage-selection support is not needed once wiring is fixed.
- Power/status LEDs are not helpful in an installed low-power device and can waste current if left populated/powered.
- The full mikroBUS footprint carries unused SPI/UART/extra pins and adds enclosure volume.
- The Snap module already appears to include the counter IC, local passives, I2C, reset, loop, and pulse input.
Updated recommendation: use the full board intact for first bench validation, then use the Click Snap section for any installed prototype/final harness, assuming a quick continuity/schematic check confirms
INis S-35770CLKINand the Snap section retains the needed pull-ups/decoupling. If ultra-low sleep current matters, also check whether any onboard indicator LEDs remain connected on the Snap section and depopulate/cut them if needed.Draft implementation plan for Counter 2 Click / Click Snap handle-stroke counting
Executive pin summary
Recommended installed wiring, assuming the Click Snap section is used and
INconfirms as S-35770CLKIN:Counter 2 Click Snap pin WaterPAL / Lilygo ESP32 connection Required? Purpose / notes GNDESP32 / WaterPAL ground Yes Common ground. VCC3.3 V rail Yes Use 3.3 V, not 5 V, for ESP32-compatible I2C and sensor logic. SDAGPIO 21 ( WireSDA)Yes I2C data, address 0x32. Add/keep suitable pull-up to 3.3 V.SCLGPIO 22 ( WireSCL)Yes I2C clock. Add/keep suitable pull-up to 3.3 V. INHandle sensor pulse output Yes Counter pulse input. Sensor should produce one clean active edge per handle stroke. Confirm continuity to S-35770 CLKIN.RSTGPIO 33, or pull-up-only/no-connect if board handles reset Optional but recommended Allows ESP32 hardware reset of the counter during test/commissioning. Avoid routine resets if treating count as odometer. LP/LOOPGPIO 35 input, or no-connect Optional Rollover/loop output for detecting 24-bit wrap. Useful for long-term odometer accounting. Pins to avoid / not needed:
- Do not use GPIO 26/27; those are SIM7000
Serial1. - Do not use USB debug serial for this feature.
- Do not route unused mikroBUS UART/SPI pins unless a future carrier board needs them.
- Existing GPIO 34 float switch and GPIO 32 DHT remain unchanged.
Hardware assumptions to verify
Before finalizing the harness/PCB:
- Confirm
INon the Snap board connects to S-35770CLKIN. - Confirm the Snap section includes required decoupling and pull-ups, or add them externally.
- Confirm whether
RSTalready has a pull-up. If not, add one or drive it from ESP32 with a safe default high state. - Confirm I2C pull-ups are present and to 3.3 V. If not, add external pull-ups, likely starting around 4.7k-10k for bench validation.
- Measure sleep current with the Snap section installed. Remove/cut any indicator LED path that remains powered in deployment.
- Measure the chosen IR sensor module current separately. Commodity reflective modules may dominate the power budget if always on.
- Scope or logic-analyzer the sensor output during representative handle motion. Add RC/Schmitt/debounce/pulse shaping if one stroke produces multiple count edges.
Firmware changes
1. Add counter configuration
In
waterpal_config.h, add feature flags and pin constants:WATERPAL_USE_HANDLE_COUNTERWATERPAL_COUNTER_I2C_ADDRESS=0x32WATERPAL_COUNTER_SDA_PIN=21WATERPAL_COUNTER_SCL_PIN=22WATERPAL_COUNTER_RST_PIN=33if wiredWATERPAL_COUNTER_LOOP_PIN=35if wired- optional
WATERPAL_COUNTER_I2C_SPEED_HZ, starting at100000
2. Add a small counter module
Create
waterpal_counter.h/ implementation following current header-style firmware patterns.Minimum API:
counter_setup()initializesWireand optionalRST/LOOPpins.counter_read_raw(uint32_t *count)reads the 24-bit counter value from I2C address0x32.counter_read_loop()returns optionalLP/LOOPpin state if wired.counter_delta_24bit(previous, current)computes deltas across 24-bit wrap.- Optional
counter_reset()for bench/commissioning only.
Implementation notes from MikroE driver:
- Read current counter by reading 3 bytes from device address
0x32. - Treat the raw counter as 24-bit, range
0to16,777,215. - If
LOOPis not wired, handle single-wrap deltas with modulo math and assume we read often enough to avoid multiple wraps between reads. - If
LOOPis wired, use it to detect rollover state changes for long-term accounting.
3. Add RTC-persisted state
Add
RTC_DATA_ATTRfields near the existing water-usage state:last_handle_counter_rawtotal_handle_strokesdaily_handle_strokesflow_start_handle_counter_rawflow_start_handle_totallast_flow_handle_strokeslast_flow_strokes_per_minstrokes_to_water_flow- optional
last_counter_loop_state - optional
counter_read_fail_count
Prefer monotonic lifetime/daily totals in firmware rather than resetting the hardware counter routinely.
4. Read counter on every wake
In
setup(), after basic serial/debug setup and beforedoLogWaterInput()computes edge behavior:- initialize I2C/counter module;
- read current counter;
- compute delta from
last_handle_counter_raw; - update
total_handle_strokesanddaily_handle_strokes; - update
last_handle_counter_rawonly after a successful read; - log failures but do not block water-time logging if the counter is missing.
5. Integrate with float switch edge handling
In
doLogWaterInput():- On water-flow start edge, save
flow_start_time_s,flow_start_handle_counter_raw, and/orflow_start_handle_total. - Compute
strokes_to_water_flowas the delta between the last no-flow baseline and flow-start total. If no baseline exists, mark unknown/zero. - On water-flow end edge, compute:
flow_duration_slast_flow_handle_strokeslast_flow_strokes_per_min = strokes * 60 / duration
- Guard against zero/negative duration and invalid counter reads.
Terminology note: existing code uses
WATERPAL_FLOAT_SWITCH_INVERTto define which logical state means water is flowing. Keep the new stroke logic tied to that same water-on/water-off abstraction, not hardcoded rising/falling language.6. Reporting changes
Add fields in phases to avoid breaking receivers:
Phase A, lowest risk:
- include
daily_handle_strokesin HTTP reporting and/or the existing SMS placeholder currently labeledFlutter Count (TODO); - preserve existing packet version until receiver compatibility is checked, or bump packet version if adding fields to SMS.
Phase B:
- report
last_flow_handle_strokes,last_flow_strokes_per_min, andstrokes_to_water_flow. - decide backend storage names and units:
dailyHandleStrokeslastFlowHandleStrokeslastFlowStrokesPerMinutestrokesToWaterFlow- optional
totalHandleStrokes
Phase C:
- add backend/schema/app updates so these fields are visible and robust to noisy priming/play strokes.
7. Sleep behavior
No new ESP32 wake source is needed for handle strokes. The counter remains awake and counts while the ESP32 sleeps. Existing wake sources remain:
- float switch edge on GPIO 34;
- timer wake for scheduled reads/SMS.
Do not wake the ESP32 per handle stroke.
Suggested implementation order
- Bench-wire full Counter 2 Click first: 3.3 V, GND, SDA 21, SCL 22,
INfrom a button/signal generator/sensor output, optionalRST33, optionalLP35. - Add
waterpal_countermodule with a simple serial debug read of raw count. - Verify raw count increments while ESP32 code is idle/asleep.
- Add RTC delta accounting and wrap-safe delta math.
- Integrate flow-start/flow-end metrics into
doLogWaterInput(). - Add daily stroke count to existing SMS/HTTP report path.
- Validate with bench test sequences:
- strokes before flow start;
- flow start, strokes during flow, flow end;
- no counter connected;
- counter wrap simulation;
- sleep current measurement with counter and sensor.
- Move from full board to Click Snap harness once
IN/pull-ups/current are verified.
Open decisions
- Should
RSTbe wired to GPIO 33, or should reset be hard-pulled and only software/reset-command behavior be used? - Is
LP/LOOPworth wiring to GPIO 35 for long-term odometer rollover tracking? - Which sensor is first: reflective IR module, break-beam IR, reed switch, Hall sensor, or another low-power option?
- What is the acceptable current draw for always-on handle sensing?
- Should the first public report contain only daily stroke delta, or also per-flow derived metrics?
- Do not use GPIO 26/27; those are SIM7000
Reporting-plan refinement from bucket/session discussion:
For the first handle-counter implementation, keep reporting aggregate rather than bucket/session-level. The useful near-term daily fields should be:
total_daily_handle_strokes: all handle strokes counted during the report period, including dry/priming strokes and strokes while water is flowing.total_flowing_water_strokes: only handle strokes counted while the float switch says water is actively flowing.average_strokes_to_water_flow_from_dry: average number of dry/priming strokes needed before water starts flowing, but only for starts that follow a long enough inactive/drain period.
Add a configuration parameter:
WATERPAL_MIN_DRY_DRAIN_TIME_S
Recommended starting default:
240seconds, or perhaps60seconds if field testing shows the pump drains/loses prime quickly. This should be configurable because the right value may vary by pump, plumbing, float-switch geometry, and user behavior.Reasoning:
If users swap buckets/workers and water stops flowing for only a second or two, the pump may still be primed. The next flow-start event should not be treated as a true dry start, and should not feed the dry-start average. Only if the float switch has been inactive for at least
WATERPAL_MIN_DRY_DRAIN_TIME_Sshould the next flow-start event update dry-start totals.Suggested aggregate counters for firmware:
daily_handle_strokes_totaldaily_flowing_handle_strokes_totaldaily_dry_start_strokes_totaldaily_dry_start_count- derived at report time:
average_strokes_to_water_flow_from_dry = daily_dry_start_strokes_total / daily_dry_start_count
This gives us the predictive-maintenance signals we need soon without creating lots of per-bucket/per-session data. Rich bucket/session-level reporting is tracked separately in #7.
Naming/reporting refinement:
Use the shorter derived field name:
average_dry_start_strokes
But prefer reporting the raw aggregate pieces as well, so clients/backend can calculate or recalculate the average:
dry_start_count: number of qualifying dry starts during the report period.dry_start_strokes_total: total priming/dry strokes across those qualifying dry starts.- derived:
average_dry_start_strokes = dry_start_strokes_total / dry_start_countwhendry_start_count > 0.
This is more flexible than only reporting the average. It lets the receiver handle divide-by-zero, confidence/weighting, weekly/monthly aggregation, and future changes to display logic without losing information.
Suggested near-term daily aggregate report fields are now:
total_daily_handle_strokestotal_flowing_water_strokesdry_start_countdry_start_strokes_total- optional/derived
average_dry_start_strokes
The dry-start qualification should still use
WATERPAL_MIN_DRY_DRAIN_TIME_Sso quick bucket swaps or worker handoffs do not count as true dry starts.Field naming convention update:
Use feature-first names so related fields group together alphabetically and stay easy to scan in schemas, spreadsheets, logs, and autocomplete.
For dry-start reporting, use:
dry_start_countdry_start_strokes_totaldry_start_strokes_avg
dry_start_strokes_avgis a derived field:dry_start_strokes_avg = dry_start_strokes_total / dry_start_countwhendry_start_count > 0.
This supersedes the earlier suggested name
average_dry_start_strokes.Apply the same style to future handle-stroke fields where practical: feature/context first, measurement/aspect later.
Implementation note on reset and overflow behavior:
The firmware should follow the existing reporting convention for handle aggregate fields: after a successful regular report, reset the report-period handle totals to zero.
The important guardrail is that reset should only clear report-period aggregates, not the running state needed to survive mid-bucket reports. Preserve:
- last raw 24-bit counter reading;
- whether the previous water state was flowing;
- active dry-start candidate stroke count, if currently waiting for water to start;
- last water-flow end time / drain-threshold state.
That way, if a scheduled report fires while water is flowing, future handle strokes in the same bucket/session are counted after the report without losing the raw-counter baseline. If a report fires during dry priming before water starts, the in-progress dry-start candidate can still be completed when flow begins.
Overflow behavior for the first pass:
- The S-35770 raw counter is 24-bit and wraps at
16,777,216. - Firmware delta math handles one 24-bit wrap between ESP32 reads.
- Multiple wraps between reads are not expected for pump-handle rates; if that ever becomes a concern, wire/use
LP/LOOPto track rollover explicitly. - Report-period aggregate fields use wider firmware counters before being clamped to 32-bit report values.
Metric update from implementation pass:
Dry-start fields now use singular
strokein the metric name:dry_start_countdry_start_stroke_totaldry_start_stroke_avgdry_start_stroke_max
New tier-one metrics added:
dry_start_stroke_max: max qualifying dry-start stroke count in the report period.handle_strokes_flowing_per_min:handle_strokes_flowing_total * 60 / dailyWaterUsageTimewhen water usage time is greater than zero.
SMS decision:
The regular compact
Rpacket can include all handle aggregate fields for now because the packet is numeric/comma-delimited and still appears comfortably under the 160-character SMS target with normal values. A test string with large-but-plausible values was about 116 characters. Truly worst-case 32-bit values could exceed one SMS, but those are not realistic daily pump values. If field testing shows SMS splitting or delivery trouble, we can demote lower-priority handle fields back to HTTP-only or define a second packet type.Regular SMS now includes:
handle_strokes_totalhandle_strokes_flowing_totalhandle_strokes_flowing_per_mindry_start_countdry_start_stroke_totaldry_start_stroke_avgdry_start_stroke_max
Implementation summary for commit
0eb7287(Add handle stroke counter reporting):Hardware / pin choices
The first firmware implementation assumes the Counter 2 Click / Click Snap module is wired as planned:
VCC-> 3.3 VGND-> groundSDA-> GPIO 21SCL-> GPIO 22IN-> handle sensor pulse output- optional
RST-> GPIO 33 - optional
LP/LOOP-> GPIO 35
waterpal_config.hnow contains these defaults plusWATERPAL_MIN_DRY_DRAIN_TIME_S, currently 240 seconds.Firmware structure
Handle-stroke logic is in its own module,
waterpal_handle_counter.h, rather than in the DHT/extra-sensors file. That module owns:- I2C setup and raw 24-bit counter reads from address
0x32. - 24-bit wrap-safe delta math for one wrap between wakeups.
- RTC-persisted report-period aggregate counters.
- Dry-start qualification using the drain-time threshold.
- Dry-start total/avg/max tracking.
Wake / float-switch integration
On every wake, WaterPAL reads the handle counter before logging the float-switch edge. This is intentional: on an edge wake, the new handle strokes since the previous wake belong to the previous water state.
Strokes are attributed to:
- total handle strokes, always;
- flowing handle strokes, only when the previous water state was flowing;
- the active dry-start candidate, only while the pump is not flowing and the candidate is valid.
When flow starts, firmware decides whether the dry-start candidate qualifies based on
WATERPAL_MIN_DRY_DRAIN_TIME_S. Short bucket swaps / worker handoffs should not pollute the dry-start average.Reporting/reset behavior
The implementation follows the existing WaterPAL reporting convention: after a successful regular SMS report, report-period handle aggregates reset to zero.
The reset does not clear the raw counter baseline or active dry-start candidate state, so mid-bucket and mid-priming reports should continue gracefully.
Reported fields
The default regular CSV/SMS packet, GPRS query string, and Design Outreach JSON now include:
handle_strokes_totalhandle_strokes_flowing_totalhandle_strokes_flowing_per_mindry_start_countdry_start_stroke_totaldry_start_stroke_avgdry_start_stroke_max
handle_strokes_flowing_per_minis calculated ashandle_strokes_flowing_total * 60 / total_water_usage_time_swhen water usage time is nonzero.The default CSV is still expected to fit inside normal SMS size for realistic daily pump values. A large-but-plausible sample was about 116 characters. If field data shows packet growth or SMS splitting problems, lower-priority handle fields can be moved to HTTP-only or a second packet type.
Overflow behavior
The raw S-35770 counter wraps at 16,777,216. Firmware handles one wrap between reads. Multiple wraps between reads are not expected for pump-handle rates; if that ever becomes a concern,
LP/LOOPshould be wired and used for explicit rollover tracking.Validation
Compiled successfully with the Arduino IDE bundled CLI:
arduino-cli compile --fqbn esp32:esp32:esp32 firmware/WaterPALResult: 422,678 bytes program storage (32%) and 26,292 bytes dynamic memory (8%).
Summary
Add an odometer-like pump-handle stroke counter as a second measurement channel for WaterPAL. The goal is to count rapid pump strokes from a handle-movement sensor, keep counting while the Lilygo SIM7000G / ESP32 is asleep, and read the accumulated count whenever the main micro wakes for existing reasons.
This is distinct from #2, which tracks cycle counts for pulse-output flow meters. This issue is specifically about a low-power external counter IC for pump-handle movement / predictive maintenance.
Ask
Investigate and integrate a small always-on counter circuit, likely on a breakout board or small PCB, using the ABLIC counter IC below or a suitable off-the-shelf equivalent. The Lilygo should only need to wake up, read the count over I2C, and include the count in the SMS / data payload.
Candidate IC:
Suggested breakout:
Motivation
Current WaterPAL measurements are based on the float switch on/off state and water-use duration. Handle movement sensing is the desired second measurement for Afridev-style pumps because it can reveal:
Known Design Notes
From the email response, the ABLIC counter IC may only need a breakout board and pull-ups:
/RST: pull up to VCC with a resistor, suggested around 30K, or connect to a Lilygo output pin for reset control.CLKIN: pull up to VCC with a resistor and use a reed switch / IR sensor output to pull to ground, or tie to a Lilygo input with internal pull-up enabled. External resistor gives better control over current loss while the switch is closed.GND: connect to ground.LOOP: can float, or connect to a Lilygo input if overflow detection is desired. Overflow is above roughly 16 million counts and may not be likely.I2C: connect to Lilygo open-drain I2C pins. External pull-ups are preferred; internal pull-ups may require a slower I2C clock, probably around 10-20 kHz.VCC: share the Lilygo 3.3V rail.CLK,RST,SDA, andSCL.The count-input signal can start as a simple reed switch like the current WaterPAL sensing approach, with IR sensing as a likely future option.
Desired Behavior
Unknowns / Decisions Needed
/RSTshould be hard-pulled high or controlled by a Lilygo GPIO.CLKIN,/RST,SDA, andSCL, balancing sleep current against signal reliability.CLKINshould be driven by reed switch, IR sensor module, or another handle movement sensor for the first implementation.CLKINfor real pump-handle motion.LOOPfor overflow detection or leave it unconnected.Acceptance Criteria
Source Notes
Opening ask:
Response summary: