pyhubblenetwork

pyhubblenetwork is a Python SDK for communicating with Hubble Network devices over Bluetooth Low Energy (BLE) and securely relaying data to the Hubble Cloud. It provides a simple API for scanning, sending, and managing devices—no embedded firmware knowledge required.
Table of contents
Quick links
Requirements & supported platforms
- Python 3.9+ (3.11/3.12 recommended)
- BLE platform prerequisites (only needed if you use
ble.scan()):
- macOS: CoreBluetooth; run in a regular user session (GUI).
- Linux: BlueZ required; user must have permission to access the BLE adapter (often
bluetooth group).
- Windows: Requires a compatible BLE stack/adapter.
- Satellite scanning prerequisites (only needed if you use
sat.scan()):
- Docker: Docker Desktop (macOS/Windows) or Docker Engine (Linux) must be installed and running.
- PlutoSDR: An Analog Devices ADALM-PLUTO SDR dongle connected via USB.
Installation
Users (stable release)
pip install pyhubblenetwork
# or install CLI into an isolated environment:
pipx install pyhubblenetwork
Developers (editable install)
From the repo root (recommended):
cd python
python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
Quick start
Scan locally, then ingest to backend
from hubblenetwork import ble, Organization
org = Organization(org_id="org_123", api_token="sk_XXX")
pkts = ble.scan(timeout=5.0)
if len(pkts) > 0:
org.ingest_packet(pkts[0])
else:
print("No packet seen within timeout")
Manage devices and query packets
from hubblenetwork import Organization
org = Organization(org_id="org_123", api_token="sk_XXX")
# Create a new device
new_dev = org.register_device()
print("new device id:", new_dev.id)
# List devices
for d in org.list_devices():
print(d.id, d.name)
# Get packets from a device (returns a list of DecryptedPacket)
packets = org.retrieve_packets(new_dev)
if len(packets) > 0:
print("latest RSSI:", packets[0].rssi, "payload bytes:", len(packets[0].payload))
Local decryption (when you have the key)
from hubblenetwork import Device, ble, decrypt
from typing import Optional
dev = Device(id="dev_abc", key=b"<secret-key>")
pkts = ble.scan(timeout=5.0) # might return a list or a single packet depending on API
for pkt in pkts:
maybe_dec = decrypt(dev.key, pkt)
if maybe_dec:
print("payload:", maybe_dec.payload)
else:
print("failed to decrypt packet")
Receive satellite packets
from hubblenetwork import sat
# sat.scan() manages the Docker container automatically:
# pulls the image, starts the container, polls for packets, and stops on exit.
for pkt in sat.scan(timeout=60.0):
print(f"device={pkt.device_id} seq={pkt.seq_num} rssi={pkt.rssi_dB} dB payload={pkt.payload.hex()}")
Docker must be running before calling sat.scan(). The PlutoSDR dongle must be connected.
CLI usage (optional)
If installed, the hubblenetwork command is available:
hubblenetwork --help
hubblenetwork ble scan
hubblenetwork ble scan --payload-format hex
hubblenetwork org get-packets --payload-format string
Payload format option
Commands that output packet data (ble scan, ble detect, org get-packets) support the --payload-format flag to control how payloads are displayed:
base64 (default) — encode payloads as base64
hex — display payloads as hexadecimal
string — decode payloads as UTF-8 text (falls back to <invalid UTF-8> if bytes are not valid UTF-8)
This applies to all output formats (tabular, json, csv).
Satellite scanning (PlutoSDR)