IcomRadio¶
The main entry point for controlling an Icom transceiver over LAN.
Class: IcomRadio¶
Constructor¶
IcomRadio(
host: str,
port: int = 50001,
username: str = "",
password: str = "",
radio_addr: int = 0x98,
timeout: float = 5.0,
audio_codec: AudioCodec | int = AudioCodec.PCM_1CH_16BIT,
audio_sample_rate: int = 48000,
auto_reconnect: bool = False,
reconnect_delay: float = 2.0,
reconnect_max_delay: float = 60.0,
watchdog_timeout: float = 30.0,
)
| Parameter | Type | Default | Description |
|---|---|---|---|
host |
str |
required | Radio IP address or hostname |
port |
int |
50001 |
Control port number |
username |
str |
"" |
Authentication username |
password |
str |
"" |
Authentication password |
radio_addr |
int |
0x98 |
CI-V address of the radio |
timeout |
float |
5.0 |
Default timeout for all operations (seconds) |
Additional optional parameters:
audio_codec,audio_sample_rate— audio stream configurationauto_reconnect,reconnect_delay,reconnect_max_delay,watchdog_timeout— reconnect/watchdog behavior
Context Manager¶
IcomRadio supports async with for automatic connection management:
async with IcomRadio("192.168.1.100", username="u", password="p") as radio:
freq = await radio.get_frequency()
# Disconnect happens automatically
Equivalent to:
radio = IcomRadio("192.168.1.100", username="u", password="p")
await radio.connect()
try:
freq = await radio.get_frequency()
finally:
await radio.disconnect()
Properties¶
connected¶
Whether the radio is currently connected and ready for commands.
Audio Capabilities¶
audio_capabilities()¶
Return the stable icom-lan audio capability structure:
supported_codecssupported_sample_rates_hzsupported_channelsdefault_codecdefault_sample_rate_hzdefault_channels
Default values are deterministic:
- Codec: first supported codec in icom-lan preference order.
- Sample rate: highest supported sample rate.
- Channels: implied by default codec (fallback to minimum supported channels).
get_audio_stats()¶
Return runtime audio quality stats for the active audio stream as a JSON-friendly dictionary. If no audio stream is active, returns a zeroed idle snapshot.
Connection Methods¶
connect()¶
Open connection to the radio and authenticate. Performs the full handshake:
- Discovery (Are You There → I Am Here)
- Login with credentials
- Token acknowledgement
- Conninfo exchange
- CI-V data stream open
Raises:
| Exception | When |
|---|---|
ConnectionError |
UDP connection failed |
AuthenticationError |
Login rejected |
TimeoutError |
Radio didn't respond |
disconnect()¶
Cleanly disconnect from the radio. Closes the CI-V data stream and both UDP connections.
Frequency¶
get_frequency()¶
Get the current operating frequency in Hz.
Returns: int — frequency in Hz (e.g., 14074000)
set_frequency()¶
Set the operating frequency.
| Parameter | Type | Description |
|---|---|---|
freq_hz |
int |
Frequency in Hz |
Raises: CommandError if the radio rejects the frequency.
Mode¶
get_mode()¶
Get the current operating mode.
Returns: Mode enum value (e.g., Mode.USB)
get_mode_info()¶
Get current mode and filter number (if radio reports filter in response).
get_filter() / set_filter()¶
Read/set current filter number (1-3) while preserving mode.
set_mode()¶
Set the operating mode.
| Parameter | Type | Description |
|---|---|---|
mode |
Mode \| str |
Mode enum or name string ("USB", "CW", etc.) |
Raises: CommandError if the radio rejects the mode.
Power¶
get_power()¶
Get the RF power level.
Returns: int — power level (0–255)
set_power()¶
Set the RF power level.
| Parameter | Type | Description |
|---|---|---|
level |
int |
Power level 0–255 |
Meters¶
get_s_meter()¶
Read the S-meter value. Returns: int (0–255)
get_swr()¶
Read the SWR meter value (TX only). Returns: int (0–255)
Raises: TimeoutError if not transmitting.
get_alc()¶
Read the ALC meter value (TX only). Returns: int (0–255)
Raises: TimeoutError if not transmitting.
PTT¶
set_ptt()¶
Toggle Push-To-Talk.
| Parameter | Type | Description |
|---|---|---|
on |
bool |
True = TX, False = RX |
VFO & Split¶
select_vfo()¶
Select the active VFO.
| Value | Description |
|---|---|
"A" |
VFO A |
"B" |
VFO B |
"MAIN" |
Main receiver (IC-7610) |
"SUB" |
Sub receiver (IC-7610) |
vfo_equalize()¶
Send the CI-V A=B command. On MAIN/SUB radios (e.g. IC-7610), practical semantics can differ from a literal MAIN→SUB copy depending on rig state.
vfo_exchange()¶
Swap VFO A and VFO B.
set_split_mode()¶
Enable or disable split mode (TX on VFO B, RX on VFO A).
Attenuator & Preamp¶
All attenuator and preamp methods use Command29 framing for dual-receiver
radio compatibility (IC-7610). The receiver parameter defaults to RECEIVER_MAIN (0).
get_attenuator_level()¶
Read attenuator level in dB (0, 3, 6, ..., 45).
get_attenuator()¶
Read attenuator state as boolean (compatibility wrapper).
set_attenuator_level()¶
Set attenuator level in dB. IC-7610 supports 0–45 in 3 dB steps.
Raises: ValueError if db is not a valid step.
set_attenuator()¶
Toggle attenuator (compatibility wrapper: on=18 dB, off=0 dB).
get_preamp()¶
Read preamp level.
set_preamp()¶
Set the preamp level.
| Level | Description |
|---|---|
0 |
Off |
1 |
PREAMP 1 |
2 |
PREAMP 2 |
| Receiver | Constant | Value |
|---|---|---|
| Main | RECEIVER_MAIN |
0x00 |
| Sub | RECEIVER_SUB |
0x01 |
CW¶
send_cw_text()¶
Send CW text via the radio's built-in keyer. Long messages are automatically split into 30-character chunks.
stop_cw_text()¶
Stop CW sending in progress.
Power Control¶
power_control()¶
Remote power on/off. Requires the radio to maintain network connectivity in standby.
State Guardrails¶
snapshot_state() / restore_state()¶
async def snapshot_state(self) -> dict[str, object]
async def restore_state(self, state: dict[str, object]) -> None
Best-effort helpers for preserving and restoring rig state in integration workflows.
run_state_transaction()¶
Run an operation with automatic snapshot/restore guard.
Scope / Waterfall¶
on_scope_data()¶
Register a callback for scope/waterfall data. The callback receives a complete ScopeFrame each time the radio delivers a full spectrum burst (all sequences assembled).
Pass None to unregister.
from icom_lan.scope import ScopeFrame
def handle_scope(frame: ScopeFrame):
print(f"Receiver {frame.receiver}: "
f"{frame.start_freq_hz/1e6:.3f}–{frame.end_freq_hz/1e6:.3f} MHz, "
f"{len(frame.pixels)} pixels, mode={frame.mode}")
radio.on_scope_data(handle_scope)
enable_scope()¶
Enable scope display and data output on the radio. Sends CI-V 0x27 0x10 0x01 (scope on) and 0x27 0x11 0x01 (data output on).
| Parameter | Type | Default | Description |
|---|---|---|---|
output |
bool |
True |
Also enable wave data output |
Raises: CommandError if the radio rejects the command.
disable_scope()¶
Disable scope data output. Sends CI-V 0x27 0x11 0x00.
Raises: CommandError if the radio rejects the command.
ScopeFrame¶
| Attribute | Type | Description |
|---|---|---|
receiver |
int |
0=MAIN, 1=SUB |
mode |
int |
0=center, 1=fixed, 2=scroll-C, 3=scroll-F |
start_freq_hz |
int |
Lower edge frequency in Hz |
end_freq_hz |
int |
Upper edge frequency in Hz |
pixels |
bytes |
Amplitude values, each 0x00–0xA0 (0–160) |
out_of_range |
bool |
True if scope data is out of range |
Note: In center mode, start_freq_hz and end_freq_hz are already expanded from center ± half-span to actual edge frequencies.
Raw CI-V¶
send_civ()¶
async def send_civ(
self,
command: int,
sub: int | None = None,
data: bytes | None = None,
) -> CivFrame
Send an arbitrary CI-V command and return the response.
| Parameter | Type | Description |
|---|---|---|
command |
int |
CI-V command byte |
sub |
int \| None |
Optional sub-command byte |
data |
bytes \| None |
Optional payload data |
Returns: CivFrame with the radio's response.