Skip to main content

Unofficial Python library and CLI for communicating with Alti-2 skydiving altimeters

Project description

pyaltitool

PyPI Python License: MIT

Unofficial Python library and CLI for communicating with Alti-2 skydiving altimeters over USB serial.

Device Status
Atlas Expected to work
Atlas 2 Tested, works
Atlas 2 Student Expected to work
Juno Expected to work
MA-12 Expected to work
MA-15A Expected to work

Features

  • Read device information (serial number, firmware version, jump count, etc.)
  • Read jump logbook records with full field parsing
  • Export logbook to CSV
  • Read device date/time
  • Read custom name tables (aircraft, drop zones, alarms)
  • Read/write raw FRAM memory (Warning: write operations are untested and may corrupt device data. Use at your own risk!)
  • Read/write device settings (Warning: writing settings is untested. May cause configuration errors or data loss. Proceed with caution!)
  • Auto port detection, keepalive, and auto-reconnect
  • Pure Python — only depends on pyserial
  • Automatic logbook date parsing for firmware < 1.0.10 (handles overflow bug).

Usage

Getting Started

git clone https://github.com/5BytesHook/pyaltitool.git
cd pyaltitool
pip install pyserial

Connect your Alti-2 device via USB and run:

python altitool_cli.py

The tool auto-detects the serial port. To specify a port manually:

python altitool_cli.py -p /dev/cu.usbserial-XXXX   # macOS
python altitool_cli.py -p /dev/ttyUSB0              # Linux
python altitool_cli.py -p COM3                      # Windows

Common Commands

Once connected, you'll enter the interactive prompt. Type any command for its usage:

altitool> logbook all                    # Show all jumps
altitool> logbook last 10                # Show last 10 jumps
altitool> logbook csv all                # Export all jumps to CSV
altitool> logbook csv last 20 jumps.csv  # Export last 20 to a file
altitool> datetime                       # Read device clock
altitool> names aircraft                 # Read aircraft names
altitool> names dz                       # Read drop zone names
altitool> info                           # Show device info
altitool> help                           # Full command list

Quick CSV export without entering interactive mode:

python altitool_cli.py --csv          # Export all jumps then exit
python altitool_cli.py --csv 50       # Export last 50 jumps then exit

Development

Install for Development

git clone https://github.com/5BytesHook/pyaltitool.git
cd pyaltitool
pip install -e .

Using as a Library

from pyaltitool import AltitoolDevice, auto_detect_port
from pyaltitool import parse_logbook_record, LOGBOOK_RECORD_SIZE

port = auto_detect_port()  # works on macOS, Linux, Windows
with AltitoolDevice(port) as dev:
    info = dev.connect()
    print(f"{info['product_name']} S/N {info['serial_number']}, {info['total_jumps']} jumps")

    dt = dev.read_datetime()
    print(f"Device time: {dt:%Y-%m-%d %H:%M:%S}")

    addr = info["summary_start"] + (info["total_jumps"] - 5) * LOGBOOK_RECORD_SIZE
    data = dev.read_memory(addr, 5 * LOGBOOK_RECORD_SIZE)

    for i in range(5):
        rec = parse_logbook_record(data[i * 22 : (i + 1) * 22])
        print(f"  Jump #{rec['jump_number']}: {rec['exit_alt_ft']}ft exit, {rec['freefall_time']}s freefall")

You can also set the PYALTITOOL_PORT environment variable to override auto-detection, or pass the port path directly:

# macOS:   AltitoolDevice("/dev/cu.usbserial-XXXX")
# Linux:   AltitoolDevice("/dev/ttyUSB0")
# Windows: AltitoolDevice("COM3")

API Reference

AltitoolDevice

The main class for communicating with an Alti-2 device.

