Skip to content

Troubleshooting

Connection Issues

"Radio did not respond to discovery"

Symptom: TimeoutError: Radio did not respond to discovery after 10 attempts

Causes:

  1. Wrong IP address — verify your radio's IP in its network settings menu
  2. Radio not on network — ensure the radio is powered on and connected to your LAN
  3. Firewall blocking UDP — allow UDP ports 50001–50003
  4. Different subnet — the client and radio must be on the same subnet (or have routing configured)
  5. Network Control disabled — enable "Remote Control" in your radio's network settings

Debug:

# Can you reach the radio?
ping 192.168.1.100

# Is the port open?
nc -u -z 192.168.1.100 50001

# Try discovery
icom-lan discover

"Authentication failed"

Symptom: AuthenticationError: Authentication failed (error=0xFEFFFFFF)

Causes:

  1. Wrong username/password — check your radio's Network User settings
  2. Too many connections — the radio supports limited concurrent connections. Disconnect other clients (RS-BA1, wfview, etc.)
  3. Account disabled — ensure the network user account is enabled

"CI-V response timed out"

Symptom: TimeoutError: CI-V response timed out

Causes:

  1. CI-V port negotiation failed — this usually means the conninfo exchange didn't complete properly
  2. Radio busy — another application may be holding the CI-V stream
  3. Network congestion — try increasing the timeout
  4. Command pacing too aggressive for current link/rig state — increase ICOM_CIV_MIN_INTERVAL_MS (e.g., 50-80) for LAN, or ICOM_SERIAL_CIV_MIN_INTERVAL_MS for serial backend

Debug:

import logging
from icom_lan import create_radio, LanBackendConfig

logging.basicConfig(level=logging.DEBUG)

# This will show the full handshake sequence
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
    freq = await radio.get_freq()

Look for: - Status: civ_port=50002 — confirms port negotiation succeeded - CI-V port not in status, using default — port negotiation failed, likely a GUID issue

"Scope over serial requires baudrate >= 115200"

Symptom: CommandError on enable_scope() / capture_scope_frame() with a low serial baudrate.

Cause: Scope/waterfall CI-V traffic over serial is high-rate; low baud can starve regular command responses. The serial backend enforces a deterministic guardrail.

Fixes:

  1. Set the serial CI-V speed to at least 115200 (recommended).
  2. If you must run lower for diagnostics, use explicit override:
  3. Python API: SerialBackendConfig(..., allow_low_baud_scope=True) when using create_radio(config)
  4. Env var: ICOM_SERIAL_SCOPE_ALLOW_LOW_BAUD=1

When override is used, the backend logs a warning because timeout risk increases.

Connection drops after ~30 seconds

Symptom: Commands work initially, then start timing out.

Cause: Keep-alive pings stopped. This shouldn't happen under normal use, but can occur if:

  • The event loop is blocked for extended periods
  • The Python process is suspended

The library sends pings every 500ms automatically. If the radio doesn't receive pings for its timeout period (usually 10–30 seconds), it drops the connection.

Web UI API returns 401 Unauthorized

Symptom: GET /api/v1/info (or WebSocket connect) fails with HTTP 401.

Cause: Web server was started with --auth-token, but request does not include token.

Fixes:

# HTTP API
curl -H "Authorization: Bearer <TOKEN>" http://127.0.0.1:8080/api/v1/info

For WebSocket clients, send either:

  • Authorization: Bearer <TOKEN> header, or
  • ?token=<TOKEN> query parameter.

radio_connect returns backend_recovering

Symptom: WebSocket response:

{"type":"response","ok":false,"error":"backend_recovering"}

Cause: Backend is already in reconnect/recovery state. Parallel manual reconnect requests are rejected intentionally.

Fix: Wait for radio_ready=true in state updates before retrying manual connect. Do not spam reconnect requests from frontend automation loops.

Mobile headset/lock-screen controls do nothing

Symptom: Volume/media buttons do not tune frequency and play/pause does not toggle PTT.

Cause: Browser does not expose the MediaSession API (navigator.mediaSession), so handlers are not registered.

Fixes:

  1. Verify behavior in a browser/platform with MediaSession support.
  2. Use on-screen controls as fallback (expected behavior on unsupported browsers).

Web UI polling appears slower on low battery

Symptom: State updates arrive less frequently on mobile devices with low battery.

Cause: Frontend intentionally increases /api/v1/state polling interval when battery is low and not charging:

  • 10–20% -> 2x interval
  • <=10% -> 4x interval

Fixes / Notes:

  1. Charge device to restore normal polling cadence.
  2. This optimization is skipped automatically on browsers without Battery Status API support.

Mobile v2 gestures are not available

Symptom: Swipe-to-dismiss bottom sheets and touch-first mobile layout are missing.

Cause: UI version defaults to v1 unless v2 is selected.

