Repository navigation
Make the TrainingPeaks Hub app connect in seconds: pasta networking + LAN re-advert - #8
Merged
Merged
Conversation
This was referenced Sep 17, 2026
Open
BenA-SA
force-pushed
the
feat/hub-readvert
branch
2 times, most recently
from
September 17, 2026 13:31
4744af3 to
e4175e0
Compare
3 tasks
BenA-SA
force-pushed
the
feat/hub-readvert
branch
from
September 17, 2026 14:39
f31ae60 to
8ba6c32
Compare
Owner
Author
|
@sentry review |
Under Wine, TPV's own _tpvirtual._tcp mDNS advert can carry a bridge address (docker0's 172.17.0.1 on a host running Docker), so the Hub companion app finds TPV but cannot connect to TCP 7779 and shows no ride. The entrypoint now publishes a second advert through the host avahi-daemon while TPV runs, pointing at the default-route IPv4 address. Hub picks the reachable entry, confirmed on the laptop with a manual re-advert: Live data and the In Game remote both worked. - entrypoint: advertise_hub / stop_hub_advert around the TPV launch - run-tpv.sh: TPV_HOST_NAME, TPV_HUB_ADVERT, TPV_HUB_ADDR, TPV_HUB_NAME - Containerfile.full: avahi-utils - verify.sh: check 6 for the _tpvirtual._tcp advert address - README and ADR-0001 Refs #3 Co-Authored-By: Claude <noreply@anthropic.com>
…s to End-to-end testing showed Hub ignores 'fedora (LAN)' but connects to 'FEDORA LAN' on the same host record. ADR-0001 records the A/B steps.
… connects to" This reverts commit 0b23275.
TPV advertises an address for every interface Wine reports, and Hub tries only the first, waiting out Android's ~127 s TCP timeout when it is a Docker bridge or VPN address. pasta bound to the LAN interface shows TPV only that interface: cold-start connects went from ~132 s to 3-4 s. TPV_NETWORK=host restores host networking (network trainers, #13). ADR-0001 records the diagnosis, including the advert-name red herring.
BenA-SA
force-pushed
the
feat/hub-readvert
branch
from
September 20, 2026 08:12
8ba6c32 to
486cece
Compare
Seer flagged that the advert check leaves an orphaned avahi-publish when
only one of the two publishers dies. The orphan is real, but the stated
mechanism is inverted for this script: bash's kill BUILTIN returns 0 if
ANY listed pid is live, so 'kill -0 "${HUB_ADVERT_PIDS[@]}"' succeeds
with one publisher dead and the failure branch never runs. (/bin/kill
does return non-zero there, which is where the assumption comes from.)
The effect was worse than an orphan: no warning, and TPV reported the
advert as working while publishing half a service to the Hub app.
Check each pid on its own, and reap the rest before returning.
Seer, correctly: lan_address() runs a pipeline under 'set -euo pipefail', and its value is taken by a plain assignment, so a failing 'ip route get' propagates and the script exits before the empty-address warning can run. Reproduced: with the route unavailable the entrypoint dies silently at exit 2, printing neither the warning nor anything after it. That is exactly the case this PR introduces -- no route yet while pasta networking settles -- so it would have bitten on a cold start. Let the pipeline fail into an empty string instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes the TrainingPeaks Hub companion app connect to TPV in the container within seconds, for every user and with no manual steps. Hub's In Game remote has Gear Up/Down and Difficulty −/+, which covers the handlebar-control goal in #3.
Problem: Hub discovers TPV via mDNS (
_tpvirtual._tcp) and connects in on TCP 7779. TPV advertises an address for every interface Wine reports (172.17.0.1Docker bridge,100.89.193.106Tailscale,192.168.0.146Wi-Fi). Hub tries only the first and waits out Android's ~127 s TCP connect timeout. Meanwhile it shows "please start a ride".Fix:
run-tpv.shruns the container on pasta networking bound to the LAN interface, so TPV only sees that interface.Changes
run-tpv.sh:--network=pasta:-i,<LAN if> -p 7779:7779 --hostname <host>.TPV_LAN_IF, or by default the default-route interface.TPV_NETWORK=host, orqzmode, keeps host networking.TPV_HOST_NAME/TPV_HUB_ADVERT/TPV_HUB_ADDR/TPV_HUB_NAME.scripts/entrypoint.sh:advertise_hubruns before the TPV launch, andstop_hub_advertafterwineserver -w.<hostname>-tpv-<last octet>.localand<hostname> (LAN)._tpvirtual._tcpport 7779txtvers=1.Containerfile.full: addsavahi-utils(image rebuild required).verify.sh: check 6 flags each_tpvirtual._tcpIPv4 entry OK/BAD. Under pasta, checks 3 and 5 run inside the container, because QZ's ports live in its network namespace.docs/adr/0001-…: the full diagnosis, including a red herring (the advert name) and the measurements below.Testing
Cold starts of Hub, driven over adb: force-stop, wait 20 s for the Android NSD cache to expire, launch. Connection times are taken from the phone's
netstatand TPV'sPlayer.log:--network=host+ re-advert (Docker + Tailscale present)172.17.0.1:7779SYN_SENT--network=host,docker0deleted100.89.193.106(Tailscale, reachable by luck)wlp0s20f3+ re-advert (Docker + Tailscale present)192.168.0.146:7779ipconfigshows onlywlp0s20f3andlo.tpv-full:pr8).bothmode with the real trainer under pasta. QZ's DIRCON advert goes through host avahi over D-Bus and QZ shares the container's network namespace, so it should work. It's the main risk.Known limitation
Trainers that advertise themselves on the LAN (a Wi-Fi KICKR, a remote DIRCON bridge) probably aren't discovered under pasta, because inbound multicast isn't forwarded. The workaround is
TPV_NETWORK=host. Tracked in #13.Notes
tpv-hub-addr/tpv-hub-svcworkaround units used before this PR are no longer running and aren't needed with it.Refs #3
🤖 Generated with Claude Code