Skip to content

Getting Started

This guide will walk you through the basics of using RepeaterBook to access and work with amateur radio repeater data.

What is RepeaterBook?

RepeaterBook is a Python library that provides a convenient interface to RepeaterBook.com, a comprehensive database of amateur radio repeaters worldwide. It allows you to:

  • Download repeater data from the RepeaterBook API
  • Store repeater information in a local SQLite database
  • Query repeaters by location, frequency, capabilities, and more
  • Filter repeaters based on distance from a point
  • Work with different digital modes (DMR, P25, NXDN, etc.)

Installation

Prerequisites

  • Python 3.10 or higher
  • pip, uv, or Poetry for package management

Install from PyPI

uv add repeaterbook
pip install repeaterbook
poetry add repeaterbook

Install from Source

To install the latest development version:

uv add git+https://github.com/MicaelJarniac/repeaterbook
pip install git+https://github.com/MicaelJarniac/repeaterbook

Quick Start

1. Download Repeater Data

First, let's download repeater data for a specific region. RepeaterBook provides data for different countries and states.

import asyncio
from repeaterbook.services import RepeaterBookAPI
from repeaterbook.models import ExportQuery
import pycountry

async def download_repeaters():
    # Create an API client
    api = RepeaterBookAPI()

    # Download repeaters for Brazil
    brazil = pycountry.countries.get(name="Brazil")
    repeaters = await api.download(
        query=ExportQuery(countries={brazil})
    )

    print(f"Downloaded {len(repeaters)} repeaters")
    return repeaters

# Run the async function
repeaters = asyncio.run(download_repeaters())

2. Store in Local Database

Now let's store the downloaded data in a local SQLite database for easier querying:

from repeaterbook import RepeaterBook

# Create a database connection (defaults to repeaterbook.db)
rb = RepeaterBook()

# Populate the database with our repeaters
rb.populate(repeaters)

print(f"Database populated with {len(repeaters)} repeaters")

3. Query Repeaters

With data in the database, you can perform various queries:

from repeaterbook import Repeater
from repeaterbook.models import Status, Use

# Find all operational open repeaters
results = rb.query(
    Repeater.operational_status == Status.ON_AIR,
    Repeater.use_membership == Use.OPEN
)

print(f"Found {len(results)} open repeaters")

# Print first 5 repeaters
for repeater in results[:5]:
    print(f"{repeater.frequency:.4f} MHz - {repeater.callsign} - {repeater.location_nearest_city}")

4. Geographic Queries

Find repeaters near a specific location:

from repeaterbook.utils import LatLon, Radius
from repeaterbook.queries import filter_radius, square

# Define a search area (São Paulo, Brazil)
sao_paulo = LatLon(lat=-23.5505, lon=-46.6333)
radius = Radius(
    origin=sao_paulo,
    distance=50  # kilometers
)

# Find repeaters within the square bounding box
nearby = rb.query(square(radius))

# Filter by actual distance from origin
nearby_exact = filter_radius(nearby, radius)

print(f"Found {len(nearby_exact)} repeaters within 50km of São Paulo")

# Print repeaters with distances
# filter_radius returns repeaters sorted by distance, but doesn't add distance attribute
from haversine import haversine
for repeater in nearby_exact[:5]:
    distance = haversine(sao_paulo, (repeater.latitude, repeater.longitude))
    print(f"{distance:.1f}km - {repeater.frequency:.4f} MHz - {repeater.callsign}")

5. Filter by Capabilities

Find repeaters with specific digital modes:

from repeaterbook.queries import Bands, band

# Find DMR-capable repeaters on 2m or 70cm bands
dmr_repeaters = rb.query(
    Repeater.dmr_capable == True,
    band(Bands.M_2, Bands.CM_70),
    Repeater.operational_status == Status.ON_AIR
)

print(f"Found {len(dmr_repeaters)} DMR repeaters")

for repeater in dmr_repeaters[:5]:
    modes = []
    if repeater.dmr_capable:
        modes.append("DMR")
    if repeater.apco_p_25_capable:
        modes.append("P25")
    if repeater.nxdn_capable:
        modes.append("NXDN")

    print(f"{repeater.callsign} - {repeater.frequency:.4f} MHz - {', '.join(modes)}")

Complete Example

Here's a complete example that ties everything together:

import asyncio
from repeaterbook import RepeaterBook, Repeater
from repeaterbook.services import RepeaterBookAPI
from repeaterbook.models import ExportQuery, Status, Use
from repeaterbook.utils import LatLon, Radius
from repeaterbook.queries import filter_radius, square, band, Bands
import pycountry

async def main():
    # 1. Download repeater data
    api = RepeaterBookAPI()
    brazil = pycountry.countries.get(name="Brazil")

    print("Downloading repeaters...")
    repeaters = await api.download(
        query=ExportQuery(countries={brazil})
    )
    print(f"Downloaded {len(repeaters)} repeaters")

    # 2. Store in database
    rb = RepeaterBook(database="my_repeaters.db")
    rb.populate(repeaters)

    # 3. Find DMR repeaters near São Paulo
    sao_paulo = LatLon(lat=-23.5505, lon=-46.6333)
    radius = Radius(origin=sao_paulo, distance=50)

    nearby = rb.query(
        square(radius),
        Repeater.dmr_capable == True,
        Repeater.operational_status == Status.ON_AIR,
        Repeater.use_membership == Use.OPEN,
        band(Bands.CM_70)  # 70cm band
    )

    nearby_filtered = filter_radius(nearby, radius)

    print(f"\nFound {len(nearby_filtered)} DMR repeaters within 50km:")
    # filter_radius returns repeaters sorted by distance
    # Calculate distances for display
    from haversine import haversine
    for rep in nearby_filtered[:10]:
        distance = haversine(radius.origin, (rep.latitude, rep.longitude), unit=radius.unit)
        print(f"  {distance:5.1f}km - {rep.frequency:.4f} MHz - {rep.callsign:8s} - {rep.location_nearest_city}")

if __name__ == "__main__":
    asyncio.run(main())

Next Steps

Now that you understand the basics, explore:

Tips

  • Caching: The API client automatically caches responses to avoid unnecessary downloads
  • Database Updates: Use rb.populate() to merge new data without duplicates
  • Async/Await: Most API operations are asynchronous for better performance
  • Units: Distance calculations use kilometers by default (configurable with haversine units)
  • Filtering: Combine multiple query conditions using standard SQLAlchemy expressions

Common Patterns

Search by State (USA)

from repeaterbook.models import ExportQuery
import pycountry

usa = pycountry.countries.get(alpha_2="US")
query = ExportQuery(countries={usa}, state_ids={"06", "32"})  # CA, NV (FIPS codes)
repeaters = await api.download(query=query)

Find All Digital Modes

digital_repeaters = rb.query(
    (Repeater.dmr_capable | Repeater.apco_p_25_capable | Repeater.nxdn_capable),
    Repeater.operational_status == Status.ON_AIR
)

Export to DataFrame

import pandas as pd

results = rb.query(Repeater.operational_status == Status.ON_AIR)
df = pd.DataFrame([r.model_dump() for r in results])
print(df.head())