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
- Background Tasks: Periodic read, write, and scan operations with event callbacks
- 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
-Hto specify the exact characteristic handle. You can find the handle value fromairctl ble characteristicsoutput.
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) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Task Manager │ │
│ │ (periodic read/write/scan operations) │ │
│ └─────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ 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.logon Windows,/tmp/airctl-daemon.logon Linux/macOS). Use--log-level DEBUGfor 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]
# Background Tasks (Periodic Operations)
airctl ble task start-read <address> -u UUID -i 5 # Periodic read (every 5s)
airctl ble task start-read <address> -H HANDLE -i 2 # Using handle instead of UUID
airctl ble task start-write <address> -u UUID -d "hex:01" -i 10 # Periodic write (every 10s)
airctl ble task start-scan -i 30 --timeout 5 # Periodic scan (every 30s)
airctl ble task list # List all background tasks
airctl ble task stop <task_id> # Stop a background task
airctl ble events -t periodic_read # Stream periodic read events
airctl ble events -t periodic_write # Stream periodic write events
airctl ble events -t periodic_scan # Stream periodic scan events
Background Task Types
| Task Type | Command | Use Case |
|---|---|---|
| Periodic Read | task start-read |
Keep connection alive, monitor sensor data |
| Periodic Write | task start-write |
Send heartbeat, periodic control commands |
| Periodic Scan | task start-scan |
Continuously monitor nearby devices |
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file airctl-0.1.4.tar.gz.
File metadata
- Download URL: airctl-0.1.4.tar.gz
- Upload date:
- Size: 36.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38c7992cf6d3c62e85fec1d89ec0afe9e9aca86c2c130a3068b817fb76aaffcf
|
|
| MD5 |
a395e7c3a10eea60e5ef1066a0080a36
|
|
| BLAKE2b-256 |
8de73b30454a2b5cd33709a44d340846926b5afa3d54a718ace4fe5ce54ad906
|
File details
Details for the file airctl-0.1.4-py3-none-any.whl.
File metadata
- Download URL: airctl-0.1.4-py3-none-any.whl
- Upload date:
- Size: 47.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c6555c2ea08fea80a7e5be2181af9138af04b4e532b26327c4e27b9999855e9
|
|
| MD5 |
14634054e6b3b9e09e9a4da7fc860d57
|
|
| BLAKE2b-256 |
25c17cc8b1d01beff45dc53def910afe97e726947e0c6d84a17ad046a28979a8
|