Fixes:

  1. Open Web UI with ?ui=v2 query parameter.
  2. Keep v2 selected in localStorage for subsequent sessions.

Command Issues

"Radio rejected set_frequency"

Symptom: CommandError: Radio rejected set_frequency(999999999)

The radio returned NAK (0xFA). Possible causes:

  • Frequency out of the radio's supported range
  • Radio is in a mode that doesn't allow frequency changes
  • VFO lock is enabled

SWR/ALC always returns 0

These meters only report values during transmit. When receiving, they return 0.

CW text not sending

  • Ensure the radio is in CW mode (await radio.set_mode("CW"))
  • Check that CW keying speed is set appropriately on the radio
  • Text must be ASCII A–Z, 0–9

Network Tips

Static IP

Assign a static IP to your radio to avoid DHCP lease changes:

  • IC-7610: Menu → Set → Network → IP Address — set to Manual
  • Use an IP outside your DHCP range

WiFi vs Ethernet

  • Ethernet is more reliable with lower latency
  • WiFi (IC-705) works but may experience higher packet loss
  • For WiFi radios, increase the timeout: timeout=10.0

VPN / Remote Access

The library works over VPN tunnels if UDP traffic is forwarded:

  • Ensure your VPN supports UDP
  • Allow ports 50001–50003
  • Increase timeout for high-latency links
  • Discovery (broadcast) won't work over VPN — specify the radio's IP directly

Retry / Fail-Fast Policy

Recommended policy for real-radio automation:

  • Retry allowed (soft-fail): idempotent reads (get_*) and non-critical telemetry.
  • Retry with recovery: command timeout after all retries -> one reconnect recovery path -> retry command once.
  • Fail-fast (no blind retries): safety-critical toggles (PTT, power_control, CW stop/start transactions) when state uncertainty is dangerous.
  • Always log on timeout: command name, attempt, timeout flag, recovered flag, duration.

In integration soak, use structured JSON logs with canonical fields:

  • test, step, cmd, attempt, timeout, recovered, duration_ms

Soak / Integration Diagnostics

Use soak mode to capture rare timeout behavior with structured logs:

export ICOM_SOAK_SECONDS=120
pytest -m integration tests/integration/test_radio_integration.py::TestSoak::test_soak_retries_and_logging -q -s

Look for:

  • {"ev":"timeout", ...} — timeout event
  • {"ev":"recover", ...} — reconnect recovery attempts
  • SOAK_SUMMARY {...} — final counters (timeouts, timeouts_unrecovered, etc.)

Getting Help

  1. Enable debug logging (see above)
  2. Open an issue with:
    • Your radio model
    • Python version
    • OS
    • Debug log output
    • Steps to reproduce

CI-V Commands Timeout During Scope/Waterfall

Symptom: get_frequency(), get_power() etc. return cached values or raise TimeoutError while scope/waterfall is active.

Cause: Fixed in v0.8.0. In earlier versions, the RX pump processed one packet at a time. Scope data (~225 packets/sec) would queue ahead of command responses.

Solution: Upgrade to v0.8.0+. The drain-all RX pattern processes all queued packets each iteration.

Reconnect After Disconnect Takes Too Long

Symptom: After clicking Disconnect then Connect, the radio doesn't respond for 30-60 seconds.

Cause: Fixed in v0.8.0. Earlier versions did a full disconnect (including the control transport) and then a full reconnect with discovery. IC-7610 doesn't respond to discovery for ~60s after a recent session.

Solution: v0.8.0 uses soft disconnect/reconnect — only the CI-V data stream is closed. The control transport stays alive, so reconnect skips discovery and authentication entirely. Reconnect takes ~1 second.

Connection Fails With civ_port=0

Symptom: Log shows Status: civ_port=0, audio_port=0 repeatedly.

Cause: The radio needs time to recover between connections. Rapid reconnects (especially during development/testing) cause this.

Solutions: 1. Wait 30–60 seconds before reconnecting 2. v0.8.0+ uses optimistic default ports — connects instantly even with civ_port=0 3. If persistent: power-cycle the radio's network (Menu → Set → Network → LAN → Off/On)

Audio Cuts Out on Mobile (Safari iOS)

Symptom: Audio stops when Safari goes to background, doesn't resume on return.

Cause: iOS suspends WebSocket connections and AudioContext in background tabs.

Solution: v0.8.0+ adds visibilitychange listener that resumes AudioContext and reconnects the audio WebSocket when the tab returns to foreground. Audio may stutter briefly during reconnection.

Audio Stutters Over VPN/Tailscale

Symptom: Audio playback has gaps or stutters when accessing the Web UI remotely.

Cause: Network jitter from VPN tunneling.

Solution: v0.8.0+ uses a 200ms jitter buffer (up from 50ms). For very high latency connections, this may still be insufficient — consider a local deployment.

