Metadata-Version: 2.4
Name: actuisense
Version: 0.6.2
Summary: Cross-platform terminal UI to configure Actisense NMEA 2000 gateways (NGT-1/NGW-1/NGX-1) over serial or TCP
Author: phobicdotno
License: MIT
Project-URL: Homepage, https://github.com/phobicdotno/actuisense
Project-URL: Issues, https://github.com/phobicdotno/actuisense/issues
Keywords: actisense,nmea2000,ngt-1,ngw-1,ngx-1,canbus,tui,marine
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyserial>=3.5
Requires-Dist: textual>=0.50
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: paramiko>=2.7; extra == "dev"
Provides-Extra: wago
Requires-Dist: paramiko>=2.7; extra == "wago"
Dynamic: license-file

# AcTuiSense

A cross-platform **terminal UI to configure Actisense NMEA 2000 gateways**
(NGT-1, NGW-1, NGX-1) over a serial port or TCP — the open, scriptable alternative
to the Windows-only **Actisense NMEA Reader → Hardware Configuration**.

Runs anywhere Python runs: **Linux, macOS, and Windows (PowerShell / Windows
Terminal)**.

![AcTuiSense PGN filter tab](docs/screenshot.svg)

**Activity Log tab** — every gateway exchange (line, time, action, result, detail),
fed by a live Get-Operating-Mode poll plus your own actions, just like NMEA Reader's
command log:

![AcTuiSense activity log tab](docs/screenshot-log.svg)

**Firmware tab** — update **NGX-1 / WGX-1** firmware over the reverse-engineered
**BstFt** protocol, no Actisense Toolkit required: read the currently-installed version,
**Browse…** for the `.zip`, and watch a live progress bar while the whole archive
streams to the gateway (which decrypts the inner `.actp` itself):

![AcTuiSense firmware tab](docs/firmware-tab.png)

> Validated end-to-end against a real **Actisense NGT-1** and **NGX-1** — reading the
> operating mode and Rx/Tx enable lists, toggling per-PGN filters, activating, and
> committing to EEPROM.

## Why

The NGT-1 will only **transmit** a PGN onto the bus if that PGN is in its **Tx PGN
Enable List**, and only **receives** the PGNs in its **Rx PGN Enable List** when in
Filter mode. By default these lists are minimal, so injected/forwarded application
PGNs are silently dropped. Actisense ships a Windows GUI to edit these lists;
AcTuiSense does the same job from any terminal, plus a plain CLI for automation.

> Heads-up: this writes to your gateway's configuration (and optionally its
> EEPROM). It is an independent project, **not affiliated with Actisense**. See
> [CREDITS.md](CREDITS.md) for protocol provenance.

## Install

```bash
# install straight from GitHub (recommended), with the WAGO/can0 extra:
pipx install "actuisense[wago] @ git+https://github.com/phobicdotno/actuisense.git"

# core only (serial / TCP gateway config, no can0 monitor):
pipx install "git+https://github.com/phobicdotno/actuisense.git"

# from a local checkout:
pipx install ".[wago]"          # or:  pip install -e ".[wago]"
```

Use `pip install --user "<same spec>"` instead of `pipx` if you prefer.

The TUI checks GitHub once at startup for a newer release (fail-silent, works fine
offline) and shows a toast when one exists; `actuisense --version` prints the same
hint. Opt out with `ACTUISENSE_NO_UPDATE_CHECK=1`.
Requires Python ≥ 3.9, `pyserial`, and `textual` (plus `paramiko` for `[wago]`).

## Use

### TUI

```bash
actuisense tui                           # start disconnected, then pick a connection
actuisense tui -p /dev/ttyUSB0          # Linux/macOS serial
actuisense tui -p COM5                   # Windows
actuisense tui -p tcp://192.168.1.50:60002   # networked gateway (e.g. W2K-1)
```

Arrow keys / mouse to move, **space** toggles the RX or TX box on the focused PGN,
type in the filter box to narrow the list, then **Commit → EEPROM** to persist.

**Connection dialog** (`Ctrl+O`): choose the source without restarting — a serial
port (auto-detected ports are listed) + baud, a `tcp://` gateway, or a **WAGO PLC**.

### Bus Monitor — listen on a WAGO PLC's can0

A WAGO PFC200 on the same NMEA 2000 backbone exposes the bus as SocketCAN (`can0`).
Log in with a username/password over SSH and the **Bus Monitor** tab streams live
traffic straight off the wire — the ground truth for what the gateway is actually
transmitting. Pick *WAGO PLC (can0)* in the Connection dialog, or from the CLI:

```bash
actuisense monitor --host 10.0.0.202 -u root -P wago          # decoded can0 dump
actuisense monitor --host 10.0.0.202 -u root -P wago --iface can1 -n 50
```

Read-only: it never writes to the bus or the gateway. Needs the `wago` extra
(`pip install actuisense[wago]`, which adds paramiko).

