Metadata-Version: 2.5
Name: kc8jcrigctl
Version: 0.2.1
Summary: A terminal front end for rigctld, for picking a rig and a serial device without the command line
Project-URL: Homepage, https://www.kc8jc.com/kc8jcrigctl/
Author-email: "J.C. Wilson" <jcw@othertime.com>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Keywords: amateur radio,ham radio,hamlib,rig control,rigctld
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications :: Ham Radio
Requires-Python: >=3.11
Requires-Dist: pyserial>=3.5
Requires-Dist: textual>=8.2.8
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# KC8JCRigctl

A compact Textual TUI wrapper for `rigctld` (Hamlib). Pick a rig model from
your installed Hamlib's known-rig list, pick a USB/serial device, and
connect/disconnect `rigctld` without touching the command line.

## Requirements

- Python 3.11+
- [Hamlib](https://hamlib.github.io/), providing `rigctl` and `rigctld`
- [uv](https://docs.astral.sh/uv/) — optional; used if present

## Installing

### From a wheel (what other people should use)

Each release is published as a single `.whl` file on the website. It needs no
account, no index and no clone. The exact command, with the current version
number in it, is in `INSTALL.txt` beside the wheel:

<https://www.kc8jc.com/kc8jcrigctl/INSTALL.txt>

```sh
pipx install https://www.kc8jc.com/kc8jcrigctl/kc8jcrigctl-<version>-py3-none-any.whl
```

The version is deliberately not spelled out here. It used to be, and it went
stale twice over: this file still named 0.1.0 while the site was serving 0.1.1
and the source was at 0.2.0, so following the README got you a build older than
anything anyone had. `INSTALL.txt` is generated by `make website` from the
version in `__init__.py`, so it cannot drift.

`pipx` puts the program in its own virtualenv and links only the
`kc8jcrigctl` command onto your PATH, so its Textual version cannot argue
with anything else you have installed. `pipx upgrade kc8jcrigctl` and
`pipx uninstall kc8jcrigctl` do what they say.

Hamlib is **not** installed by this and cannot be - `rigctl` and `rigctld`
are native binaries that come from your operating system (`brew install
hamlib`, `apt install libhamlib-utils`, or hamlib.org). The program finds
them on your PATH at run time. On Linux you also need to be in the `dialout`
group to open `/dev/ttyUSB*`; see the note `install.sh` prints.

A `SHA256SUMS` file sits beside the wheel if you want to prove you got the
file that was built:

```sh
shasum -a 256 -c SHA256SUMS
```

### From a clone


```sh
./install.sh
```

Clone to running in well under a minute. Nothing beyond `python3` has to be
in place first:

- If **uv** is installed it is used, exactly as before: `uv tool install`
  puts a `kc8jcrigctl` command on your PATH.
- If it is not, a plain virtualenv is built in `.venv` with the standard
  library's `venv` and `pip`, a `./kc8jcrigctl` launcher is written, and it
  is symlinked into `~/.local/bin`. Pass `--no-link` to skip the symlink.

Either way you end up with a `kc8jcrigctl` command, and the script prints
the exact path to run if it is not on your PATH yet.

Before installing it also checks the two things that otherwise fail
confusingly at the radio rather than at install time:

- **Hamlib.** If `rigctl` and `rigctld` are missing it installs
  `libhamlib-utils` on Debian and Ubuntu, or tells you the `brew` command on
  macOS. A Hamlib built from source is found too, so this only fires when one
  is genuinely absent.
- **Serial port access.** On Linux, `/dev/ttyUSB*` belongs to the `dialout`
  group. Not being in it is the usual reason `rigctld` cannot open the radio,
  and it looks like a baud rate problem rather than a permissions one. The
  script prints the `usermod` line to fix it — it deliberately does not run
  it for you, because a group change needs a fresh login before it takes
  effect and doing it silently would leave you believing it had.

Re-run the script any time to pick up local changes; the install is a
snapshot copy, not a link back to the working tree. `./install.sh --uninstall`
removes the command, the launcher, the symlink and `.venv`.

## Running from a checkout

```sh
./install.sh --dev
```

With uv that runs `uv sync`, so use `uv run kc8jcrigctl`. Without it you get
an editable install plus pytest in `.venv`, and the script tells you the two
commands to use. Either way local edits take effect without reinstalling.

## Usage

- Type in the rig filter box to narrow the rig list by manufacturer, model,
  or numeric ID.
- Arrow through the rig table and device table to select each; the device
  path also populates a free-text field so you can type a manual value
  (e.g. `host:port` for Hamlib's NET rigctl backend, or a device path that
  wasn't auto-detected).
- Edit the TCP port or baud rate fields if you don't want the defaults
  (`4532`, and Hamlib's auto baud negotiation).
- Press **Connect** (or `c`) to launch `rigctld` with the selected
  parameters; press it again to stop it.
- Press **Power Off** / **Power On** (or `p`) to switch the radio itself on or
  off over CAT. See the caveat below -- it is a convenience, not a remote
  power switch.
- `r` refreshes the rig list, `u` refreshes the USB device list, `q` quits
  (stopping `rigctld` first if it's running).

While connected, the rig and device tables are replaced by a read-only summary
of what's in use, the port and baud fields become plain labels, and `rigctld`'s
live stdout/stderr is tailed in a scrollable pane below. The log is cleared at
the start of each connection.

Connecting isn't reported as successful until `rigctld` has actually answered a
`get_freq` on its TCP port. A `rigctld` that can't reach the rig still starts
and still listens -- it accepts a client, spends ten-plus seconds failing to
open the rig, then hangs up without replying, which clients report only as an
`i/o timeout`. Rather than showing that as connected, the app probes the port
itself, reports what Hamlib said, and shuts the daemon down.

Your last-used rig, device, port, and baud rate are saved to
`~/.config/kc8jcrigctl/config.json` and restored on the next launch.

## Rig power, and what it can't do

The power button sends Hamlib's `set_powerstat` down the same CAT link
`rigctld` is already holding open. That is the whole mechanism, and it sets the
whole limit:

- **It works while you are connected.** The button is disabled until `rigctld`
  is running, because there is no other path to the radio.
- **It reliably turns a rig off, and reliably turns that rig back on**, because
  stopping the radio does not stop `rigctld` -- the serial port stays open, so
  the wake-up command still has somewhere to go.
- **It usually cannot wake a rig that was switched off any other way.** Most
  radios stop listening to CAT entirely when they are properly off, so a rig
  killed at its own front panel, or one left off after you disconnected, has to
  be switched on by hand. Disconnecting while the rig is off prints a warning
  saying exactly this.

The label always names what pressing it would do next. On connect the app asks
the rig with `get_powerstat`; rigs that cannot answer that (it is a separate
capability from `set_powerstat`, and some backends have one without the other)
are assumed to be on, which they are, since they just answered a frequency
query. After a power-on the rig is asked again, so a radio that accepted the
command and ignored it shows up in the label rather than being believed --
but a power-off is trusted on its `RPRT 0` alone, with no follow-up query.
That asymmetry is deliberate: some backends (Elecraft's K3 and K3S among
them) cannot answer `get_powerstat` while actually off, and asking anyway
makes `rigctld` log an i/o error and reopen its handle to the rig, which was
enough to leave those radios unable to take the next `set_powerstat` and
power back on.

A rig whose backend has no power control at all reports that when the button is
pressed -- "this rig doesn't offer power control over CAT" -- rather than the
button being hidden or the failure being silent.

## Troubleshooting

If **Connect** fails with "the rig didn't answer", the usual cause is a baud
rate that doesn't match the radio's CI-V / serial menu setting -- the app's
`auto` default won't negotiate it for you on most backends. Check the rate the
radio is set to (an IC-7300's *CI-V USB Baud Rate*, for example, is often
`115200`) and enter it in the Baud field. If several USB serial adapters are
plugged in, also confirm the device row is the radio: its description or
serial number usually names the model.

## Tests

```sh
uv run pytest                     # with uv
.venv/bin/python -m pytest        # after ./install.sh --dev without uv
```