from pyaltitool import AltitoolDevice, auto_detect_port
Function / Method Description
auto_detect_port() -> str | None Detect the serial port for an Alti-2 device (macOS / Linux / Windows).
Method Description
connect() -> dict Open port, wake device, perform handshake. Returns parsed Type 0 record.
disconnect() End communication and close port.
reconnect() -> dict Re-establish communication with full DTR wake.
force_reconnect() Thread-safe reconnection (acquires lock internally).
read_memory(address, length) -> bytes Read FRAM memory. Auto-reconnects on failure.
write_memory(address, data) Write to FRAM. Splits large writes automatically. Untested.
read_datetime() -> datetime Read device clock (A2 command).
read_aircraft_names() -> dict[int, str] Read aircraft name table from FRAM.
read_dz_names() -> dict[int, str] Read drop zone name table from FRAM.
read_alarm_names() -> dict[int, str] Read alarm name table from FRAM.
write_aircraft_name(index, name) Write an aircraft name. Untested.
write_dz_name(index, name) Write a drop zone name. Untested.
write_alarm_name(index, name) Write an alarm name. Untested.
read_settings() -> dict Read device settings from FRAM. Untested.
write_settings(settings, base=None) Write settings (read-modify-write). Untested.

Properties: connected, type_zero, session_key.

Protocol helpers

from pyaltitool import (
    parse_logbook_record,     # Parse 22-byte jump record → dict
    format_logbook_record,    # Format parsed record as human-readable string
    logbook_record_to_csv_row,# Format parsed record as CSV row
    CSV_HEADER,               # CSV header string
    LOGBOOK_RECORD_SIZE,      # 22
    parse_type_zero,          # Parse 32-byte Type 0 record → dict
    parse_datetime_response,  # Parse A2 response → datetime
    parse_settings,           # Parse 13-byte settings → dict
    encode_settings,          # Encode settings dict → 13 bytes
    parse_fram_name,          # Parse 10-byte FRAM name → str
    encode_fram_name,         # Encode str → 10-byte FRAM name
    PRODUCT_NAMES,            # {product_id: name} mapping
)

Exceptions

Exception Description
AltitoolError Base exception for all communication errors.
AltitoolAckError(AltitoolError) Device returned an unexpected acknowledgement code.

How It Works

The Alti-2 devices communicate over USB serial (57600 baud, 8N1, RTS/CTS hardware flow control) using a custom encrypted protocol:

  1. DTR wake — toggle DTR to wake the device from sleep
  2. ASCII handshake — send "018080" to receive the 32-byte Type 0 identification record
  3. Session key — derive a 16-byte XTEA key from the Type 0 record + product-specific seed
  4. Encrypted commands — all subsequent commands are 32-byte XTEA-encrypted packets, sent byte-by-byte with CTS flow control polling
  5. Exit — send \x01EXIT to end the session

The device has a ~10-15 second idle timeout. pyaltitool runs a background keepalive thread that sends periodic datetime pings to prevent disconnection.

For bulk logbook reads, the library automatically reconnects between batches of 100 records, as the device's serial state becomes unreliable during sustained transfers.

See ALTI2_ATLAS_COMMUNICATION_PROTOCOL.md for the full protocol specification.

License

MIT

Disclaimer

This is an independent open-source project. It is not affiliated with, endorsed by, or supported by Alti-2 Technologies. Use at your own risk. The authors are not responsible for any damage to your altimeter. Always verify your equipment through official channels before skydiving.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyaltitool-0.1.0.tar.gz (25.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyaltitool-0.1.0-py3-none-any.whl (24.7 kB view details)

Uploaded Python 3

File details

Details for the file pyaltitool-0.1.0.tar.gz.

File metadata

  • Download URL: pyaltitool-0.1.0.tar.gz
  • Upload date:
  • Size: 25.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyaltitool-0.1.0.tar.gz
Algorithm Hash digest
SHA256 91ce686b783d4307b81928bcb56c63019410eb1a14227fa0adeec8ac87c44919
MD5 73f44d41279678969636483fd1ec9647
BLAKE2b-256 ebece32f77b691b3cb94d97e0f09bd36011f1d6a30523fbfd7ab937a76bbfa30

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaltitool-0.1.0.tar.gz:

Publisher: publish.yml on 5BytesHook/pyaltitool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaltitool-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyaltitool-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyaltitool-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 70e7bc15b4910b8eeb2e5ee5da3479b7e9d535e9799fd3b260df1502a645fec7
MD5 67b021858bc81f41c617596074e6382b
BLAKE2b-256 8f83b44c7a17560d9c39f7115d92744d7af600b38f63a4dd4953453d91f72af8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaltitool-0.1.0-py3-none-any.whl:

Publisher: publish.yml on 5BytesHook/pyaltitool

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page