-
Notifications
You must be signed in to change notification settings - Fork 0
Operations
| What | Where |
|---|---|
| Club leaderboard dashboard | http://<router-ip>/strava/ |
| Club activities JSON | http://<router-ip>/strava/activities.json |
| Per-club all-time JSON | http://<router-ip>/strava/leaderboard_<clubid>.json |
| Club activity store | $STRAVA_STATE_DIR/activities_<clubid>.ndjson |
| Dated leaderboard snapshots | $STRAVA_STATE_DIR/snapshots/YYYYMMDD_<clubid>.json |
| Club token state |
$STRAVA_STATE_DIR/token.json (chmod 600) |
| Club leaderboard log | /var/log/strava-leaderboard.log |
| My Activities dashboard | http://<router-ip>/strava/me/ |
| Activity detail page | http://<router-ip>/strava/me/activity.html?id=<id> |
| Personal stats summary | http://<router-ip>/strava/me/stats.html |
| Activity heatmap | http://<router-ip>/strava/me/heatmap.html |
| Heatmap GPS data |
http://<router-ip>/strava/me/heatmap.json (sampled track points) |
| Heatmap city labels |
http://<router-ip>/strava/me/cities.json (generated from Overpass API each run) |
| Bike service tracker | http://<router-ip>/strava/me/bike.html |
| Bike service CGI (read/write) | http://<router-ip>/cgi-bin/bike-service |
| Bike service data store |
$STRAVA_MY_BIKE_DATA (default $STRAVA_MY_STATE_DIR/bike-service.json) |
| Annual goals CGI (read/write) | http://<router-ip>/cgi-bin/ride-goals |
| Annual goals data store |
$STRAVA_MY_GOALS_DATA / $HEALTHSYNC_GOALS_DATA (default $STATE_DIR/ride-goals.json) |
| My activities JSON | http://<router-ip>/strava/me/activities.json |
| Per-activity detail JSON |
$STRAVA_MY_DETAIL_DIR/<id>.json (default …/strava/me/details/) |
| My activity store | $STRAVA_MY_STATE_DIR/activities.ndjson |
| Detail backfill skip list | $STRAVA_MY_STATE_DIR/detail-skip.txt |
| My activities token state |
$STRAVA_MY_STATE_DIR/token.json (chmod 600) |
| My activities log | /var/log/strava-my-activities.log |
| HealthSync Drive auth status |
$HEALTHSYNC_WEB_DIR/drive-status.json (ok:true / ok:false) |
| HealthSync re-auth CGI |
http://<router-ip>/cgi-bin/drive-auth (non-functional — device flow blocked for Drive scopes; use OAuth Playground + SSH instead) |
| HealthSync log | /var/log/healthsync-activities.log |
Note: on this project's router the state directories are under /mnt/sda5/ (USB persistent storage, not flash overlay).
| Script | Type | Purpose |
|---|---|---|
strava-leaderboard |
executable (0755) | Club leaderboard main script |
strava-my-activities |
executable (0755) | My Activities main script |
healthsync-activities |
executable (0755) | HealthSync / Google Drive main script |
strava-cron-guard |
executable (0755) | Cron wrapper with retry + alert |
strava-email-monthly |
executable (0755) | Monthly summary email |
strava-email-weekly |
executable (0755) | Weekly summary email |
strava-lib.sh |
sourced (0644) | Shared library: token refresh, weather, curl retry |
strava-my-html-dashboard.sh |
sourced (0644) | Renders index.html
|
strava-my-html-detail.sh |
sourced (0644) | Renders activity.html
|
strava-my-html-bike.sh |
sourced (0644) | Renders bike.html + installs bike CGIs |
strava-my-html-stats.sh |
sourced (0644) | Renders stats.html
|
strava-my-html-heatmap.sh |
sourced (0644) | Renders heatmap.html + generates heatmap.json
|
strava-my-feed-api.sh |
sourced (0644) | Strava API feed pagination |
strava-my-feed-scrape.sh |
sourced (0644) | Strava scrape feed pagination + normalization |
strava-my-detail-backfill.sh |
sourced (0644) | Per-activity detail JSON backfill |
strava-my-bike-alert.sh |
sourced (0644) | Bike-service threshold email alerts |
strava-render-pages.sh |
sourced (0644) | Shared wrapper: sources dashboard+detail+bike+stats (used by both strava-my-activities and healthsync-activities) |
strava-leaderboard-html.sh |
sourced (0644) | Club leaderboard index.html heredoc |
healthsync-fit-import.sh |
sourced (0644) | Magene FIT processing + dual-source merge |
Every nightly cron job is wrapped by /usr/bin/strava-cron-guard. In addition to sending alert emails on failure, the guard now provides two automatic recovery layers:
Before running the script the guard pings STRAVA_NET_CHECK_HOST (default 1.1.1.1). If the host is unreachable (e.g. the ISP modem is re-connecting) the guard waits, polling every STRAVA_NET_CHECK_INTERVAL seconds (default 15 s), for up to STRAVA_NET_CHECK_WAIT seconds (default 120 s = 2 min).
- If the network comes up within that window the script runs normally; the recovered delay is logged to syslog.
- If the network is still offline after
STRAVA_NET_CHECK_WAITseconds the guard logsERROR: … skipped — no network after 120sto syslog and exits cleanly. No alert email is sent for a pure network-absence abort, to avoid alarm-fatigue when the ISP is simply slow to reconnect.
The check uses a bare IP address so DNS is not required for the pre-flight itself.
If the script exits non-zero the guard re-runs it up to STRAVA_CRON_RETRIES times (default 2), waiting STRAVA_CRON_RETRY_DELAY seconds (default 300 s = 5 min) between attempts.
- Each failed attempt is logged to syslog:
WARNING: … failed (exit N) — retry 1/2 in 300s - The alert email is sent only after all attempts have failed.
- The email subject includes the total attempt count:
[strava-cron] strava-leaderboard failed after 3 attempt(s) (exit 1).
| Variable | Default | Description |
|---|---|---|
STRAVA_NET_CHECK_HOST |
1.1.1.1 |
IP to ping for connectivity check |
STRAVA_NET_CHECK_WAIT |
120 |
Max seconds to wait for network |
STRAVA_NET_CHECK_INTERVAL |
15 |
Seconds between connectivity polls |
STRAVA_CRON_RETRIES |
2 |
Retries after the first attempt (0 = no retry) |
STRAVA_CRON_RETRY_DELAY |
300 |
Seconds between retries |
All five knobs are optional and commented out in config.example; the defaults are used when they are absent.
In STRAVA_SOURCE=api mode the club feed carries no real activity dates, so each activity is dated by the day the script first saw it, not when it was performed. Run daily, that is accurate to within a day or two; an activity older than the ~2-week feed window when you first install will be dated to install day.
In STRAVA_SOURCE=scrape mode, real activity dates are available and used directly — no approximation needed. When you switch from API to scrape mode, old entries keep their first-seen dates and new ones get real dates going forward.
Each club leaderboard store (activities_<clubid>.ndjson) is append-only and never pruned (only per-club snapshots/ are capped by STRAVA_KEEP_SNAPSHOTS). The My Activities store is instead reconciled with the feed each run, so it reflects edits and deletions and can shrink.
For a club the store stays small for years, but it is the one file to watch if flash is very tight — keep STRAVA_STATE_DIR on roomy persistent storage.
Strava truncates last names to an initial in the club feed (e.g. John D.). Athletes are grouped by firstname|lastname|profile_medium, matching the main app's buildAthleteKey. Activities are deduped by a content signature of those names plus the activity's shape — so two genuinely identical activities by the same person collapse into one.
Strava allows 100 requests / 15 min, 1000 / day for a standard (non-premium) API app. A daily cron run uses a handful of requests — well within limits.
Keep STRAVA_STATE_DIR off /tmp and /var — both are RAM (tmpfs) on OpenWrt and are cleared on reboot. The default /usr/lib/... lives in the overlay and survives reboots, but for larger datasets or USB drives point the config variables accordingly.
ca-bundle is required so curl can verify strava.com. This is installed by install.sh automatically.
strava-my-activities.sh and healthsync-activities.sh have separate NDJSON stores (different state directories), so there is no storage duplication. However, both write to the same web directory (/www/strava/me) by default — whichever runs last overwrites activities.json and all HTML. The dashboard ends up showing only that source's activities.
To run both side-by-side you would need to point them at different web directories and serve at different URLs. In practice: run strava-my-activities while you still have API access, then switch cron to healthsync-activities when it ends. See Switching-Data-Sources for migration steps.
The bike page saves through /cgi-bin/bike-service. uhttpd serves /www/cgi-bin as CGI out of the box and install.sh ensures it (uci set uhttpd.main.cgi_prefix=/cgi-bin). If you only scp the script instead of running the installer, confirm with uci get uhttpd.main.cgi_prefix (should print /cgi-bin).