igm402 0.1.0
Add your description here
Requires Python: >=3.11

# igm402

Python driver for the Hornet IGM402 over serial or TCP serial gateways.

## Install

```bash
uv add igm402
```

Or for local development:

```bash
uv sync
```

## Suggested usage

```python
from igm402 import HornetIGM402, SerialTransport, SocketTransport

# Serial
t = SerialTransport(port="/dev/ttyUSB0", baudrate=19200, timeout_s=0.3)
g = HornetIGM402(t, address=1)

with g:
	print(g.read_sw_version())
	print(g.read_system_pressure_torr())

# TCP gateway
t = SocketTransport(host="192.168.1.50", port=4001, timeout_s=0.3)
g = HornetIGM402(t, address=1)

with g:
	print(g.read_sw_version())
	# g.set_baud(9600) -> raises IGM402UnsupportedTransportOperationError
```

## Without `with g:`

Use explicit `open()` / `close()` with `try/finally`:

```python
from igm402 import HornetIGM402, SerialTransport

t = SerialTransport(port="/dev/ttyUSB0", baudrate=19200, timeout_s=0.3)
g = HornetIGM402(t, address=1)

g.open(probe=True)
try:
	print(g.read_sw_version())
	print(g.read_system_pressure_torr())
finally:
	g.close()
```

If you already know the link is configured correctly and want faster startup, use `g.open(probe=False)`.

## Notes

- `read_pressure_unit()` returns a `str` enum (`PressureUnit`), so direct checks like `== "T"` work.
- `read_emission_setting()` returns an `int` enum (`EmissionSetting`), so direct checks like `== 0` work.
- Serial reconfiguration (`set_baud()`, `set_parity()`) is only supported with `SerialTransport`.

## Quick API overview

Common read operations:

- `read_sw_version()`
- `read_ig_pressure_torr()`
- `read_system_pressure_torr()`
- `read_cg_pressure_torr(1 | 2)`
- `read_ig_status_code()`
- `read_pressure_unit()`
- `read_emission_setting()`

Common control operations:

- `ig_on()`, `ig_off()`
- `degas_on()`, `degas_off()`
- `set_emission(EmissionSetting.U100 | EmissionSetting.MA4)`
- `set_filament(1 | 2)`
- `set_pressure_unit(PressureUnit.TORR | PressureUnit.MBAR | PressureUnit.PASCAL)`

Relay/trip point operations:

- `set_trip_point(relay, mode, value_torr)`
- `read_trip_point(relay, mode)`

Where:

- `relay` is `RelayName.I | RelayName.A | RelayName.B`
- `mode` is `"on_below" | "off_above"`

## Capability probing

By default, entering `with g:` calls `open(probe=True)` which:

1. Verifies ASCII protocol connectivity
2. Probes optional command families and sets:
   - `g.supports_ru`
   - `g.supports_rdig`

If you want to skip probing (faster startup), call `g.open(probe=False)`.

## Enum-friendly comparisons

Because returned enums inherit from primitive types, both patterns work:

```python
unit = g.read_pressure_unit()     # PressureUnit (str enum)
if unit == "T":
	print("Torr")

em = g.read_emission_setting()    # EmissionSetting (int enum)
if em == 1:
	print("4 mA mode")
```

## Error handling

Typical exceptions:

- `IGM402TimeoutError`: no response before timeout
- `IGM402ProtocolError`: malformed/invalid frame or payload
- `IGM402DeviceError`: explicit device-side error response (`?...`)
- `IGM402UnsupportedTransportOperationError`: serial-only command used on socket transport

Example:

```python
from igm402.driver import (
	IGM402TimeoutError,
	IGM402ProtocolError,
	IGM402DeviceError,
)

try:
	p = g.read_system_pressure_torr()
except IGM402TimeoutError:
	print("Timeout talking to gauge")
except IGM402DeviceError as e:
	print(f"Gauge error: {e.code} / {e.message}")
except IGM402ProtocolError:
	print("Protocol mismatch (address/settings/mode)")
```

## Serial communication reconfiguration

Serial-only helpers:

- `set_baud(baud, verify=True, ...)`
- `set_parity("N" | "O" | "E", verify=True, ...)`
- `set_serial_comm(baud=..., parity=..., verify_each_step=True, ...)`

These commands are disruptive by nature. The driver relinks and can verify communication after each step.

## Troubleshooting checklist

- Confirm RS485 address (`address`) matches the gauge address.
- Match serial settings (baud/parity/8N1) before probing.
- Increase transport timeout (`timeout_s`) on slower links.
- If using a TCP serial gateway, verify raw TCP mode and no line-ending translation.
- If probing fails, try `open(probe=False)` and call `read_sw_version()` manually to isolate startup issues.