TX Audio Has No Modulation on macOS (Web UI / Bridge)

Symptom: PTT toggles ON, but transmitted audio is silent or very weak.

Typical logs:

  • audio: TX transcoder unavailable (opus codec missing?)
  • Opus library import failures from opuslib.

Cause: On macOS, opuslib may fail to locate Homebrew libopus automatically.

Fixes:

# Install libopus via Homebrew
brew install opus

# Apply project patch for opuslib path detection
python scripts/patch_opuslib_macos.py

Then restart the app and retest TX audio. See detailed notes: docs/opuslib-macos-fix.md.

Serial Backend Issues (IC-7610 USB)

"No such file or directory: /dev/cu.usbserial-..."

Symptom: FileNotFoundError or SerialException when connecting.

Causes: 1. USB cable not connected 2. Radio not powered on 3. Wrong device path

Solutions:

# List available serial devices (macOS)
ls -l /dev/cu.usbserial-*

# Linux
ls -l /dev/ttyUSB*

# Wait 5-10 seconds after power-on for device to appear

"CI-V USB Port must be set to CI-V, not REMOTE"

Symptom: Serial connection opens, but CI-V commands fail with timeout or NAK.

Cause: Radio's CI-V USB Port setting is in [REMOTE] mode (RS-BA1), not Link to [CI-V].

Solution: 1. On IC-7610: Menu → Set → Connectors → CI-V → CI-V USB Port 2. Set to Link to [CI-V] (NOT [REMOTE]) 3. Disconnect/reconnect USB cable 4. Retry connection

Critical Hardware Finding

This was confirmed with live IC-7610 hardware validation (issue #146, 2026-03-06). [REMOTE] mode blocks serial CI-V commands. Use Link to [CI-V] for icom-lan serial backend.

"Audio device 'IC-7610 USB Audio' not found"

Symptom: AudioError or sounddevice exception when starting audio.

Causes: 1. USB audio not enabled on radio 2. Wrong device name 3. sounddevice/numpy not installed

Solutions:

# List available audio devices
icom-lan --list-audio-devices
icom-lan --list-audio-devices --json

# Check radio settings:
# Menu → Set → Connectors → USB Audio → USB Audio (RX/TX) → Enabled

# Install serial + USB audio dependencies if missing
pip install 'icom-lan[serial,bridge]'

"Scope over serial requires baudrate >= 115200"

Symptom: CommandError when calling enable_scope() or capture_scope_frame() on serial backend with baud < 115200.

Cause: Scope CI-V traffic is high-rate (~225 packets/sec on LAN). Lower serial baud rates cannot sustain this without starving command responses. The serial backend enforces a deterministic guardrail.

Solutions: 1. Recommended: Set CI-V USB Baud Rate to 115200 or higher in radio settings: - Menu → Set → Connectors → CI-V → CI-V USB Baud Rate → 115200 2. Override (use with caution for debugging only):

export ICOM_SERIAL_SCOPE_ALLOW_LOW_BAUD=1
icom-lan --backend serial --serial-baud 19200 scope
Python API:
config = SerialBackendConfig(..., allow_low_baud_scope=True)
The library will log a warning about increased timeout risk.

Serial CI-V commands time out under load

Symptom: TimeoutError on CI-V commands when audio or scope is active.

Causes: 1. Baud rate too low for combined traffic 2. CI-V pacing too aggressive

Solutions:

# Increase serial CI-V pacing interval (default 50 ms)
export ICOM_SERIAL_CIV_MIN_INTERVAL_MS=80
icom-lan --backend serial status

# Or use higher baud rate (radio setting)
# Menu → Set → Connectors → CI-V → CI-V USB Baud Rate → 115200

USB audio RX works, but TX does not

Symptom: Can hear radio RX audio, but transmit from computer does not work.

Causes: 1. Radio USB Audio TX not enabled 2. PTT not activated 3. Wrong TX device selected

Solutions:

# Check radio setting:
# Menu → Set → Connectors → USB Audio → USB Audio TX → Enabled

# Verify TX device name matches RX
icom-lan --list-audio-devices

# Explicitly set TX device
icom-lan --backend serial --tx-device "IC-7610 USB Audio" audio tx --in test.wav

# Ensure PTT is active during TX (library handles this automatically for audio tx)

Permission denied on /dev/cu.usbserial-*

Symptom: PermissionError when opening serial device.

Cause: User lacks permissions (rare on macOS, more common on Linux).

Solutions:

# Linux: add user to dialout group
sudo usermod -a -G dialout $USER
# Logout/login required

# macOS: check ownership (typically world-readable by default)
ls -l /dev/cu.usbserial-*
# Should show: crw-rw-rw- root wheel

# Temporary workaround (not recommended for production)
sudo chmod 666 /dev/cu.usbserial-XXXXXX