Dry Fire Rep Tracking
Idea
Track the number of reps a user performs per dry fire drill. Dry fire drills are self-evaluating (start beep, perform, end beep, self-evaluate), but we currently don’t persist rep counts. Recording reps would let users see their practice volume over time and incentivize daily practice.
Motivation
- Encourage consistent daily dry fire practice by making rep counts visible
- Show practice trends over days/weeks (e.g., “150 draws this week”)
- Gamification angle — streaks, volume milestones, progress charts
Hardware-Assisted Approach (Mantis TitanX)
The Mantis TitanX is a BLE 4.1 laser training pistol with a gyro/accelerometer and laser emitter. It connects to Mantis’ own apps (MantisX, Laser Academy) but has no public SDK or API. However, it likely emits a BLE notification on trigger pull, which is the only event we’d need.
Event-driven laser detection
Rather than running continuous camera-based laser dot detection (battery killer), use the BLE trigger event as a gate:
- BLE notify → “trigger pulled”
- App captures a single camera frame (or short burst, ~100ms window)
- Image processing checks just that frame for laser dot position on target
- Log the rep + optional hit location
The camera stays dormant 99% of the time, only waking for a snapshot per rep. Dramatically cheaper than continuous scanning.
Even without camera/laser detection, BLE trigger events alone give us:
- Automatic rep counting (no manual entry)
- Split times between reps (draw-to-first-shot, split-to-split)
- Par time evaluation (did they finish within the beep?)
Integration paths (in order of preference)
- Contact Mantis about a partnership — they may expose trigger events to drive hardware sales
- BLE reverse engineering — scan GATT services with nRF Connect to find the trigger characteristic. Trigger events are simple boolean payloads, likely not buried in proprietary analytics. Fragile if firmware changes though.
- Software-only fallback — manual rep entry, par timer beep counting. Works for everyone regardless of hardware.
Open Questions
- Should reps reuse the Score model (PassFail type, one score per rep)? This gives per-rep timestamps and ties into existing leaderboard/history infra, but could be noisy for high-rep drills.
- Or is this a separate lightweight model — just a daily aggregate (drill_id, user_id, date, rep_count)? Simpler, but loses per-rep granularity.
- Hybrid: each “session” is a Score (PassFail, with a rep_count field), so you get one record per practice session rather than one per rep?
- Does the par timer already emit enough data to derive rep counts automatically (number of beep cycles), or does the user need to manually enter them?
- How does this interact with offline/sync — are dry fire reps queued the same way as scores?
- Can we define a generic BLE trigger-event interface so other laser trainers (not just TitanX) could plug in?