Metadata-Version: 2.4
Name: microcycler
Version: 0.1.5
Summary: Python SDK for the Microcycler battery testing platform
Project-URL: Homepage, https://github.com/your-org/microcycler
Project-URL: Documentation, https://docs.microcycler.io
Project-URL: Issues, https://github.com/your-org/microcycler/issues
License: MIT
Keywords: EIS,battery,cycler,electrochemistry,lab,testing
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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 :: Chemistry
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.9
Provides-Extra: all
Requires-Dist: numpy>=1.24; extra == 'all'
Requires-Dist: pandas>=2.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-asyncio; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Provides-Extra: numpy
Requires-Dist: numpy>=1.24; extra == 'numpy'
Provides-Extra: pandas
Requires-Dist: pandas>=2.0; extra == 'pandas'
Description-Content-Type: text/markdown

# Microcycler Python SDK

Python SDK for the [Microcycler](https://github.com/your-org/microcycler) battery testing platform.

> **Status:** Pre-alpha — API subject to change.

## Installation

```bash
pip install microcycler
```

## Quickstart

### Connect and read telemetry

```python
import asyncio
from microcycler import Cycler

async def main():
    async with Cycler("192.168.1.100") as cycler:
        print(await cycler.identify())
        t = await cycler.get_telemetry()
        print(f"State:    {t.state}")
        print(f"Voltage:  {t.voltage:.3f} V")
        print(f"Current:  {t.current:.3f} A")
        print(f"Temp:     {t.temperature:.1f} °C")
        print(f"Capacity: {t.capacity_mah:.1f} mAh")

asyncio.run(main())
```

### Discover cyclers on the network

```python
from microcycler.streaming import discover

hosts = asyncio.run(discover())
print(hosts)  # ['192.168.1.100', '192.168.1.101']
```

### Stream live telemetry via UDP

```python
from microcycler.streaming import CyclerStream

async def monitor():
    async with CyclerStream() as stream:
        async for telemetry in stream:
            print(telemetry.voltage, telemetry.current)
```

### Build and run a recipe

```python
from microcycler import Cycler
from microcycler.recipes import Recipe, CC, CV, Rest, Loop

recipe = (
    Recipe(name="Standard Formation")
    .add(CC(current=0.1, cutoff_voltage_high=4.2))
    .add(CV(voltage=4.2, limit_current_high=0.1, cutoff_current_low=0.02))
    .add(Rest(duration=1800))
    .add(CC(current=-0.2, cutoff_voltage_low=2.8))
    .add(Rest(duration=1800))
    .add(Loop(cycles=3))
)

async def run():
    async with Cycler("192.168.1.100") as cycler:
        await cycler.load_recipe(recipe)
        await cycler.start()
```

## Recipe steps

| Step | Description |
|------|-------------|
| `CC(current, cutoff_voltage_high, cutoff_voltage_low, cutoff_time, cutoff_capacity)` | Constant current |
| `CV(voltage, limit_current_high, cutoff_current_low, cutoff_time)` | Constant voltage |
| `CP(power, cutoff_voltage, cutoff_time)` | Constant power |
| `CR(resistance, cutoff_voltage, cutoff_time)` | Constant resistance |
| `Rest(duration)` | Open-circuit rest |
| `EIS(freq_start, freq_end, amplitude, points_per_decade)` | Impedance sweep |
| `Loop(cycles)` | Repeat preceding steps N times |

## License

MIT
