Skip to main content

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

Project description

AirCtl

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

AirCtl is designed to enable AI agents to control various devices through a command-line interface. The first implementation focuses on Bluetooth Low Energy (BLE) device control, built on top of the Bleak library.

Features

  • AI-First Design: JSON output by default for easy parsing by AI agents
  • Daemon Architecture: Background daemon maintains connections for fast operations
  • Multi-Device Support: Connect and manage multiple BLE devices simultaneously
  • Event Streaming: Subscribe to real-time notifications via event streams
  • Cross-Platform: Works on Windows, Linux, and macOS
  • Configuration Persistence: Save device aliases and GATT presets

Installation

pip install airctl

All dependencies (bleak, typer, rich, pydantic, etc.) will be installed automatically.

Or install from source:

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

Quick Start

1. Scan for Devices

airctl ble scan -t 10

Output (JSON):

{
  "devices": [
    {
      "address": "AA:BB:CC:DD:EE:FF",
      "name": "My Sensor",
      "rssi": -45,
      "service_uuids": ["180D"]
    }
  ],
  "count": 1
}

2. Connect to a Device

airctl ble connect AA:BB:CC:DD:EE:FF -a my_sensor

Note: Avoid using hyphens (-) in aliases as they may be misinterpreted as command options. Use underscores (_) instead.

3. Explore Services

airctl ble services my_sensor
airctl ble characteristics my_sensor

4. Read/Write Characteristics

# Read a characteristic by UUID
airctl ble read my_sensor -u 2A19 -f hex

# Read a characteristic by handle (useful when multiple chars have same UUID)
airctl ble read my_sensor -H 74 -f hex

# Write to a characteristic
airctl ble write my_sensor -u 2A19 -d "hex:010203"

Note: Some devices may have multiple characteristics with the same UUID (e.g., Alert Level in both Immediate Alert and Link Loss services). Use -H to specify the exact characteristic handle. You can find the handle value from airctl ble characteristics output.

5. Subscribe to Notifications

# Subscribe
airctl ble notify subscribe my_sensor -u 2A37

# Stream events
airctl ble events -t notification

Architecture

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

Commands Reference

Daemon Management

airctl daemon status          # Check daemon status (JSON output)
airctl daemon start           # Start daemon manually
airctl daemon start --log-level DEBUG  # Start with debug logging
airctl daemon stop            # Stop daemon
airctl daemon restart         # Restart daemon

Note: Daemon logs are written to the system temp directory (%TEMP%\airctl-daemon.log on Windows, /tmp/airctl-daemon.log on Linux/macOS). Use --log-level DEBUG for verbose logging during troubleshooting.

Diagnostics

airctl doctor check           # Run diagnostic checks (JSON output)

BLE Operations

# Scanning
airctl ble scan [-t 10] [--service-uuids UUID1,UUID2]
airctl ble scan -n "Heart Rate"   # Filter by exact device name

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

# 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 [-f hex|base64|text]
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
airctl ble events [-a ADDR] [-t TYPE]

Configuration

# View configuration
airctl config list
airctl config get daemon.auto_start

# Device aliases
airctl config alias list
airctl config alias set <address> <name>
airctl config alias remove <name>

# GATT presets
airctl config preset list
airctl config preset get uart
airctl config preset set <name> --service UUID --char UUID
airctl config preset remove <name>

Data Input Formats

The -d / --data parameter supports multiple formats:

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

Built-in Presets

Preset Service Description
uart Nordic UART UART service for serial communication
heart_rate 180D Heart Rate service
battery 180F Battery service
device_info 180A Device Information service

Configuration File

Configuration is stored in ~/.airctl/config.yaml:

version: 1

aliases:
  "my_sensor": "AA:BB:CC:DD:EE:FF"

presets:
  custom:
    service: "custom-service-uuid"
    char: "custom-char-uuid"

daemon:
  auto_start: true
  log_level: "INFO"

Development

Setup

# Clone the repository
git clone https://github.com/skinapi2025/AirCtl.git
cd AirCtl

# Create virtual environment
python -m venv venv
source venv/bin/activate  # Linux/macOS
# or
.\venv\Scripts\activate  # Windows

# Install development dependencies
pip install -e ".[dev]"

Running Tests

pytest

Code Formatting

black airctl tests
isort airctl tests

Type Checking

mypy airctl

Requirements

  • Python 3.10+
  • Bluetooth adapter with BLE support
  • Platform-specific requirements:
    • Windows: Windows 10 version 16299 or later
    • Linux: BlueZ 5.55 or later
    • macOS: macOS 10.15 or later

Dependencies

All dependencies are automatically installed with pip install airctl:

Package Purpose
bleak Cross-platform BLE library
typer CLI framework
rich Rich text/pretty print
pydantic Data validation
orjson Fast JSON serialization
pyyaml YAML configuration
pywin32 Windows named pipes (Windows only)

Known Issues

Alias Naming

Avoid using hyphens (-) in device aliases. For example, use my_sensor instead of my-sensor. This is because command-line parsers may interpret the hyphen as an option prefix.

Windows Daemon Stop

On Windows, the daemon uses named pipes for IPC. The daemon stop command works by connecting to the daemon to unblock the pipe and signal shutdown. This is handled automatically.

BLE Authentication Errors

Some BLE characteristics require authentication (pairing) to read or write. If you encounter Insufficient Authentication errors, the device needs to be paired with your system first. This is a BLE security feature, not a bug.

Multiple Characteristics with Same UUID

Some devices have multiple characteristics with the same UUID in different services (e.g., Alert Level appears in both Immediate Alert and Link Loss services). When reading by UUID, airctl automatically selects the first readable characteristic. Use -H for precise control.

License

MIT License

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a pull request.

Acknowledgments

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

airctl-0.1.2.tar.gz (31.7 kB view details)

Uploaded Source

Built Distribution

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

airctl-0.1.2-py3-none-any.whl (41.3 kB view details)

Uploaded Python 3

File details

Details for the file airctl-0.1.2.tar.gz.

File metadata

  • Download URL: airctl-0.1.2.tar.gz
  • Upload date:
  • Size: 31.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for airctl-0.1.2.tar.gz
Algorithm Hash digest
SHA256 32607f47c3f99f0af686846db0ea9c4558465ac22ffe11f8d62a9b7a969df3e9
MD5 e8e6c6965fc3ba978a2b88bbb399a8a6
BLAKE2b-256 e072f1940814cd39d92c1874f6b1fffcb52216344c040f44abbb1fd1976bf5f0

See more details on using hashes here.

File details

Details for the file airctl-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: airctl-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 41.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for airctl-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d28c2462fb953f7aa035f512e6c47332205d9c0a8c0008f4e275b87180d3cc1d
MD5 bebea58f14043c5120dc8f7622b9bbc2
BLAKE2b-256 c1324b912bf2eee2367a3d80c8ce1f9dcaf7a615f218da9c19c6fe76a5111a11

See more details on using hashes here.

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