### CLI (scriptable, no UI)

```bash
actuisense info        -p /dev/ttyUSB0           # hardware + operating mode + lists
actuisense enable  tx 127512 127514 127751 -p /dev/ttyUSB0 --commit
actuisense disable rx 130306 -p /dev/ttyUSB0
actuisense mode rxall  -p /dev/ttyUSB0           # filter | rxall | convert
actuisense mode convert -p COM5                  # NMEA 0183<->2000 conversion mode
actuisense list tx     -p /dev/ttyUSB0
actuisense fw NGX-1-Release-v3.068.1986.zip -p COM5   # NGX-1/WGX-1 firmware update (CRC auto-filled for known files)
actuisense baud        -p COM5                   # show serial baud codes; --set 5,7 to change (Convert mode only)
```

### Firmware update (NGX-1 / WGX-1)

`actuisense fw <firmware.zip>` (and the **Firmware** tab in the TUI) push an Actisense
firmware `.zip` to the gateway over the reverse-engineered **BstFt** protocol — no
Actisense Toolkit needed. The whole `.zip` is streamed in 200-byte windows with
XON/XOFF flow control; the device unwraps and decrypts the inner `.actp` itself.

- **Progress bar** with percent / KB / rate / ETA, and a confirmation prompt.
- **CRC**: the Actisense end-of-transfer CRC-32 uses a non-standard polynomial that
  isn't recovered yet, so the CRC is **auto-filled by filename** for files we've seen
  (e.g. `NGX-1-Release-v3.068.1986.zip`). For any other file, pass it explicitly with
  `--crc 0x…` (read from a Toolkit `*-bstft.log`); a wrong/placeholder CRC is safely
  **rejected** by the device (nothing is flashed).
- The gateway must be in **Convert** mode at the chosen baud — set it directly with
  `actuisense mode convert` (no NMEA Reader / power-cycle needed).
- **115200 baud pre-flight**: firmware updates are refused when the serial link is
  not at 115200 baud (the NGX-1-USB factory rate). A gateway whose stored baud has
  drifted (e.g. to 38400) half-works at other speeds and has caused very confusing
  failed-update sessions — normalize it first (`actuisense baud` or the Toolkit
  *Hardware Config* tab), reconnect at 115200, then flash. CLI escape hatch:
  `--force-baud`. The TUI header always shows the current **mode + baud** so a
  drifted link is visible at a glance.

⚠️ Do not remove power until the gateway's LED returns to its normal pulse. Protocol
details: [`docs/reverse-engineering/bstft/`](docs/reverse-engineering/bstft/).

## Settings coverage

| Setting | CLI | TUI | Notes |
|---|---|---|---|
| Operating mode (Filter / Receive-All / Convert) | `mode` | `m` | the `0x11` command (Filter=1, Receive-All=2, Convert=4) |
| Per-PGN **Rx** enable (all 339 PGNs) | `enable/disable rx` | `r` | `0x46` |
| Per-PGN **Tx** enable (all 339 PGNs) | `enable/disable tx` | `t` | `0x47` |
| Activate enable lists | implicit | `a` | `0x4B` |
| Commit to EEPROM (persist) | `--commit` | `c` | `0x01` |
| Read current Rx/Tx lists & mode | `info` / `list` | on connect | parsed |
| Raw diagnostic queries (hw/product/total-time) | `raw` | — | read-only hex; vendor-binary fields are **not** guessed |
| Serial (port) baud codes | `baud` / `--set` | — | `0x12`/`0x16` GET+SET; codes read from device or supplied explicitly (closed rate<->code table) |
| Activity log of every exchange (+ live poll) | — | Activity Log tab | line/time/action/result/detail; `p` pauses polling |
| Choose connection (serial/baud, TCP, WAGO) | `-p` / `monitor` | `Ctrl+O` | serial port auto-detect; start disconnected |
| Live can0 bus monitor (via WAGO PLC SSH) | `monitor` | Bus Monitor tab | read-only `candump`; per-PGN/source aggregation |
| Firmware update (NGX-1 / WGX-1) | `fw` | Firmware tab | BstFt transfer with live progress bar; Browse for the `.zip`, reads the installed version, CRC auto-filled for known files; see `docs/reverse-engineering/bstft/` |

Deliberately **not** wired up yet: NMEA 0183 P-code, and
duplicate-filtering — these can disrupt the link, and their payloads are not
publicly specified, so they are left out rather than guessed. Device model/firmware
identification (via N2K PGN 126996) is a planned addition. The `protocol` module
already encodes the full Actisense command set, so adding these is straightforward
once each is verified against hardware.

## Status

Early but working: the protocol codec is validated against real NGT-1 captures
(see the tests). See [CHANGELOG.md](CHANGELOG.md) for what's wired up.

## License

MIT — see [LICENSE](LICENSE).
