Skip to content

skinapi2025/AirCtl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AirCtl

AI-friendly CLI tool for Bluetooth device control.

AirCtl enables AI agents to control devices through a command-line interface, supporting both BLE (Bluetooth Low Energy) and BT Classic (BR/EDR) protocols.

Features

  • AI-First Design: JSON output by default, -h for human-readable
  • Auto-Connect: Device commands automatically connect if needed
  • Daemon Architecture: Background daemon maintains BLE connections for fast operations
  • LLM-Friendly Snapshots: --last N returns immediately instead of streaming
  • AI Hint Errors: All errors include actionable recovery hints for autonomous recovery
  • Standard BLE Profiles: Built-in Heart Rate, Battery, Device Information
  • Device Discovery: One-stop capabilities and info commands
  • UUID Name Mapping: Human-readable names for standard BLE UUIDs
  • BT Classic (BR/EDR): RFCOMM connection for Serial Port Profile devices
  • Cross-Platform BLE: Windows, Linux, macOS | BT Classic: Windows, Linux

Quick Start

pip install airctl

# BLE: Scan and discover device
airctl ble scan -t 10

# Device info (one command, auto-connect)
airctl device quick-scan <address>
# Returns: name, manufacturer, battery, services, capabilities

# Read battery
airctl device battery <address>

# Monitor heart rate (auto-connect + subscribe + parse)
airctl device heart-rate <address>

# BT Classic: Serial port devices
airctl bt scan -t 10
airctl bt connect <address> --channel 1

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        CLI Layer                                 │
│           (airctl ble/bt/device/daemon/config commands)         │
└───────────────────────────┬─────────────────────────────────────┘
                            │ JSON-RPC over IPC (BLE only)
                            ▼
┌─────────────────────────────────────────────────────────────────┐
│                     BLE Daemon (Background)                      │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │  Connection │  │   Event     │  │    Device Manager       │  │
│  │   Manager   │  │   Stream    │  │  (multi-device support) │  │
│  └─────────────┘  └─────────────┘  └─────────────────────────┘  │
│  ┌─────────────────────────────────────────────────────────────┐ │
│  │                    Task Manager                              │ │
│  │       (periodic read/write/scan operations)                  │ │
│  └─────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│                     Bleak Library (BLE)                         │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│              BT Classic (Direct System Calls)                    │
│  - Windows: WSA + BluetoothFind APIs                             │
│  - Linux: BlueZ via D-Bus / hctltool                            │
└─────────────────────────────────────────────────────────────────┘
Category Commands Description
BLE Protocol ble Scan, connect, GATT read/write/notify
Device Discovery ble info, ble capabilities Structured device info and capabilities
BT Classic Protocol bt Scan, SDP discovery, RFCOMM connect
Device Profiles device Heart rate, battery, device info, quick-scan

Commands Reference

Daemon Management

airctl daemon status          # Check daemon status
airctl daemon start          # Start daemon manually
airctl daemon start --log-level DEBUG
airctl daemon stop
airctl daemon restart

BLE Discovery (High-Level)

# One-stop device discovery: auto-connect + identity + battery + capabilities
airctl device quick-scan <address>

# Structured device info: identity, battery, subscriptions, MTU
airctl ble info <address>

# Full capabilities: all services/characteristics with names and operation flags
airctl ble capabilities <address>

BLE Operations

# Scanning
airctl ble scan [-t 10] [--service-uuids UUID1,UUID2]
airctl ble scan -n "Heart Rate"

# Connection
airctl ble connect <address> [-t 30] [-a alias]
airctl ble disconnect <address>
airctl ble list

# GATT Operations
airctl ble services <address>
airctl ble characteristics <address> [-s UUID]
airctl ble read <address> -u UUID [-f hex|base64|text]
airctl ble read <address> -H HANDLE
airctl ble write <address> -u UUID -d "hex:..."
airctl ble write <address> -H HANDLE -d "hex:..."

# Notifications
airctl ble notify subscribe <address> -u UUID
airctl ble notify unsubscribe <address> -u UUID

# Event Snapshots (LLM-friendly, returns immediately)
airctl ble events --last 5
airctl ble events --last 10 --address <addr>
airctl ble events --last 5 --type notification

# Background Tasks
airctl ble task start-read <address> -u UUID -i 5
airctl ble task start-write <address> -u UUID -d "hex:01" -i 10
airctl ble task start-scan -i 30 --timeout 5
airctl ble task list
airctl ble task stop <task_id>
airctl ble task result <task_id> --last 5

Device Profiles (High-Level, Auto-Connect)

All device commands automatically connect if not connected and disconnect when done.

# Battery: auto-connect + read + status
airctl device battery <address>
# {"battery_level": 85, "status": "normal"}

# Device info: identity (manufacturer, model, firmware)
airctl device device-info <address>
# {"identity": {"manufacturer_name": "Huawei", "model_number": "WATCH GT 4"}}

# Heart rate: auto-connect + subscribe + parse
airctl device heart-rate <address> [-d 30]
# {"latest_heart_rate": 72, "measurement_count": 5, "measurements": [...]}

