Usage Guide

Installation

pip install python-rayhunter

Requirements

Quick Start

All interaction with a Rayhunter device happens through RayhunterApi. Instantiate it with the hostname (or IP address) and port of your device:

from rayhunter import RayhunterApi

api = RayhunterApi(hostname="192.168.1.1", port=8080)

Checking Recording Status

The active_recording property returns True if a capture is currently in progress:

if api.active_recording:
    print("A recording is currently in progress")

Fetching the QMDL Manifest

The manifest lists all capture files available on the device, plus the currently active capture (if any). Use get_manifest() to retrieve it:

manifest = api.get_manifest()

for entry in manifest.entries:
    print(f"{entry.name} — started {entry.start_time}, size {entry.qmdl_size_bytes} bytes")

if manifest.current_entry:
    print(f"Active capture: {manifest.current_entry.name}")

Downloading Capture Files

Use the filenames from the manifest to download raw captures, PCAP files, or analysis reports.

# Raw QMDL capture data
qmdl_data = api.get_qmdl_file("capture.qmdl")

# PCAP file (dynamically generated from QMDL by the Rayhunter binary)
pcap_data = api.get_pcap_file("capture.qmdl")

# Analysis report
report_data = api.get_analysis_report_file("capture.qmdl")

# ZIP containing both the QMDL and the generated PCAP
zip_data = api.get_zip("capture.qmdl")

Controlling Recordings

# Start a new recording (stops any active recording first)
api.start_recording()

# Stop the current recording
api.stop_recording()

# Delete a specific recording
api.delete_recording("capture.qmdl")

# Delete all recordings (not available in debug mode)
api.delete_all_recordings()

System Statistics

get_system_stats() returns a SystemStats object containing disk, memory, and battery information:

stats = api.get_system_stats()

disk = stats.disk_stats
print(f"Partition:  {disk.partition} ({disk.mounted_on})")
print(f"Disk usage: {disk.used_size}/{disk.total_size} bytes ({disk.used_percent}% used)")

mem = stats.memory_stats
print(f"Memory:     {mem.used}/{mem.total} bytes used, {mem.free} bytes free")

meta = stats.runtime_metadata
print(f"Rayhunter {meta.rayhunter_version} on {meta.system_os} ({meta.arch})")

if stats.battery_status:
    bat = stats.battery_status
    print(f"Battery: {bat.level}% {'(charging)' if bat.is_plugged_in else ''}")

Configuration

Read and update the runtime configuration of a connected device using the configuration property or the lower-level get_config() / set_config() methods.

Warning

Setting the configuration triggers a device reboot.

config = api.configuration          # fetch current config
config.debug_mode = True
api.configuration = config          # push updated config (reboots device)

Analysis Status

Check which QMDL files have been analyzed, are queued, or are currently being processed:

status = api.get_analysis_status()

print("Finished:", status.finished)
print("Queued:  ", status.queued)
if status.running:
    print("Running: ", status.running)

Time

Retrieve the device clock and its current offset:

t = api.get_time()
print(f"System time: {t.system_time}")
print(f"Adjusted time (+{t.offset_seconds}s): {t.adjusted_time}")

Notifications

Trigger a test notification to the ntfy_url configured on the device:

api.send_test_notification()

Device Log

Download the current device log as raw bytes (UTF-8 plaintext):

log_bytes = api.get_log()
print(log_bytes.decode("utf-8"))