# ingress-edge Python SDK

Python SDK for sending telemetry data to vikdata ingress cores.

## Features

- **Auto-batching**: Automatically batches data points by size (default: 100) or timeout (default: 5s)
- **Retry logic**: Exponential backoff with configurable max attempts (default: 5)
- **Offline buffering**: Stores up to 10,000 points when network is unavailable
- **Type-safe**: Full Pydantic v2 validation for all data
- **Async-first**: Built on asyncio and httpx for modern Python applications

## Installation

```bash
pip install ingress-edge
```

## Quick Start

```python
import asyncio
from datetime import datetime
from ingress_edge import IngressClient, IngressDataPoint, IngressClientConfig

async def main():
    # Configure client
    config = IngressClientConfig(
        base_url="https://ingress.vikdata.io",
        api_key="your-device-api-key",
        batch_size=100,        # Optional (default: 100)
        batch_timeout=5.0,     # Optional (default: 5.0 seconds)
        max_retries=5,         # Optional (default: 5)
        offline_buffer_size=10000,  # Optional (default: 10000)
    )

    # Create and use client
    async with IngressClient(config) as client:
        # Send a data point
        await client.send(IngressDataPoint(
            channel_id="telemetry:vessel_123",
            timestamp=datetime.now(),
            data={
                "latitude": 59.9139,
                "longitude": 10.7522,
                "speed_knots": 12.5,
                "heading": 135.0,
            }
        ))

        # Send more points (auto-batched)
        for i in range(50):
            await client.send(IngressDataPoint(
                channel_id="telemetry:vessel_123",
                timestamp=datetime.now(),
                data={"sensor_reading": i * 10}
            ))

        # Force flush current batch
        await client.flush()

asyncio.run(main())
```

## Configuration

### IngressClientConfig

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `base_url` | str | *required* | Base URL of the ingress core |
| `api_key` | str | *required* | API key for authentication |
| `batch_size` | int | 100 | Number of points before auto-flush |
| `batch_timeout` | float | 5.0 | Seconds before auto-flush |
| `max_retries` | int | 5 | Maximum retry attempts |
| `offline_buffer_size` | int | 10000 | Maximum points to buffer offline |

## Offline Mode

The client automatically buffers data points when offline and sends them when connectivity is restored.

```python
async with IngressClient(config) as client:
    # Send points (buffered if offline)
    await client.send(point1)
    await client.send(point2)

    # Manually control online/offline status
    await client.set_online(False)  # Go offline
    await client.send(point3)  # Buffered

    await client.set_online(True)  # Come online (auto-drains buffer)

    # Check buffer stats
    stats = client.get_buffer_stats()
    print(f"Buffer: {stats.size}/{stats.max_size} points")
```

## API Reference

### IngressClient

#### Methods

- `async send(point: IngressDataPoint)` - Send a data point (auto-batched)
- `async flush()` - Force flush current batch immediately
- `async set_online(online: bool)` - Set online/offline status
- `async drain_offline_buffer()` - Manually drain offline buffer
- `get_buffer_stats() -> BufferStats` - Get offline buffer statistics
- `get_pending_count() -> int` - Get points pending in current batch
- `is_client_online() -> bool` - Check if client is online
- `async close()` - Close HTTP client and cleanup

### Types

#### IngressDataPoint

```python
class IngressDataPoint(BaseModel):
    channel_id: str  # Channel identifier (min length: 1)
    timestamp: datetime  # ISO 8601 datetime
    data: dict[str, Any]  # Arbitrary JSON data
```

#### BufferStats

```python
class BufferStats(BaseModel):
    size: int  # Current points in buffer
    max_size: int  # Maximum buffer capacity
    is_at_capacity: bool  # Whether buffer is full
```

## Development

### Setup

```bash
# Clone repository
git clone https://github.com/vikmar/vikdata
cd vikdata/sdk/python/ingress-edge

# Install with dev dependencies
pip install -e ".[dev]"
```

### Running Tests

```bash
# Run tests
pytest

# With coverage
pytest --cov=ingress_edge --cov-report=html

# Type checking
mypy src/ingress_edge/

# Linting
ruff check src/ tests/
ruff format src/ tests/
```

## Architecture

The ingress-edge SDK is designed for edge devices (vessels, sensors, IoT) to send data to vikdata ingress cores:

```
┌─────────────┐
│   Device    │
│  (Python)   │
└──────┬──────┘
       │ ingress-edge SDK
       │ - Auto-batching
       │ - Retry logic
       │ - Offline buffer
       ▼
┌──────────────┐
│ Ingress Core │
│ (5-stage)    │
└──────┬───────┘
       │ Validates, transforms, routes
       ▼
┌──────────────┐
│   Services   │
│  (fishinfo)  │
└──────────────┘
```

## License

MIT

## Links

- [GitHub Repository](https://github.com/vikmar/vikdata)
- [Documentation](https://docs.vikmar.io/ingress/edge/python)
- [Issue Tracker](https://github.com/vikmar/vikdata/issues)
