Important
The Health and Fueling tabs (medical-episode detection, wellness monitor, carb/hydration tracker, FIT export) require KSafe v2.0 or newer. Earlier installs only ship the safety / SOS / messaging features.
Warning
KSafe can send emergency alerts to your contacts. Test it carefully before relying on it.
Tip
New to KSafe? Start here → Easy Setup guide (español). A plain-English walkthrough — what to tap, what to set, what to ignore — with a 5-minute minimum setup and simple versions of the Senders and Fueling sections. The pages below are the in-depth reference.
KSafe is a free, open-source safety extension for Karoo 3 (Karoo OS 1.527+). It works on two layers:
- Reactive — detects crashes (accelerometer + gyroscope), sudden speed drops, missed check-ins and, optionally with an HR sensor, medical-episode patterns (HR flatline, HR collapse) and wellness alerts (sustained / critical HR, HR–power decoupling). A manual SOS button is always one tap away.
- Preventive (v2.0) — carb and hydration tracker with sensor-aware targets that warn you before bonking or dehydration impair your judgment on the bike.
It also sends ride-start / ride-end notifications with an optional Karoo Live tracking link, exposes three custom-message buttons for one-tap status updates ("I'm OK", "Heading home"…), and two webhook slots to fire any HTTP endpoint from a hardware button (garage door, Home Assistant, IFTTT…).
Important
KSafe sends messages through your phone's internet connection via the Hammerhead Companion app. Without an active phone connection no alerts are sent.
Note
To help improve crash detection, enable the anonymous calibration data toggle in the Settings tab and send the log after your rides. No GPS, no messages, no identifiers — see docs/calibration-logging.md.
Note
Languages. The KSafe interface is localised to English and Spanish. It follows your Karoo's system language automatically and falls back to English for any other language — there is no in-app language switch. The default message templates (emergency / ride-start / ride-end / custom messages) ship in English; edit them to your language in the relevant tab.
| Provider | Cost | Notes |
|---|---|---|
| Telegram | Free, unlimited | Best free option |
| ntfy | Free, unlimited | Quickest setup — no account |
| CallMeBot (WhatsApp) | Free | If your contacts use WhatsApp |
| Pushover | ~$5 one-time | Most reliable push delivery |
You can save credentials for all four; only the selected one is used. Each configured recipient has an alert scope — All (default, both emergency + info), Emergency only, or Info only; the UI keeps at least one emergency contact per provider. Setup steps: docs/messaging-providers.md.
KSafe is officially distributed by Hammerhead in the Karoo's built-in Extensions store. This is the supported path for the great majority of riders: no APK file, no sideloading, no Companion-app workaround, no developer options, no ADB. Hammerhead handles signing, hosting and update delivery, so installs and version bumps land on the device the same way every other Karoo-native feature does.
On the Karoo:
- Open the Extensions store from the main menu.
- Find KSafe in the list, tap Install.
- Restart the Karoo (shut down and start again).
- Open KSafe — it will prompt for "Draw over other apps" permission (required for the SOS cancel overlay). Toggle KSafe → Allow and press Back. If you miss the prompt, a yellow banner inside the app lets you grant it later.
Updates published by Hammerhead arrive in the same store entry — no manual re-install needed.
For riders who want a pre-release build, a custom fork, or who need to install before a version reaches the store:
- Open
https://github.com/lockevod/Karoo-KSafe/releases/latest/download/ksafe.apkon your phone. - Share the file with the Hammerhead Companion app and install.
- Restart the Karoo (shut down and start again).
- Grant the "Draw over other apps" permission as above.
Without the overlay permission the SOS overlay won't appear, but you can still cancel via the SOS/Timer data fields or a hardware button — regardless of which install method you used.
When a countdown is active you have three ways to cancel:
- Overlay — a red full-screen CANCEL button is drawn on top of any screen. Works everywhere; requires the overlay permission (recommended).
- Data field — tap the SOS or Safety Timer field. Requires that field to be visible on the current screen.
- Hardware button — assign KSafe: Cancel Emergency to a SRAM AXS shifter via Sensors → AXS → Configure Controls. Works from any screen.
If the countdown completes, KSafe obtains a GPS fix and sends the configured emergency message via the active provider, then returns to idle monitoring. You can still cancel for up to ~30 minutes after the countdown ends — the visible UI returns to SAFE after 5 s but the sender keeps retrying in the background, and tapping SOS / Safety Timer / the hardware Cancel button aborts the in-flight retry. If delivery fails on every retry (no coverage, expired credentials, provider down) you hear a distinct descending beep and a red "Alert NOT delivered" message appears — so you always know whether your contacts were reached.
KSafe exposes 21 custom data fields. Add any combination from the Karoo profile editor; configure them inside the KSafe app.
| Field | Idle | Tap action | Active states |
|---|---|---|---|
| SOS | SAFE (green) |
Trigger SOS countdown | Orange CANCEL + seconds · Red ALERT SENT |
| Safety Timer | Remaining time, green→yellow→red | Reset check-in ("I'm OK") | Orange CANCEL during any emergency · Timer OFF |
The Safety Timer pauses automatically when the ride is paused.
| Field | Tap action | Active states |
|---|---|---|
| Custom Message 1 / 2 / 3 | Send the slot's preset text — no countdown | Orange SENDING… · Green SENT ✓ · Red ERR retry |
| Webhook 1 / 2 | Fire the configured HTTP request, with optional geo-fence and on-screen ride alert | Orange firing… · Green OK ✓ · Red ERR retry |
| Field | Tap action |
|---|---|
| Carb log 1 / 2 / 3 | Log one serving of the slot's configured grams. A second tap on the same slot within ~5 s of the green +Xg flash undoes the entry (red −Xg confirmation) |
| Hydration log 1 / 2 | Log one serving of the slot's configured ml. Same on-screen undo: second tap within ~5 s reverses the log |
| Combined fuel log 1 / 2 | Log a drink volume AND its carbs in one tap; a second tap within ~6 s undoes it. Active when either the carbs or hydration tracker is enabled (logs only the enabled side); grey when both are off. Icon is fixed; label, ml, carbs and idle colour are editable per slot |
| Field | Shows |
|---|---|
| Carb status | Current carb deficit (grams behind real burn). Shows --- until the tracker has integrated any data, then 0g / −Xg / +Xg colour-coded by deficit level |
| Carb burn rate | Instantaneous g/h from the physiological estimator (power, or HR + age/sex, or HR + max/resting). Shows Pair HR/Pwr when no sensor is paired, --- between movement-gate pauses, the live rate otherwise |
| Carb avg burn | Session-average g/h, averaged only across active integration time (stops excluded) |
| Carbs burned | Cumulative carbs burned this ride from the physiological estimator. Shows Pair HR/Pwr when no sensor, the running total otherwise |
| Calories (HR) (v2.1) | Cumulative HR-based calories this ride (kcal), estimated from heart rate — independent of, and shown alongside, the Karoo's power-based calories. Useful when no power meter is paired. Shows --- when the calorie feature is off and Pair HR/Pwr when no HR is available |
| Calorie Rate (HR) (v2.1) | Instantaneous energy expenditure (kcal/h) from the same HR estimate. Shows Pair HR/Pwr when no model can fire, --- between integration pauses, the live rate otherwise |
| Hydration status | Current fluid deficit (ml behind target). Same --- waiting behaviour as Carb status |
Note
Calories (HR) is independent of the carb tracker (v2.1). Turn it on with Fueling → "Calories (HR)" even if you keep the carb deficit tracker off — the two share the rider physiology block (age / sex / weight) but track separately. The estimate falls back through power → Keytel (HR + age + sex + weight) → Swain (HR + max/resting HR) → %HRmax, so it produces a figure from HR alone when no power meter is paired. When enabled it is also written to the FIT file as the ksafe_calories_kcal developer field (see Settings → FIT export). Additionally, Settings → "Calories as standard FIT field" (v2.1.5) can write the ride's total calories into the FIT session as the standard total_calories field — the one every platform imports (Suunto and others ignore developer fields, and the Karoo does not write this field itself). Source is selectable: the KSafe estimate (HR) or the Karoo's own power-based calories.
All seven fueling status fields also publish their value as a karoo-ext data stream, so any other extension can consume them live (the same inter-extension composition pattern karoo-headwind uses for wind data). Subscribe with streamDataFlow / OnStreamState using these IDs:
Stream ID (TYPE_EXT::…) |
Value (Field.SINGLE) |
|---|---|
ksafe::carb-status |
Carb deficit in g (negative = surplus) |
ksafe::carb-burn-rate |
Instantaneous carb burn in g/h (0 while integration is paused) |
ksafe::carb-avg-burn-rate |
Session-average carb burn in g/h |
ksafe::carbs-burned |
Cumulative carbs burned this ride in g |
ksafe::calories-total |
Cumulative HR-based calories in kcal |
ksafe::calories-rate |
Instantaneous energy expenditure in kcal/h (0 while paused) |
ksafe::hyd-status |
Fluid deficit in ml (negative = surplus) |
Stream states mirror the on-screen fields: Idle whenever no ride is active (the trackers retain their totals after ride end for the post-ride summary, but consumers never receive them as live data), Searching while the tracker is booting or no usable sensor is paired, NotAvailable when the extension master switch or the feature toggle is off, Streaming otherwise. Streams only run while at least one consumer subscribes, so they cost nothing when unused.
Fourteen of the 21 fields have a rider-pickable idle background — SOS, Safety Timer, Custom Message 1–3, Webhook 1–2, Carb Log 1–3, Hydration Log 1–2, Combined Fuel Log 1–2 — picked from a palette in the corresponding tab. The first entry is Karoo default (auto day/night) — the new default for fresh installs — which makes the field render with no custom background and theme-aware text (black on white during the day, white on black at night) so it matches native Karoo fields. Below it sits a 20-hue painted palette for riders who want a coloured tap target. Reserved state colours (red error, orange countdown, amber warning, green success, grey OFF) can't be selected — they belong to the state machine. The remaining 7 fields have no picker: Carb burn rate, Carb avg burn, Carbs burned, Calories (HR) and Calorie Rate (HR) are always Karoo-theme (passive readouts that should look native); Carb status and Hydration status are always coloured by deficit level (blue ahead / green within margin / amber approaching threshold / red over). The five Karoo-theme readout fields also respect the per-field horizontal alignment (left / center / right) the rider sets in the Karoo profile editor; every other field is always centered because they're tap targets or coloured state indicators where alignment makes the field look off-balance next to its neighbours.
KSafe registers 9 BonusActions assignable to SRAM AXS shifters via Sensors → AXS → Configure Controls. Short Press and Long Press can be bound independently.
| Action | What it does |
|---|---|
| Cancel Emergency | Cancels the active countdown from any screen |
| Send Custom Message | Sends the message in slot 1 immediately |
| Webhook Action 1 / 2 | Fires the configured HTTP request |
| Log Carb 1 / 2 / 3 (v2.0) | Logs one serving from the corresponding carb slot |
| Log Drink 1 / 2 (v2.0) | Logs one serving from the corresponding hydration slot |
Note
BonusActions only appear if a SRAM AXS groupset is paired and the Karoo has been restarted after installing KSafe. See the official Hammerhead guide.
The KSafe app has six tabs, in this order:
-
Safety — emergency message + tokens (
{location},{reason},{livetrack}), countdown duration, SOS / Timer field colours, crash detection (sensitivity preset + custom slider, min speed, confirm speed, per-Karoo-profile overrides, monitor-outside-ride toggles), speed-drop window, check-in interval. -
Health (v2.0) — HR-based detectors: medical episode (HR flatline / collapse) and wellness monitor (critical HR, sustained HR, HR–power decoupling). Each has Silent / Warning / Emergency response level and customisable
{bpm}/{threshold}/{minutes}/{drift}templates. Requires a paired HR sensor. -
Fueling (v2.0) — physiological carb burn estimator: 4-tier fall-back chain that picks the highest-confidence formula whose sensor inputs are paired. Tier 1 — power:
kcal/h = power_W × 3.6(standard cycling formula, ~5-10 % error, Coyle / Moseley & Jeukendrup). Tier 2 — Keytel et al. 2005: HR + age + sex + weight, gold-standard HR-only formula (~10-15 % error in cycling between 50-80 % VO2max). Tier 3 — Swain & Leutholtz 1997: HRR → METs → kcal/h, fallback when age/sex unknown (~20-30 % error). Each tier's kcal/h is multiplied by a CHO-fraction from the rider's current intensity zone (linear 0.30 → 0.95 across Z1 → Z5+, from Romijn 1993 / Achten 2003 / Jeukendrup 2014). The integrator is clamped to the 90 g/h gut-absorption ceiling (ISSN 2017). Hydration retains the optional dynamic sweat-rate estimate (HR + power + weight + temp + humidity). Two combinable alert modes per category (deficit and time); deficit reminders are configurable 5/10/15/20/30 min; alert templates use{deficit},{elapsed},{target}(now binds to instantaneous burn rate). Per-category beep + background colour. Post-ride summary. Calories (HR) (v2.1) is a separate toggle in this tab — an HR-based total-calorie estimate (power → Keytel → Swain → %HRmax fall-back) that runs independently of the carb deficit tracker, surfaces on the Calories (HR) / Calorie Rate (HR) data fields, and (when enabled) is exported to the FIT asksafe_calories_kcal. The carb tracker and the calorie estimate share one rider physiology block (age / sex / weight).[!NOTE] How the alerts know you are "low" — KSafe doesn't measure your blood glucose directly (no bike sensor can). It integrates an estimate of your real per-hour carb burn from whichever sensors are paired (power → Keytel HR → Swain HR), modulated by your intensity zone's typical CHO fraction. The integrated total is compared with what you've tapped on the log slots; the gap is the deficit. The alert fires when the deficit crosses your threshold (default 25 g, configurable). When no HR and no power are paired the burn estimator can't run — the data fields display
Pair HR/Pwrand the deficit stays at 0 (no fictitious numbers). For hydration the original target-based model is kept (no biosensor exists for sweat rate; the dynamic estimator using HR + power + temp + humidity is the closest approximation).[!IMPORTANT] Hydration target shift (v18.2) — riders running KSafe with dynamic hydration enabled (Settings → Fueling → "Dynamic sweat rate") will see hourly targets in hot conditions drop by ~25 % vs prior versions. The internal
SweatEstimatorwas re-calibrated to track the literature median (Sawka 2007 / Baker 2017) instead of the upper-bound anchors used before. The old curve over-targeted by ~30-60 % on warm rides, which manifested as alert fatigue and a non-trivial hyponatremia exposure for lighter riders on long hot efforts. The new curve is comparable in shape to Garmin's Firstbeat HeatStress targeting. If you tuned yourhydrationTargetMlPerHour(static mode) around the previous behaviour you are unaffected; if you relied on the dynamic estimator's numbers, expect fewer / less frequent deficit alerts in heat. -
Actions — three sub-blocks: Karoo Live (ride-start / ride-end toggles + messages, Karoo Live key, test buttons), Custom Messages 1–3 (enable, 7-char button label, message text, idle colour), and Webhook 1–2 (URL, GET/POST, headers, body, optional geo-fence, optional on-screen alert, idle colour).
-
Provider — pick the active messaging provider and enter credentials. All four configurations are saved independently. Each recipient has a per-recipient scope selector (All / Emergency only / Info only) controlling which alert types it receives. 📘 Step-by-step for each provider (Telegram bot token, ntfy topic, CallMeBot WhatsApp activation, Pushover App Token + User Key): docs/messaging-providers.md.
-
Settings — master kill switch, test buttons (Simulate Crash, Test ride start/end), FIT export (v2.0, opt-in — off by default) of logged + burned carbs / burn rate / hydration / wellness drift — and, when Calories (HR) is enabled, HR-based calories as
ksafe_calories_kcal(v2.1) — as developer fields for Strava / Intervals.icu / TrainingPeaks (session-average burn rate is shown live on the Karoo via the new data field but not duplicated in the FIT — downstream tools can average the per-recordksafe_carb_burn_rate_gphthemselves), anonymous calibration logging (opt-in), Backup / Restore.
Detailed field references:
- 📘 Messaging providers — full setup (Telegram, ntfy, CallMeBot/WhatsApp, Pushover — where to click, how to get each token/key)
- 📘 Safety / Settings — field reference
- 📘 Health & Fueling — full reference (tier thresholds, FIT schema, alert tokens)
- 📘 Setting your initial fueling targets — g/h by ride duration, ml/h by temperature, pre/post-ride weigh-in formula, ACSM / Jeukendrup / Sawka references
- 📘 What KSafe does in each ride state — Idle / Recording / Paused: which subsystems run, what the status fields show, day/night theme handling
- 📘 On-screen feedback, notifications & sounds — every moment KSafe shows/sounds something (alerts, overlay, beeps, field colours), the channel used, and the mute contract
All test buttons work without an active ride:
| Button | Where | What it does |
|---|---|---|
| Test Send | Provider | Sends a test message via the active provider, with a precise error string on failure |
| Simulate Crash | Settings | Sends your real emergency message immediately — no countdown |
| Test ride start / end | Actions | Sends the configured ride-start or ride-end message |
| Send Message 1 / 2 / 3 | Actions | Sends each custom message directly from the app |
Simulate Crash sends a real alert to your contact. Warn them first, or use Test Send for connectivity-only checks.
The algorithm is based on the same approach as Garmin's incident detection: large impact followed by genuine stillness. Four presets:
| Preset | Best for |
|---|---|
| ⛰ Low | MTB, enduro, technical terrain (lower sensitivity, lower confirm-speed gate) |
| 🚴 Medium | Road, gravel, mixed — recommended default |
| 🏁 High | Smooth road only (velodrome, closed circuit) — do not use on MTB / gravel |
| 🔧 Custom | 20–70 m/s² threshold slider plus speed gates |
You can override min-speed manually after picking a preset (0 disables the speed gate — useful for testing).
Per-Karoo-profile overrides. Each Karoo ride profile (road, gravel, MTB, etc.) can have its own crash sensitivity, min speed and confirm speed — independent of the global defaults. Overrides appear as cards in the Safety tab once a profile has been active during a ride (KSafe auto-learns it on first encounter). Each card has a "Use global settings" toggle; off exposes the full preset + threshold controls for that profile. Only the active profile's override is used at runtime, and the settings you save take effect at the start of your next ride with that profile (configure it before the ride you want it to apply to). Each card collapses to a one-line summary so a long profile list stays manageable.
When it fires and when it doesn't. An impact only confirms as a crash if the device then stays genuinely still — accelerometer near gravity, gyroscope ≤ 2 rad/s, GPS speed below the confirm threshold — for 4.5 continuous seconds. Any movement in that window resets the countdown. After hitting a pothole, expansion joint or a small jump, a rider keeps pedalling — the GPS keeps moving and the gyro never settles, so no alert fires. After a real crash the device lies on the ground with near-zero motion for several seconds and the countdown starts. Without a GPS fix (tunnel, dense tree cover) the speed gate degrades and only the inertial checks remain; High sensitivity is therefore unsafe on MTB / gravel because a hard landing followed by a brief pause can confirm.
📘 Full pipeline (MONITORING → IMPACT → SILENCE_CHECK → CRASH_CONFIRMED), per-preset thresholds, real-world scenarios (pothole at 40 km/h, MTB jump landing, expansion joint…) and the rationale for every constant: docs/crash-detection-algorithm.md.
The two webhook slots fire any HTTP endpoint (GET or POST) through the Karoo network bridge — same path used for emergency alerts, works over Bluetooth tether. Each slot supports an optional geo-fence (only fire near a configured location) and an optional on-screen ride alert so you notice accidental presses.
📘 Copy-paste recipes for Home Assistant, Shelly (local + cloud), ntfy, IFTTT, n8n / Make: docs/webhooks-cookbook.md.
Export and Import buttons (Settings tab) write/read ksafe_export.json / ksafe_import.json in the shared /sdcard/KSafe/ folder, which survives uninstall/reinstall (the backups are no longer wiped when KSafe is updated or removed). The first time you export or import, KSafe requests "All files access" (MANAGE_EXTERNAL_STORAGE) and opens the system settings page to grant it; if the prompt doesn't appear you can grant it over ADB instead. ADB-pulling the file, editing it on your computer and pushing it back is also the easiest way to enter long tokens (Pushover, Telegram) without typing them on the Karoo:
adb pull /sdcard/KSafe/ksafe_export.json
# edit on your computer, then:
adb push ksafe_export.json /sdcard/KSafe/ksafe_import.jsonUnknown fields are silently ignored, so imports across versions always work.
📘 Procedure, ADB commands and JSON schema: docs/backup-restore.md.
- The Karoo has a buzzer, not a speaker. Emergency sounds (crash countdown and SOS firing) play even when the Karoo is muted — KSafe sounds the buzzer directly through the device's hardware layer, controlled by the "Buzzer on emergency (overrides mute)" toggle in Settings (on by default). Non-emergency sounds (ride start, check-in, fueling and wellness reminders) use the standard SDK beep API and still respect the device mute, so they go silent if you mute the Karoo. Keep the Karoo unmuted if you also want to hear those reminders.
- No phone connection for the whole retry window → no alert. Emergency alerts retry automatically: 3 cycles of 3 attempts each (60 / 120 / 180 s between attempts inside a cycle, 5 min and 10 min between cycles — up to ~30 min total). If your phone reconnects within that window the alert still goes out; only a sustained disconnect across all 9 attempts fails completely. When that happens you get a distinct descending beep + a red "Alert NOT delivered" message on the Karoo so you know to find another way to call for help.
- A large pothole or expansion joint followed by a complete stop for several seconds can trigger a false positive. The countdown is your safety net — tap CANCEL.
- Without GPS fix (tunnel, dense tree cover) the speed gate degrades; gyroscope + accelerometer remain the only guard.
- Each provider has its own rate limits and free-tier rules.
- Crash detection only runs during an active ride unless you enable "Monitor crash when not riding" in the Safety tab.
KSafe is a safety aid, not a safety guarantee. It can fail to detect an incident or deliver an alert for many reasons — phone disconnected or not carried, GPS lost, provider outage, undetected impact pattern, misconfiguration, device failure, no internet.
KSafe is provided "as is", without warranty. The developer (lockevod) accepts no responsibility or liability for any harm arising from its use or inability to use it. By installing KSafe you accept full responsibility for your own safety. Always carry your phone, keep it connected to the Karoo, and let someone know your planned route — regardless of whether KSafe is active.
- All configuration is stored locally on the Karoo.
- Message content and identifiers (phone number, chat ID, user key…) are shared with whichever third-party provider you select. Read their terms.
- KSafe has no relationship with any of these providers.
- The opt-in anonymous calibration data toggle records sensor / algorithm data only — no GPS, no messages, no personal identifier. Full disclosure: docs/calibration-logging.md.
User guides:
- Safety / Settings — field reference
- Messaging providers — full setup
- Health & Fueling — full reference
- Webhook cookbook
- Backup and restore
- Field colours
- Calibration logging
Algorithm internals (for contributors):
- Developed by EnderThor.
- Uses the Karoo Extensions Framework by Hammerhead.
- Optionally talks to Telegram, ntfy, CallMeBot (WhatsApp) or Pushover. Each has its own terms; KSafe has no affiliation.
- Thanks to Hammerhead for the Karoo and the extensions API.
- Thanks to Tim Kluge (timklge) for karoo-headwind. When installed alongside KSafe, headwind publishes real meteo data (ambient temperature, humidity) as Karoo streams that the Fueling tab's dynamic sweat-rate estimator consumes instead of the device's heat-biased onboard temperature sensor — a noticeably better hydration target on hot rides. KSafe degrades cleanly to the onboard sensor when headwind isn't installed.