# Full monitor: subscribe all notifications + periodic reads
airctl device monitor <address> [-d 30] [-i 5]
# {"subscribed_count": 3, "read_count": 12, "notifications": [...]}

# Identify device coordinator
airctl device identify <address>

# List coordinators and features
airctl device list-coordinators
airctl device features
airctl device kinds

BT Classic Operations

BT Classic uses direct system calls (not the daemon).

airctl bt scan [-t 10]                       # Scan for devices
airctl bt scan --timeout 10 -h              # Human-readable output
airctl bt services <address>                   # List RFCOMM services
airctl bt connect <address> --channel 1       # Connect via RFCOMM
airctl bt connect <address> --service-uuid <UUID>  # Auto-detect channel
airctl bt list                               # List connected devices
airctl bt disconnect <address>

When to Use BT Classic vs BLE

Use Case Protocol Example
Device discovery BLE airctl device quick-scan <addr>
Standard profiles (heart rate, battery) BLE airctl device heart-rate <addr>
Raw GATT read/write/notify BLE airctl ble read/notify <addr>
RFCOMM serial communication BT Classic airctl bt connect <addr>
Device with SPP (Serial Port Profile) BT Classic HC-05/06 modules, GPS devices

LLM-Friendly Patterns

Use snapshot queries (--last N) instead of streaming for AI agents:

# Snapshot: returns immediately
airctl ble events --last 5
# {"events": [...], "count": 5}

# Task results snapshot
airctl ble task start-read <addr> -u 2A19 -i 5
# {"task_id": "abc123", "type": "periodic_read"}

airctl ble task result abc123 --last 5
# {"task_id": "abc123", "results": [...], "count": 5}

Workflow for AI Agents:

  1. airctl device quick-scan <addr> — One command to discover everything
  2. airctl device heart-rate <addr> — One command for heart rate monitoring
  3. If error: check hint field and follow the recovery steps

AI Hint Errors

All errors include an actionable hint field for autonomous recovery:

{
  "error": true,
  "message": "Device 24:81:C7:1B:3B:46 not connected",
  "hint": "Run 'airctl ble connect 24:81:C7:1B:3B:46' first, then retry this command."
}
Error Hint
Device not connected Run 'airctl ble connect <addr>' first
Device not found Run 'airctl ble scan -t 10' to discover
Characteristic not found Run 'airctl ble characteristics <addr>'
Insufficient authentication Pair the device with your system first
Operation timed out Restart daemon: airctl daemon stop && airctl daemon start
Lost connection to daemon Run 'airctl daemon start'

Configuration

airctl config list
airctl config alias set <address> <name>
airctl config alias list
airctl config alias remove <name>
airctl config preset list
airctl config preset set <name> --service UUID --char UUID
airctl config preset remove <name>

Data Formats

Input Formats

The -d / --data parameter supports:

Format Example Description
hex: hex:010203 Hexadecimal bytes
text: text:hello UTF-8 text
base64: base64:AQID Base64 encoded
(default) 010203 Hexadecimal

UUID Name Mapping

Standard BLE UUIDs are automatically mapped to human-readable names:

{
  "services": [
    {
      "uuid": "0000180f-0000-1000-8000-00805f9b34fb",
      "name": "Battery",
      "characteristics": [
        {"uuid": "00002a19-...", "name": "Battery Level", "readable": true}
      ]
    }
  ]
}

Output Format

The -f / --format parameter controls output format:

Format Example Description
hex 010203 Hexadecimal string
base64 AQID Base64 encoded
text Hello UTF-8 text

Common GATT UUIDs

UUID Name Description
1800 Generic Access Device name and appearance
180A Device Information Manufacturer, model, firmware
180D Heart Rate Heart Rate service
180F Battery Battery service
2A00 Device Name BLE device name (read/write)
2A19 Battery Level Battery percentage (read)
2A24 Model Number Device model (read)
2A26 Firmware Revision Firmware version (read)
2A29 Manufacturer Name Device manufacturer (read)
2A37 Heart Rate Measurement Heart rate data (notify)
2A38 Body Sensor Location Sensor position (read)

Known Issues

  • Alias Naming: Use underscores (my_sensor) not hyphens (my-sensor) in aliases
  • BLE Authentication: Some characteristics require pairing — pair the device with your system first
  • BLE Connection Stability: Some devices (e.g., smartwatches) disconnect after ~12s idle. Device commands handle this automatically with auto-reconnect
  • Short UUID Support: Both short (2A19) and full (00002a19-...) UUID formats are supported
  • Heart Rate Notifications: Only sent when the device is actively measuring (e.g., during exercise)

Requirements

  • Python 3.10+
  • Bluetooth adapter
  • Windows: Windows 10 v16299+ | Linux: BlueZ 5.55+ | macOS: macOS 10.15+

Installation

pip install airctl

Or from source:

git clone https://github.com/skinapi2025/AirCtl.git
cd AirCtl
pip install -e ".[dev]"

Testing

pytest tests/ -v

License

MIT License

About

AI-friendly CLI tool for device control via Bluetooth and more

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages