NBA Feed
Your teams' news and games, with scores hidden until you reveal them.
An open-source Android app that reads the WaterRower S4 monitor over USB and turns it into analog instruments, 19 games and a Cesium flight down the California coast.
Sports & fitnessJava · JavaScriptGitHub @dustin-gambleOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Rowing instruments, 21 games and a coastal flight, driven by a WaterRower S4 monitor over USB. Runs on the rower's own Android tablet. No root.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Rowing instruments, 19 games and a coastal flight, driven by a WaterRower S4 monitor over USB.
📥 Download the APK and read the guide →
Your rowing machine already measures everything. WAKE reads the WaterRower S4 monitor over USB
from the Android tablet on the machine, and turns it into analog instruments that behave like
water, a shelf of games driven by your real power and cadence, and a flight down the California
coast on a 3D globe.Read the full README ↗Rowing instruments, 19 games and a coastal flight, driven by a WaterRower S4 monitor over USB.
📥 Download the APK and read the guide →
The machine all of this was written on and measured against. Nothing was added to the hardware — the app reads the S4 monitor over the USB cable that is already there.
Your rowing machine already measures everything. WAKE reads the WaterRower S4 monitor over USB from the Android tablet on the machine, and turns it into analog instruments that behave like water, a shelf of games driven by your real power and cadence, and a flight down the California coast on a 3D globe.
If Ergatta does not read your strokes after you exit WAKE, restart the screen.
Built against a WaterRower in an Ergatta fit-out, but it talks to the S4, not to Ergatta: no root, no system changes, and Ergatta itself is untouched and still the fallback.
node server/server.js) for live capture, an event stream and
protocol decoding. The app finds it on the Wi-Fi by itself; everything works without it.A real boat decelerates between strokes. Rowers call it the run of the boat, and reading it is how you judge your own stroke — a strong drive shows a high peak and a slow decay.
The S4 does not decay its readings: it holds the last value until the next one. Showing that value flat is the single mistake that cost this project the most rework. Instead every needle coasts.
Pure quadratic drag, ω(t) = ω₀ / (1 + (k/I)ω₀t), was the first model, and on the machine it read
wrong: steepest the instant you stop, then hovering just above zero for minutes — 11 rpm on a paddle
at rest. The coast now holds its run, eases off through the middle, and lands on exactly zero.
Knowing when to coast turned out to be the hard part. Three candidate triggers were tested against thousands of captured samples before one survived:
| Trigger | Result |
|---|---|
watts == 0 | Rejected — zero in 27% of samples taken while actively rowing, runs up to 9.7 s |
| Speed value unchanged | Rejected — it is an average and holds its last figure for ~10 s |
| Flywheel pulses stopped | Rejected — the paddle turns for many seconds after you let go |
| Stroke counter gone quiet | Used — exact, one tick per stroke, allowance scaled to your rating |
Pulses stopping is no good for starting a coast, but it is the one true signal the paddle has stopped — so once they stop, whatever is left of the coast finishes within 1.5 s.
1A9 with no multiplier. An inherited ×2 produced 74 spm and 294
readings above 55 spm, beyond human cadence.1A9 dipping to 19–21 in ~9% of samples, so the displayed
rate is now a trimmed mean over 15 s. The raw value still drives every decision.055 is not a distance. It is the low byte of a metres counter; real distance is 057.Device : WR USB sensor, 04D8:000A (Microchip CDC-ACM)
Tablet : Android 9, Ergatta rower tablet (minSdk 23)
Decoded: 088 watts · 14A speed · 1A9 rate · 140 strokes
057 distance · 1A0 heart rate · 1E1 clock
Any WaterRower S4 exposing USB serial should work, as should other Android tablets. Reports from different hardware are very welcome — open an issue.
WAKE was built with an AI coding agent, and everything learned the hard way is written down for the next one. Open Claude Code or any coding agent, paste this, and describe what you want:
I want to customize WAKE, a rowing app for the WaterRower S4 on an Ergatta tablet.
1. Fork https://github.com/dustin-gamble/wake to my GitHub account, clone my fork,
and create a branch called my-wake.
2. Before changing anything, read AGENTS.md, then README.md, then CLAUDE.md.
3. Help me with this: <describe what you want - e.g. "a game where I race a shark
that speeds up whenever my stroke rate drops">
4. There is no emulator for this tablet. Build the APK, tell me how to get it onto
my rower, and ask me what I see before moving on.
Your agent can't see the tablet, so you are its eyes: install each build, row, and tell it what you see. Made something others would enjoy? Send a pull request.
# JDK 17+ and the Android SDK (platform 35); one dependency, usb-serial-for-android.
./gradlew assembleDebug
# Optionally bake in your laptop's dashboard URL, otherwise it is discovered over UDP:
./gradlew assembleDebug -PdiagnosticServerUrl=http://<your-laptop-ip>:8787
The dashboard needs no dependencies at all:
node server/server.js # http://localhost:8787
For Coast Flight's satellite maps, supply a Cesium Ion token — either
CESIUM_ION_TOKEN in the environment or server/cesium.local.json as {"ionToken":"..."}. It is
served to the app once over the LAN and cached there; no token is ever committed or compiled
into the APK. Without one the flight falls back to OpenStreetMap.
Protocol and physics run without Android, so they are tested with plain javac:
S=app/src/main/java/com/codex/waterrowerdiagnostic T=tools/prototest/com/codex/waterrowerdiagnostic
javac -d /tmp/t $S/S4Protocol.java $S/PulseMeter.java $S/Coast.java $S/BoatSpeedModel.java \
$S/RowerProfile.java $S/Progress.java $S/ShuffleBag.java $T/*.java
for t in S4ProtocolTest PulseMeterTest BoatSpeedModelTest RowerProfileTest ProgressTest ShuffleBagTest; do
java -cp /tmp/t com.codex.waterrowerdiagnostic.$t
done
app/ Android app: protocol, instruments, games, Coast Flight WebView
server/ Optional laptop dashboard: HTTP, SSE, capture, UDP discovery
tools/ Capture analysis (Python) and offline tests (plain javac)
docs/ The GitHub Pages site and the published APK
AGENTS.md Start here if an AI agent is customizing it
CLAUDE.md Engineering notes: what was measured, what was ruled out, and why
MIT. Not affiliated with WaterRower or Ergatta.
If it made a row go quicker, you can sponsor the project.