Metadata-Version: 2.4
Name: wisent-wire-sdk
Version: 0.5.0
Summary: Python client library for the Wisent Wire hardware testing platform API
Author-email: Wisent Wire <info@wisent-wire.com>
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28
Requires-Dist: tenacity>=8.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: types-requests>=2.28; extra == "dev"
Dynamic: license-file

# Wisent Wire Python SDK

Python client library for the [WisentWire](https://wisent-wire.com) hardware testing platform.

## Installation

```bash
pip install wisent-wire-sdk
```

## Quick start

```python
from wisentwire import WisentWireClient

# API key (recommended — scripts, CI, MCP)
client = WisentWireClient(
    base_url="https://int.wisent-wire.com",
    api_key="wwk_...",   # or set WISENTWIRE_API_KEY env var
)

# Cognito (email + password)
client = WisentWireClient(
    base_url="https://int.wisent-wire.com",
    email="user@company.com",
    password="secret",
)

# Pre-existing bearer token
client = WisentWireClient(
    base_url="https://int.wisent-wire.com",
    token="eyJhbGciOi...",
)
```

Create an API key from the web app under **Settings → API keys**. Keys
are shown once — store securely. Default expiry is 1 year; max 10 active
keys per user.

## Usage

### WisentWires

```python
wws = client.list_wisentwires()
ww = client.get_wisentwire(ww_id=1)
```

### Power supply

```python
client.set_power_supply(ww_id=1, state="ON", voltage=5.0, current=2.0)
shadow = client.wait_shadow_state(ww_id=1, expected_state="ON")
print(shadow.reported.voltage_setpoint)
```

### Firmware & flash

```python
fw = client.upload_firmware("app.bin", firmware_bytes, "STM32F4")
job_id = client.flash(ww_id=1, firmware_id=fw.id)
client.wait_flash_complete(ww_id=1, job_id=job_id)
```

### UART

```python
client.send_uart_ascii(ww_id=1, text="HELLO")
msg = client.wait_for_uart_rx(ww_id=1, match_hex="48454C4C4F")
print(msg.bytes_hex)
```

### Telemetry

```python
readings = client.get_power_telemetry(ww_id=1)
```

### Reservations

```python
reservations = client.list_reservations()
```

### Organization

```python
org = client.get_organization()
members = client.list_members()
```

## Error handling

All API errors raise typed exceptions inheriting from `WisentWireError`:

```python
from wisentwire import NotFoundError, ConflictError

try:
    client.get_wisentwire(ww_id=999)
except NotFoundError as e:
    print(f"WisentWire not found: {e}")
```

| HTTP status | Exception               |
|-------------|-------------------------|
| 400         | `BadRequestError`       |
| 401         | `AuthenticationError`   |
| 403         | `ForbiddenError`        |
| 404         | `NotFoundError`         |
| 409         | `ConflictError`         |
| 429         | `RateLimitError`        |
| 503         | `ServiceUnavailableError` |

## Development

```bash
pip install -e ".[dev]"
pytest tests/ -v
```

## Requirements

- Python >= 3.10
- `requests` >= 2.28
- `tenacity` >= 8.0
