Metadata-Version: 2.4
Name: pico-tc08
Version: 0.1.0
Summary: Simple library for Pico Technology USB TC-08 thermocouple data logger — direct ctypes bindings, no picosdk required
Author-email: Asaf Ayalon <ayalon.asaf.c0@s.mail.nagoya-u.ac.jp>
License-Expression: MIT
Keywords: pico,tc08,thermocouple,temperature,data-logger,instrumentation,usbtc08
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Requires-Python: >=3.6
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.16.0
Provides-Extra: dev
Requires-Dist: setuptools; extra == "dev"
Requires-Dist: wheel; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: build; extra == "dev"

# pico-tc08

Simple Python library for the **Pico Technology USB TC-08** 8-channel thermocouple data logger.

Uses **direct ctypes bindings** to the Pico shared library — bypasses the official `picosdk` Python wrapper, which has a macOS-specific attribute-naming bug that prevents it from loading the library.

## Features

- All 8 channels with any mix of thermocouple types (B, E, J, K, N, R, S, T)
- Cold junction compensation temperature included in every reading
- Averaged readings over a configurable time window
- Continuous CSV logging (appends, runs until Ctrl+C)
- **Descriptive error messages** for all common failure modes (missing library, wrong CPU architecture, device not connected)
- Context manager support for safe resource cleanup

## Important: Apple Silicon (M1/M2/M3/M4)

> **The Pico TC-08 library ships as an x86_64 binary only.**
> It cannot run natively on Apple Silicon processors.

This library **detects this at startup** and prints clear instructions. See the [Apple Silicon Setup](#apple-silicon-setup-m1m2m3m4) section below.

## Installation

```bash
pip install pico-tc08
```

### Prerequisites

Install PicoLog for macOS from the Pico Technology website:

```
https://www.picotech.com/downloads
```

This installs `PicoLog.app` which contains the required `libusbtc08.dylib` library at:
```
/Applications/PicoLog.app/Contents/Resources/libusbtc08.dylib
```

## Apple Silicon Setup (M1/M2/M3/M4)

The Pico library is an **x86_64-only binary** — it must run under **Rosetta 2** (x86_64 emulation).

### Automated Setup (recommended)

Run the provided setup script once:
```bash
bash setup_arm_mac.sh
```

This creates a dedicated `tc08x86` conda environment under a Rosetta-compatible Miniconda installation. After setup:
```bash
conda activate tc08x86
python your_script.py
```

### Manual Quick Fix

For a one-off run without the setup script:
```bash
arch -x86_64 python your_script.py
```

### How the error looks

If you try to import `pico_tc08` on Apple Silicon without Rosetta, you get:

```
======================================================================
  APPLE SILICON DETECTED — Rosetta 2 required
======================================================================

  You are running Python natively on ARM64 (Apple Silicon).
  The Pico library at:
    /Applications/PicoLog.app/Contents/Resources/libusbtc08.dylib
  is an x86_64 binary and CANNOT run on ARM processors.

  FIX OPTION 1 — Quick run under Rosetta 2:
    arch -x86_64 python your_script.py

  FIX OPTION 2 — Create a dedicated x86_64 conda environment:
    bash setup_arm_mac.sh
    conda activate tc08x86
    python your_script.py
======================================================================
```

## Quick Start

### 1. Check your environment

```python
from pico_tc08 import check_environment
check_environment()  # raises RuntimeError with clear instructions if anything is wrong
```

### 2. Single reading

```python
from pico_tc08 import quick_read

sample = quick_read(channel_types={1: "K", 2: "K"})
if sample:
    print(f"Cold junction: {sample.cold_junction:.2f} °C")
    for ch, temp in sample.channels.items():
        print(f"  CH{ch}: {temp:.2f} °C")
```

### 3. Continuous CSV logging

```python
from pico_tc08 import log_csv

log_csv(
    out_csv="temperatures.csv",
    channel_types={1: "K", 2: "K", 3: "T"},
    interval_seconds=300.0,       # log every 5 minutes
    sample_window_seconds=5.0,    # average over 5 seconds per log entry
    mains_hz=50,
)
```

### 4. Full device control

```python
from pico_tc08 import TC08Device

with TC08Device(channel_types={1: "K", 2: "K", 3: "T", 4: "J"}, mains_hz=50) as dev:
    # Single reading
    sample = dev.read_once()
    print(f"Cold junction: {sample.cold_junction:.2f} °C")
    for ch, temp in sample.channels.items():
        print(f"  CH{ch}: {temp:.2f} °C")

    # Averaged reading over 10 seconds
    last, stats, (cjc_mean, cjc_std) = dev.sample_window(window_seconds=10.0)
    for ch, (mean_c, std_c) in stats.items():
        print(f"  CH{ch}: {mean_c:.2f} ± {std_c:.3f} °C")
```

## API Reference

### `check_environment(lib_path=None)`
Verify that the environment is correctly configured. Raises `RuntimeError` with instructions if anything is missing or misconfigured.

### `TC08Device` Class

#### `__init__(channel_types=None, mains_hz=50, lib_path=None)`

| Parameter | Default | Description |
|-----------|---------|-------------|
| `channel_types` | `{1: "K"}` | Dict mapping channel (1–8) to thermocouple type |
| `mains_hz` | `50` | Mains frequency for noise filtering (50 or 60 Hz) |
| `lib_path` | platform default | Override library path |

Thermocouple types: `"B"`, `"E"`, `"J"`, `"K"`, `"N"`, `"R"`, `"S"`, `"T"`

#### Methods

| Method | Returns | Description |
|--------|---------|-------------|
| `open()` | — | Open USB connection and configure channels |
| `close()` | — | Close USB connection |
| `read_once(retries=10)` | `Sample` | Single temperature reading |
| `sample_window(window_seconds=5.0)` | `(Sample, dict, tuple)` | Averaged reading over a time window |

#### Context Manager
```python
with TC08Device({1: "K"}) as dev:
    sample = dev.read_once()
# device automatically closed on exit
```

### `Sample` Dataclass

| Attribute | Type | Description |
|-----------|------|-------------|
| `t_wall` | float | Wall-clock timestamp (`time.time()`) |
| `t_mono` | float | Monotonic timestamp (safe for duration math) |
| `cold_junction` | float | Cold junction compensation temperature (°C) |
| `channels` | dict | `{channel_number: temperature_C}` |

### Convenience Functions

#### `log_csv(out_csv, channel_types, interval_seconds=300, sample_window_seconds=5, mains_hz=50)`
Run continuous CSV logging until Ctrl+C. Appends to existing file.

#### `quick_read(channel_types=None, mains_hz=50) -> Optional[Sample]`
Connect, read once, disconnect. Returns `Sample` or `None` on failure.

## CSV Output Format

```csv
t_wall,cold_mean_C,cold_std_C,ch1_mean_C,ch1_std_C,ch2_mean_C,ch2_std_C
1740000000.123,23.45,0.12,85.23,0.15,82.11,0.13
1740000300.456,23.47,0.11,86.01,0.14,82.98,0.12
```

- `t_wall`: Unix timestamp of the reading
- `cold_mean_C` / `cold_std_C`: Cold junction mean and standard deviation
- `chN_mean_C` / `chN_std_C`: Channel N mean and standard deviation

## Notes

- **Always close PicoLog** before using this library — it holds the USB device
- The minimum sampling interval is 200 ms (hardware limitation)
- Channels not listed in `channel_types` are disabled
- On macOS, the library is loaded from inside `PicoLog.app` — do not uninstall PicoLog

## License

MIT License
