UI: развести статусы каналов — сводка «Связь» (BLE / TCP/IP); transport 0.1.1-SNAPSHOT; BLOCKERS B-5
Обе строки назывались «Связь» (Канал 1 WebSocket и Канал 2 Mercury BLE), из-за чего статус BLE читался как статус TCP: при выключенном Wi-Fi на очках телефон показывал «подключено». Теперь вверху вкладки «Очки» сводка с отдельными строками BLE (Mercury) и TCP/IP (Wi-Fi), в секциях — «BLE» и «TCP/IP». mercuryTransport -> 0.1.1-SNAPSHOT (клиентский WS-пинг, см. BLOCKERS B-5).
This commit is contained in:
+34
@@ -121,3 +121,37 @@ adb -s A06B4AB933C4103 shell input keyevent 223
|
|||||||
Shizuku `SET_SCREEN`.
|
Shizuku `SET_SCREEN`.
|
||||||
|
|
||||||
**Статус:** выполнено (mWakefulness=Dozing подтверждён в конце ночной сессии).
|
**Статус:** выполнено (mWakefulness=Dozing подтверждён в конце ночной сессии).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## B-5 · Телефон показывал «подключено» при мёртвом TCP-канале — РЕШЕНО
|
||||||
|
|
||||||
|
**Когда замечено:** 2026-09-27, пользователь: «телефон говорит подключено, очки говорят что нет связи».
|
||||||
|
|
||||||
|
**Причина:** у очков Wi-Fi был выключен (`wifi_on=0`, нет default network) — реального Канала 1 не
|
||||||
|
было. Очки при выключении Wi-Fi локально теряют сокеты мгновенно и честно писали «нет связи».
|
||||||
|
Телефон же об этом не узнавал: FIN/RST до него не доходит (у очков уже нет интерфейса), а у
|
||||||
|
**клиента `:transport` не было ни пинга, ни таймаута** — `WifiTransport.connect` вечно висел в
|
||||||
|
`for (frame in s.incoming)`. TCP-сокет телефона оставался в `ESTAB`, `onDisconnected` не срабатывал,
|
||||||
|
`VmPhoneController` оставался в `Connected` → UI показывал «подключено».
|
||||||
|
|
||||||
|
**Доказательство (воспроизведено):** выключили Wi-Fi очкам — через 20 c с телефона:
|
||||||
|
```
|
||||||
|
ESTAB 192.168.76.121:50438 → 192.168.76.248:8080
|
||||||
|
```
|
||||||
|
сокет так и висел, телефон даже не переподключался (те же local-порты после возврата Wi-Fi).
|
||||||
|
|
||||||
|
**Фикс (`rayneo-mercury :transport` 0.1.1-SNAPSHOT):** клиентским транспортам добавлен
|
||||||
|
`install(WebSockets) { pingIntervalMillis = WS_PING_INTERVAL_MS }` (15 c) — `WifiTransport` и
|
||||||
|
`WifiByteTransport`; константа в `Transport.kt`. Серверные транспорты пингуют и так
|
||||||
|
(`pingPeriod=15s`, `timeout=30s`), но они ловят мёртвого клиента, а не наоборот.
|
||||||
|
|
||||||
|
**Проверено вживую 2026-09-27:** Wi-Fi очкам выключен → на 10-й секунде у телефона `Send-Q=82`
|
||||||
|
(пошли пинги, недоставленные) → на ~41-й секунде сокет ушёл в `FIN-WAIT-1` (клиент сам закрыл
|
||||||
|
мёртвую сессию, `onDisconnected` сработал) → после возврата Wi-Fi новый `ESTAB :57996` и в логах
|
||||||
|
очков `Phone connected: ws-83ad…` (авто-реконнект).
|
||||||
|
|
||||||
|
**Побочно:** в UI телефона обе строки назывались одинаково — «Связь» (Канал 1 WebSocket и
|
||||||
|
Канал 2 Mercury BLE), из-за чего статус BLE читался как статус TCP. Теперь вверху вкладки «Очки»
|
||||||
|
сводка «Связь» с отдельными строками **BLE (Mercury)** и **TCP/IP (Wi-Fi)**, а в секциях каналов
|
||||||
|
строки переименованы в «BLE» и «TCP/IP».
|
||||||
|
|||||||
@@ -113,6 +113,17 @@ fun GlassesStatusScreen(
|
|||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SectionCard(title = "Связь") {
|
||||||
|
StatusRow(
|
||||||
|
"BLE (Mercury)",
|
||||||
|
if (mercuryConnected) "есть" else "нет",
|
||||||
|
)
|
||||||
|
StatusRow(
|
||||||
|
"TCP/IP (Wi-Fi)",
|
||||||
|
if (connection is ConnectionState.Connected) "есть" else "нет",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Channel1WebSocketSection(connection = connection, glasses = glasses)
|
Channel1WebSocketSection(connection = connection, glasses = glasses)
|
||||||
|
|
||||||
ShizukuSection(
|
ShizukuSection(
|
||||||
@@ -183,7 +194,7 @@ private fun Channel1WebSocketSection(
|
|||||||
glasses: pw.binom.rayneovm.phone.protocol.GlassesStatusInfo?,
|
glasses: pw.binom.rayneovm.phone.protocol.GlassesStatusInfo?,
|
||||||
) {
|
) {
|
||||||
SectionCard(title = "Канал 1 — наше приложение (WebSocket)") {
|
SectionCard(title = "Канал 1 — наше приложение (WebSocket)") {
|
||||||
StatusRow("Связь", connection.label)
|
StatusRow("TCP/IP", connection.label)
|
||||||
when (connection) {
|
when (connection) {
|
||||||
is ConnectionState.Connected -> glasses?.let { g ->
|
is ConnectionState.Connected -> glasses?.let { g ->
|
||||||
StatusRow("Аккумулятор", g.batteryPercent?.let { "$it%" } ?: "—")
|
StatusRow("Аккумулятор", g.batteryPercent?.let { "$it%" } ?: "—")
|
||||||
@@ -270,13 +281,13 @@ private fun Channel2MercurySection(
|
|||||||
OutlinedButton(onClick = onScan) { Text("Проверить ещё раз") }
|
OutlinedButton(onClick = onScan) { Text("Проверить ещё раз") }
|
||||||
}
|
}
|
||||||
is MercuryState.Disconnected -> {
|
is MercuryState.Disconnected -> {
|
||||||
StatusRow("Связь", "нет связи")
|
StatusRow("BLE", "нет связи")
|
||||||
mercury.message?.let { Hint(it) }
|
mercury.message?.let { Hint(it) }
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Button(onClick = onScan) { Text("Сканировать") }
|
Button(onClick = onScan) { Text("Сканировать") }
|
||||||
}
|
}
|
||||||
is MercuryState.Scanning -> {
|
is MercuryState.Scanning -> {
|
||||||
StatusRow("Связь", "поиск… (найдено ${mercury.found.size})")
|
StatusRow("BLE", "поиск… (найдено ${mercury.found.size})")
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
if (mercury.found.isNotEmpty()) {
|
if (mercury.found.isNotEmpty()) {
|
||||||
Text("Найденные устройства:", color = Color(0xFFB0B0B0), fontSize = 12.sp)
|
Text("Найденные устройства:", color = Color(0xFFB0B0B0), fontSize = 12.sp)
|
||||||
@@ -288,11 +299,11 @@ private fun Channel2MercurySection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is MercuryState.Connecting -> {
|
is MercuryState.Connecting -> {
|
||||||
StatusRow("Связь", "сопрягаем ${mercury.device.name ?: mercury.device.address}…")
|
StatusRow("BLE", "сопрягаем ${mercury.device.name ?: mercury.device.address}…")
|
||||||
Hint("Если очки запрашивают PIN — подтвердите на них.")
|
Hint("Если очки запрашивают PIN — подтвердите на них.")
|
||||||
}
|
}
|
||||||
is MercuryState.Connected -> {
|
is MercuryState.Connected -> {
|
||||||
StatusRow("Связь", "подключено (${mercury.device.name ?: mercury.device.address})")
|
StatusRow("BLE", "подключено (${mercury.device.name ?: mercury.device.address})")
|
||||||
StatusRow("Адрес", mercury.device.address)
|
StatusRow("Адрес", mercury.device.address)
|
||||||
StatusRow("Аккумулятор", mercury.batteryPercent?.let { "$it%" } ?: "—")
|
StatusRow("Аккумулятор", mercury.batteryPercent?.let { "$it%" } ?: "—")
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ shizukuApi = "13.1.5"
|
|||||||
shizukuProvider = "13.1.5"
|
shizukuProvider = "13.1.5"
|
||||||
navCompose = "2.10.2"
|
navCompose = "2.10.2"
|
||||||
mercury = "0.1.0-SNAPSHOT"
|
mercury = "0.1.0-SNAPSHOT"
|
||||||
mercuryTransport = "0.1.0-SNAPSHOT"
|
mercuryTransport = "0.1.1-SNAPSHOT"
|
||||||
mercuryBinocular = "0.1.0-SNAPSHOT"
|
mercuryBinocular = "0.1.0-SNAPSHOT"
|
||||||
mercuryShizuku = "0.1.0-SNAPSHOT"
|
mercuryShizuku = "0.1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user