terra-listens-sdk 0.1.0
Python SDK for the Terra Listens bioacoustic monitoring platform
Requires Python: >=3.10

# Terra SDK

Python SDK for the [Terra Listens](https://terralistens.com) bioacoustic monitoring platform.

Wraps the Terra Listens backend API to provide programmatic access to bird detections, station data, weather, yard lists, and more.

## Installation

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e .
```

## Quick Start

```python
from terra_sdk import TerraClient

# From .env file (USERNAME, PASSWORD)
client = TerraClient.from_env()

# Or explicit credentials
client = TerraClient("you@example.com", "your-password")

# Or reuse an existing token
client = TerraClient(token="your-token")
```

## Usage

```python
from terra_sdk import TerraClient

client = TerraClient.from_env()

# List your stations
devices = client.get_devices()
station = devices[0]
print(f"{station.alias} - {station.id}")

# Get latest bird detections
birds = client.get_latest_birds(count=10, min_confidence=0.5)
for bird in birds:
    print(f"{bird.common_name} ({bird.confidence:.0%}) - {bird.timestamp}")
    print(f"  Audio: {bird.audio_url}")
    print(f"  Image: {bird.image_url}")

# Station stats
stats = client.get_stats()
print(f"{stats.unique_species} species, {stats.call_count} calls")
print(f"Top bird: {stats.top_bird}")

# Weather
weather = client.get_weather()
print(f"{weather.condition}, {weather.temp_f}°F")

# Yard life-list
yard = client.get_yard_list(timeframe="all")
for entry in yard:
    print(f"{entry.common_name}: {entry.sighting_count} sightings")

# Species list with confidence thresholds
species = client.get_species_list()
for s in species:
    print(f"{s.common_name} ({s.species_code}) threshold={s.threshold:.2f}")

# Biodiversity ranking
rank = client.get_biodiversity_rank()
print(f"Rank {rank.rank} of {rank.competitors} ({rank.percentile}th percentile)")

# Streams (global public feeds)
streams = client.get_streams()
for s in streams:
    print(f"{s.title}: {s.live_stream_url}")
```

If you have only one Terra station, `device_id` is auto-selected. Otherwise pass it explicitly:

```python
birds = client.get_latest_birds("0123FB1FA9136F95EE", count=5)
```

## CLI

Quick test from the command line:

```bash
python -m terra_sdk
```

## Environment Variables

Create a `.env` file:

```
USERNAME=you@example.com
PASSWORD=your-password
```

Or set `TERRA_TOKEN` directly if you already have one.

## API Methods

| Method | Description |
|--------|-------------|
| `login()` | Authenticate and get token |
| `get_devices()` | List your Terra stations |
| `get_user_info()` | Account profile |
| `get_latest_birds(device_id, count, min_confidence)` | Latest detections |
| `get_species_list(device_id)` | All species detected at station |
| `get_stats(device_id)` | Station statistics |
| `get_weather(device_id)` | Weather at station |
| `get_yard_list(device_id, timeframe)` | Yard life-list |
| `get_biodiversity_rank(device_id)` | Biodiversity ranking |
| `get_graph_stats(device_id)` | Call activity over time |
| `get_streams()` | Public audio streams |
| `get_notifications_list(device_id)` | Notification preferences |
| `get_station_tags(device_id)` | Radio tags (Motus) |
| `vote(detection_id, direction, device_id)` | Vote on bird ID |

## Models

All responses are typed Pydantic models:

- `BirdDetection` — common_name, scientific_name, alpha_code, confidence, timestamp, audio_url, image_url
- `Station` — id, alias, lat, lon, streaming, version
- `StationStats` — unique_species, call_count, top_bird
- `Weather` — temp_f, temp_c, condition, humidity, wind_mph
- `YardListEntry` — common_name, species_code, sighting_count, first_seen
- `SpeciesInfo` — common_name, species_code, threshold
- `Stream` — title, live_stream_url, streaming
- `BioDiversityRank` — rank, competitors, percentile
- `GraphStatsEntry` — ts, total_calls, unique_species

## Running Tests

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

## License

MIT