mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-10 18:53:03 +02:00
Fix some frontend display/quality/doc issues
This commit is contained in:
+4
-8
@@ -3,7 +3,7 @@
|
|||||||
* Feature: Add Arch AUR package
|
* Feature: Add Arch AUR package
|
||||||
* Feature: 72hr packet density view in statistics
|
* Feature: 72hr packet density view in statistics
|
||||||
* Feature: Add warnings for event loop selection for MQTT on Windows startup
|
* Feature: Add warnings for event loop selection for MQTT on Windows startup
|
||||||
* Bufix: Bump Apprise to 1.9.9 to fix Matrix bug
|
* Bugfix: Bump Apprise to 1.9.9 to fix Matrix bug
|
||||||
* Misc: More memory-conscious on recent contact fetch
|
* Misc: More memory-conscious on recent contact fetch
|
||||||
* Misc: Fix statistics pane e2e test
|
* Misc: Fix statistics pane e2e test
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
* Bugfix: Fix Apprise duplicate names
|
* Bugfix: Fix Apprise duplicate names
|
||||||
* Bugfix: Be better about identity resolution in the stats pane
|
* Bugfix: Be better about identity resolution in the stats pane
|
||||||
* Misc: Docs, test, and performance enhancements
|
* Misc: Docs, test, and performance enhancements
|
||||||
* Misc: Don't prompt "Are you sure" when leaving an unedited interation
|
* Misc: Don't prompt "Are you sure" when leaving an unedited integration
|
||||||
* Misc: Log node time on startup
|
* Misc: Log node time on startup
|
||||||
* Misc: Improve community MQTT error bubble-up
|
* Misc: Improve community MQTT error bubble-up
|
||||||
* Misc: Unread DMs always have a red unread counter
|
* Misc: Unread DMs always have a red unread counter
|
||||||
@@ -172,7 +172,7 @@
|
|||||||
## [3.3.0] - 2026-03-13
|
## [3.3.0] - 2026-03-13
|
||||||
|
|
||||||
* Feature: Use dashed lines to show collapsed ambiguous router results
|
* Feature: Use dashed lines to show collapsed ambiguous router results
|
||||||
* Feature: Jump to unred
|
* Feature: Jump to unread
|
||||||
* Feature: Local channel management to prevent need to reload channel every time
|
* Feature: Local channel management to prevent need to reload channel every time
|
||||||
* Feature: Debug endpoint
|
* Feature: Debug endpoint
|
||||||
* Feature: Force-singleton channel management
|
* Feature: Force-singleton channel management
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
* Feature: Massive codebase refactor and overhaul
|
* Feature: Massive codebase refactor and overhaul
|
||||||
* Bugfix: Fix packet parsing for trace packets
|
* Bugfix: Fix packet parsing for trace packets
|
||||||
* Bugfix: Refetch channels on reconnect
|
* Bugfix: Refetch channels on reconnect
|
||||||
* Bugfix: Load All on repeater pane on mobile doesn't etend into lower text
|
* Bugfix: Load All on repeater pane on mobile doesn't extend into lower text
|
||||||
* Bugfix: Timestamps in logs
|
* Bugfix: Timestamps in logs
|
||||||
* Bugfix: Correct wrong clock sync command
|
* Bugfix: Correct wrong clock sync command
|
||||||
* Misc: Improve bot error bubble up
|
* Misc: Improve bot error bubble up
|
||||||
@@ -252,10 +252,6 @@
|
|||||||
|
|
||||||
* Bugfix: Don't obscure new integration dropdown on session boundary
|
* Bugfix: Don't obscure new integration dropdown on session boundary
|
||||||
|
|
||||||
## [2.7.8] - 2026-03-08
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.7.8] - 2026-03-08
|
## [2.7.8] - 2026-03-08
|
||||||
|
|
||||||
* Bugfix: Improve frontend asset resolution and fixup the build/push script
|
* Bugfix: Improve frontend asset resolution and fixup the build/push script
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ For advanced setup and troubleshooting see [README_ADVANCED.md](README_ADVANCED.
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.11+
|
||||||
- Node.js LTS or current (20, 22, 24, 25) if you're not using a prebuilt release
|
- Node.js LTS or current (20, 22, 24, 25) if you're not using a prebuilt release
|
||||||
- [UV](https://astral.sh/uv) package manager: `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
- [UV](https://astral.sh/uv) package manager: `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
||||||
- MeshCore radio connected via USB serial, TCP, or BLE
|
- MeshCore radio connected via USB serial, TCP, or BLE
|
||||||
@@ -135,6 +135,8 @@ sudo docker compose pull
|
|||||||
sudo docker compose up -d
|
sudo docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> If you switched to a local build (`build: .` instead of `image:`), use `sudo docker compose up -d --build` instead — `pull` only fetches remote images.
|
||||||
|
|
||||||
The example file and setup script default to the published Docker Hub image. To build locally from your checkout instead, replace:
|
The example file and setup script default to the published Docker Hub image. To build locally from your checkout instead, replace:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
+2
-2
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal, NotRequired
|
||||||
|
|
||||||
from pydantic import TypeAdapter
|
from pydantic import TypeAdapter
|
||||||
from typing_extensions import NotRequired, TypedDict
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
from app.models import Channel, Contact, Message, MessagePath, RawPacketBroadcast
|
from app.models import Channel, Contact, Message, MessagePath, RawPacketBroadcast
|
||||||
from app.routers.health import HealthResponse
|
from app.routers.health import HealthResponse
|
||||||
|
|||||||
+1
-1
@@ -164,7 +164,7 @@ class BotModule(FanoutModule):
|
|||||||
),
|
),
|
||||||
timeout=BOT_EXECUTION_TIMEOUT,
|
timeout=BOT_EXECUTION_TIMEOUT,
|
||||||
)
|
)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
logger.warning("Bot '%s' execution timed out", self.name)
|
logger.warning("Bot '%s' execution timed out", self.name)
|
||||||
return
|
return
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|||||||
@@ -538,7 +538,7 @@ class CommunityMqttPublisher(BaseMqttPublisher):
|
|||||||
self._version_event.clear()
|
self._version_event.clear()
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self._version_event.wait(), timeout=30)
|
await asyncio.wait_for(self._version_event.wait(), timeout=30)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ class FanoutManager:
|
|||||||
handler = getattr(module, handler_name)
|
handler = getattr(module, handler_name)
|
||||||
await asyncio.wait_for(handler(data), timeout=_DISPATCH_TIMEOUT_SECONDS)
|
await asyncio.wait_for(handler(data), timeout=_DISPATCH_TIMEOUT_SECONDS)
|
||||||
self._clear_module_error(config_id)
|
self._clear_module_error(config_id)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
timeout_error = f"{handler_name} timed out after {_DISPATCH_TIMEOUT_SECONDS:.1f}s"
|
timeout_error = f"{handler_name} timed out after {_DISPATCH_TIMEOUT_SECONDS:.1f}s"
|
||||||
self._set_module_error(config_id, timeout_error)
|
self._set_module_error(config_id, timeout_error)
|
||||||
logger.error(
|
logger.error(
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ class BaseMqttPublisher(ABC):
|
|||||||
self._version_event.wait(),
|
self._version_event.wait(),
|
||||||
timeout=self._not_configured_timeout,
|
timeout=self._not_configured_timeout,
|
||||||
)
|
)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
continue
|
continue
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
return
|
return
|
||||||
@@ -231,7 +231,7 @@ class BaseMqttPublisher(ABC):
|
|||||||
self._version_event.clear()
|
self._version_event.clear()
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(self._version_event.wait(), timeout=60)
|
await asyncio.wait_for(self._version_event.wait(), timeout=60)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
elapsed = time.monotonic() - connect_time
|
elapsed = time.monotonic() - connect_time
|
||||||
await self._on_periodic_wake(elapsed)
|
await self._on_periodic_wake(elapsed)
|
||||||
if self._should_break_wait(elapsed):
|
if self._should_break_wait(elapsed):
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
NO_EVENT_RECEIVED_GUIDANCE = (
|
NO_EVENT_RECEIVED_GUIDANCE = (
|
||||||
"Radio command channel is unresponsive (no_event_received). Ensure that your firmware is not "
|
"Radio command channel is unresponsive (no_event_received). Ensure that your firmware is not "
|
||||||
"incompatible, outdated, or wrong-mode (e.g. repeater, not client), and that"
|
"incompatible, outdated, or wrong-mode (e.g. repeater, not client), and that "
|
||||||
"serial/TCP/BLE connectivity is successful (try another app and see if that one works?). The app cannot proceed because it cannot "
|
"serial/TCP/BLE connectivity is successful (try another app and see if that one works?). The app cannot proceed because it cannot "
|
||||||
"issue commands to the radio."
|
"issue commands to the radio."
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -118,7 +118,7 @@ async def test_serial_device(port: str, baudrate: int, timeout: float = 3.0) ->
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
logger.debug("Device %s timed out", port)
|
logger.debug("Device %s timed out", port)
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
+2
-2
@@ -480,7 +480,7 @@ async def drain_pending_messages(mc: MeshCore) -> int:
|
|||||||
# Small delay between fetches
|
# Small delay between fetches
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("Error draining messages: %s", e, exc_info=True)
|
logger.warning("Error draining messages: %s", e, exc_info=True)
|
||||||
@@ -518,7 +518,7 @@ async def poll_for_messages(mc: MeshCore) -> int:
|
|||||||
# If we got a message, there might be more - drain them
|
# If we got a message, there might be more - drain them
|
||||||
count += await drain_pending_messages(mc)
|
count += await drain_pending_messages(mc)
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("Message poll exception: %s", e, exc_info=True)
|
logger.warning("Message poll exception: %s", e, exc_info=True)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import os
|
|||||||
import platform
|
import platform
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
@@ -390,7 +390,7 @@ async def debug_support_snapshot() -> DebugSnapshotResponse:
|
|||||||
is_reconnecting=is_reconnecting,
|
is_reconnecting=is_reconnecting,
|
||||||
)
|
)
|
||||||
return DebugSnapshotResponse(
|
return DebugSnapshotResponse(
|
||||||
captured_at=datetime.now(timezone.utc).isoformat(),
|
captured_at=datetime.now(UTC).isoformat(),
|
||||||
system=_build_system_info(),
|
system=_build_system_info(),
|
||||||
application=_build_application_info(),
|
application=_build_application_info(),
|
||||||
health=_build_debug_health_summary(health_data, radio_state=radio_state),
|
health=_build_debug_health_summary(health_data, radio_state=radio_state),
|
||||||
|
|||||||
@@ -473,7 +473,7 @@ async def discover_mesh(request: RadioDiscoveryRequest) -> RadioDiscoveryRespons
|
|||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
event = await asyncio.wait_for(events.get(), timeout=remaining)
|
event = await asyncio.wait_for(events.get(), timeout=remaining)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
break
|
break
|
||||||
|
|
||||||
merged = _merge_discovery_result(
|
merged = _merge_discovery_result(
|
||||||
@@ -536,7 +536,7 @@ async def trace_path(request: RadioTraceRequest) -> RadioTraceResponse:
|
|||||||
timeout_seconds = _trace_timeout_seconds(send_result)
|
timeout_seconds = _trace_timeout_seconds(send_result)
|
||||||
try:
|
try:
|
||||||
event = await asyncio.wait_for(response_task, timeout=timeout_seconds)
|
event = await asyncio.wait_for(response_task, timeout=timeout_seconds)
|
||||||
except asyncio.TimeoutError as exc:
|
except TimeoutError as exc:
|
||||||
raise HTTPException(status_code=504, detail="No trace response heard") from exc
|
raise HTTPException(status_code=504, detail="No trace response heard") from exc
|
||||||
finally:
|
finally:
|
||||||
if not response_task.done():
|
if not response_task.done():
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ async def fetch_contact_cli_response(
|
|||||||
while _monotonic() < deadline:
|
while _monotonic() < deadline:
|
||||||
try:
|
try:
|
||||||
result = await mc.commands.get_msg(timeout=2.0)
|
result = await mc.commands.get_msg(timeout=2.0)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
continue
|
continue
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.debug("get_msg() exception: %s", exc)
|
logger.debug("get_msg() exception: %s", exc)
|
||||||
@@ -196,7 +196,7 @@ async def prepare_authenticated_contact_connection(
|
|||||||
login_future,
|
login_future,
|
||||||
timeout=response_timeout,
|
timeout=response_timeout,
|
||||||
)
|
)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"No login response from %s %s within %.1fs",
|
"No login response from %s %s within %.1fs",
|
||||||
contact_label,
|
contact_label,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ async def run_post_connect_setup(radio_manager) -> None:
|
|||||||
logger.info(
|
logger.info(
|
||||||
"Radio clock at connect: epoch=%d utc=%s",
|
"Radio clock at connect: epoch=%d utc=%s",
|
||||||
radio_time,
|
radio_time,
|
||||||
datetime.fromtimestamp(radio_time, timezone.utc).strftime(
|
datetime.fromtimestamp(radio_time, UTC).strftime(
|
||||||
"%Y-%m-%d %H:%M:%S UTC"
|
"%Y-%m-%d %H:%M:%S UTC"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -274,7 +274,7 @@ async def prepare_connected_radio(radio_manager, *, broadcast_on_success: bool =
|
|||||||
try:
|
try:
|
||||||
await radio_manager.post_connect_setup()
|
await radio_manager.post_connect_setup()
|
||||||
break
|
break
|
||||||
except asyncio.TimeoutError as exc:
|
except TimeoutError as exc:
|
||||||
if attempt < POST_CONNECT_SETUP_MAX_ATTEMPTS:
|
if attempt < POST_CONNECT_SETUP_MAX_ATTEMPTS:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Post-connect setup timed out after %ds on attempt %d/%d; retrying once",
|
"Post-connect setup timed out after %ds on attempt %d/%d; retrying once",
|
||||||
|
|||||||
+1
-2
@@ -13,13 +13,12 @@ import importlib.metadata
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import tomllib
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import tomllib
|
|
||||||
|
|
||||||
RELEASE_BUILD_INFO_FILENAME = "build_info.json"
|
RELEASE_BUILD_INFO_FILENAME = "build_info.json"
|
||||||
PROJECT_NAME = "remoteterm-meshcore"
|
PROJECT_NAME = "remoteterm-meshcore"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ class WebSocketManager:
|
|||||||
try:
|
try:
|
||||||
# Timeout prevents blocking on slow/unresponsive clients
|
# Timeout prevents blocking on slow/unresponsive clients
|
||||||
await asyncio.wait_for(connection.send_text(message), timeout=SEND_TIMEOUT_SECONDS)
|
await asyncio.wait_for(connection.send_text(message), timeout=SEND_TIMEOUT_SECONDS)
|
||||||
except asyncio.TimeoutError:
|
except TimeoutError:
|
||||||
logger.debug("Timeout sending to WebSocket client, marking disconnected")
|
logger.debug("Timeout sending to WebSocket client, marking disconnected")
|
||||||
disconnected.append(connection)
|
disconnected.append(connection)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import type {
|
|||||||
RadioTraceResponse,
|
RadioTraceResponse,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { CONTACT_TYPE_REPEATER } from '../types';
|
import { CONTACT_TYPE_REPEATER } from '../types';
|
||||||
import { calculateDistance, isValidLocation } from '../utils/pathUtils';
|
import { calculateDistance, formatDistance, isValidLocation } from '../utils/pathUtils';
|
||||||
|
import { useDistanceUnit } from '../contexts/DistanceUnitContext';
|
||||||
import { getContactDisplayName } from '../utils/pubkey';
|
import { getContactDisplayName } from '../utils/pubkey';
|
||||||
import { handleKeyboardActivate } from '../utils/a11y';
|
import { handleKeyboardActivate } from '../utils/a11y';
|
||||||
import { ContactAvatar } from './ContactAvatar';
|
import { ContactAvatar } from './ContactAvatar';
|
||||||
@@ -186,6 +187,7 @@ function TraceNodeRow({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function TracePane({ contacts, config, onRunTracePath }: TracePaneProps) {
|
export function TracePane({ contacts, config, onRunTracePath }: TracePaneProps) {
|
||||||
|
const distanceUnit = useDistanceUnit();
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [sortMode, setSortMode] = useState<TraceSortMode>('alpha');
|
const [sortMode, setSortMode] = useState<TraceSortMode>('alpha');
|
||||||
const [draftHops, setDraftHops] = useState<TraceDraftHop[]>([]);
|
const [draftHops, setDraftHops] = useState<TraceDraftHop[]>([]);
|
||||||
@@ -536,7 +538,7 @@ export function TracePane({ contacts, config, onRunTracePath }: TracePaneProps)
|
|||||||
</div>
|
</div>
|
||||||
{sortMode === 'distance' && distanceKm !== null ? (
|
{sortMode === 'distance' && distanceKm !== null ? (
|
||||||
<div className="mt-1 text-[0.6875rem] text-muted-foreground">
|
<div className="mt-1 text-[0.6875rem] text-muted-foreground">
|
||||||
{distanceKm.toFixed(1)} km away
|
{formatDistance(distanceKm, distanceUnit)} away
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{selectedCount > 0 ? (
|
{selectedCount > 0 ? (
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#MESHCORE_TCP_PORT=5000
|
#MESHCORE_TCP_PORT=5000
|
||||||
|
|
||||||
# BLE (also requires the optional `bluez` package)
|
# BLE (also requires the optional `bluez` package)
|
||||||
|
# NOTE: The systemd service sets ProtectHome=yes, which may block the D-Bus
|
||||||
|
# session bus at /run/user/. If BLE fails to connect, try overriding with
|
||||||
|
# ProtectHome=no in a systemd drop-in.
|
||||||
#MESHCORE_BLE_ADDRESS=AA:BB:CC:DD:EE:FF
|
#MESHCORE_BLE_ADDRESS=AA:BB:CC:DD:EE:FF
|
||||||
#MESHCORE_BLE_PIN=123456
|
#MESHCORE_BLE_PIN=123456
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ testpaths = ["tests"]
|
|||||||
addopts = "-n auto --dist worksteal"
|
addopts = "-n auto --dist worksteal"
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py310"
|
target-version = "py311"
|
||||||
line-length = 100
|
line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
|
|||||||
+2
-4
@@ -1073,9 +1073,7 @@ class TestPostConnectSetupOrdering:
|
|||||||
|
|
||||||
rm = RadioManager()
|
rm = RadioManager()
|
||||||
rm._connection_info = "Serial: /dev/ttyUSB0"
|
rm._connection_info = "Serial: /dev/ttyUSB0"
|
||||||
rm.post_connect_setup = AsyncMock(
|
rm.post_connect_setup = AsyncMock(side_effect=[TimeoutError(), TimeoutError()])
|
||||||
side_effect=[asyncio.TimeoutError(), asyncio.TimeoutError()]
|
|
||||||
)
|
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch("app.websocket.broadcast_error") as mock_broadcast_error,
|
patch("app.websocket.broadcast_error") as mock_broadcast_error,
|
||||||
@@ -1099,7 +1097,7 @@ class TestPostConnectSetupOrdering:
|
|||||||
|
|
||||||
rm = RadioManager()
|
rm = RadioManager()
|
||||||
rm._connection_info = "Serial: /dev/ttyUSB0"
|
rm._connection_info = "Serial: /dev/ttyUSB0"
|
||||||
rm.post_connect_setup = AsyncMock(side_effect=[asyncio.TimeoutError(), None])
|
rm.post_connect_setup = AsyncMock(side_effect=[TimeoutError(), None])
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch("app.websocket.broadcast_error") as mock_broadcast_error,
|
patch("app.websocket.broadcast_error") as mock_broadcast_error,
|
||||||
|
|||||||
Reference in New Issue
Block a user