fix: show correct 'reach the Pi' URL per uplink mode + BUG-15
- Settings: when the Pi is on the phone's hotspot (mode phone), show the Pi's hotspot IP (http://<ip>) with an LTE-only hint instead of the AP URL - BUG-15 documents the phone dual-role routing loop (host hotspot + connect to AP simultaneously breaks the uplink)
This commit is contained in:
@@ -8,7 +8,20 @@ When CLOSED, move the entire entry to Resolved — don't duplicate.
|
|||||||
|
|
||||||
## Open bugs
|
## Open bugs
|
||||||
|
|
||||||
(No open bugs)
|
### BUG-15 — Phone can't host the hotspot and connect to the Pi's AP at once
|
||||||
|
- **Status**: `OPEN` 2026-08-12
|
||||||
|
- **Symptom**: With the phone hosting the hotspot (Pi's uplink) *and* connected to the
|
||||||
|
Pi's AP ("vroom vroom yaris de course"), the Pi loses internet. Uploads fail with
|
||||||
|
`NameResolutionError` — the phone's WiFi-sharing routes the hotspot's traffic back
|
||||||
|
through the no-internet AP, creating a routing loop.
|
||||||
|
- **Cause**: phone-OS limitation — a single phone can't cleanly be both the Pi's
|
||||||
|
internet uplink (AP/hotspot host) and its WiFi client (on the Pi's AP) simultaneously.
|
||||||
|
- **Intended use / workaround**: phone must be **LTE-only** (WiFi off) to serve as the
|
||||||
|
Pi's uplink. Reach the Pi UI from that phone over the hotspot at
|
||||||
|
`http://<pi-hotspot-ip>` (Settings → "In-car hotspot" shows it), or from a second
|
||||||
|
device on the AP.
|
||||||
|
- **Pi-side hardening shipped 2026-08-12**: `phone-hotspot` now forces public DNS
|
||||||
|
(`8.8.8.8`/`1.1.1.1`) and the Settings page surfaces the correct URL per uplink mode.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+15
-2
@@ -302,22 +302,35 @@ async function loadUplinkStatus() {
|
|||||||
|
|
||||||
// In-car access card
|
// In-car access card
|
||||||
const hotspotInfo = document.getElementById('in-car-hotspot-info');
|
const hotspotInfo = document.getElementById('in-car-hotspot-info');
|
||||||
|
const phoneInfo = document.getElementById('in-car-phone-info');
|
||||||
const wifiInfo = document.getElementById('in-car-wifi-info');
|
const wifiInfo = document.getElementById('in-car-wifi-info');
|
||||||
const disconnectedInfo = document.getElementById('in-car-disconnected-info');
|
const disconnectedInfo = document.getElementById('in-car-disconnected-info');
|
||||||
const hotspotUrl = document.getElementById('hotspot-url');
|
const hotspotUrl = document.getElementById('hotspot-url');
|
||||||
|
const phoneUrl = document.getElementById('phone-url');
|
||||||
const copyBtn = document.getElementById('copy-hotspot-url');
|
const copyBtn = document.getElementById('copy-hotspot-url');
|
||||||
if (status.ap_active && status.ap_ip) {
|
const copyPhoneBtn = document.getElementById('copy-phone-url');
|
||||||
|
if (status.mode === 'phone' && status.ip_address) {
|
||||||
|
phoneUrl.textContent = `http://${status.ip_address}`;
|
||||||
|
hotspotInfo.hidden = true;
|
||||||
|
phoneInfo.hidden = false;
|
||||||
|
wifiInfo.hidden = true;
|
||||||
|
disconnectedInfo.hidden = true;
|
||||||
|
if (copyPhoneBtn) copyPhoneBtn.onclick = () => navigator.clipboard.writeText(`http://${status.ip_address}`);
|
||||||
|
} else if (status.ap_active && status.ap_ip) {
|
||||||
hotspotUrl.textContent = `http://${status.ap_ip}`;
|
hotspotUrl.textContent = `http://${status.ap_ip}`;
|
||||||
hotspotInfo.hidden = false;
|
hotspotInfo.hidden = false;
|
||||||
|
phoneInfo.hidden = true;
|
||||||
wifiInfo.hidden = true;
|
wifiInfo.hidden = true;
|
||||||
disconnectedInfo.hidden = true;
|
disconnectedInfo.hidden = true;
|
||||||
if (copyBtn) copyBtn.onclick = () => navigator.clipboard.writeText(`http://${status.ap_ip}`);
|
if (copyBtn) copyBtn.onclick = () => navigator.clipboard.writeText(`http://${status.ap_ip}`);
|
||||||
} else if (status.mode === 'wifi' || status.mode === 'phone') {
|
} else if (status.mode === 'wifi') {
|
||||||
hotspotInfo.hidden = true;
|
hotspotInfo.hidden = true;
|
||||||
|
phoneInfo.hidden = true;
|
||||||
wifiInfo.hidden = false;
|
wifiInfo.hidden = false;
|
||||||
disconnectedInfo.hidden = true;
|
disconnectedInfo.hidden = true;
|
||||||
} else {
|
} else {
|
||||||
hotspotInfo.hidden = true;
|
hotspotInfo.hidden = true;
|
||||||
|
phoneInfo.hidden = true;
|
||||||
wifiInfo.hidden = true;
|
wifiInfo.hidden = true;
|
||||||
disconnectedInfo.hidden = false;
|
disconnectedInfo.hidden = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,19 @@
|
|||||||
If the page doesn't load, try <strong>disabling cellular/mobile data</strong> on your phone.
|
If the page doesn't load, try <strong>disabling cellular/mobile data</strong> on your phone.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="in-car-phone-info" hidden>
|
||||||
|
<p class="mb-2 fw-semibold">Your phone can reach the Pi at:</p>
|
||||||
|
<div class="d-flex align-items-center gap-2 mb-3">
|
||||||
|
<code class="fs-5" id="phone-url">http://10.21.0.112</code>
|
||||||
|
<button class="btn btn-outline-secondary btn-sm" id="copy-phone-url" type="button" title="Copy">
|
||||||
|
<i class="fas fa-copy"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-info py-2 mb-0 small">
|
||||||
|
<i class="fas fa-info-circle me-1"></i>
|
||||||
|
The Pi is on your phone's hotspot. Keep the phone on <strong>mobile data (LTE)</strong> — don't also connect it to the Pi's WiFi.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="in-car-wifi-info" hidden>
|
<div id="in-car-wifi-info" hidden>
|
||||||
<p class="mb-1 small text-muted">The Pi is connected to WiFi. Open <code>http://yaris.local</code> from any device on the same network.</p>
|
<p class="mb-1 small text-muted">The Pi is connected to WiFi. Open <code>http://yaris.local</code> from any device on the same network.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user