Universal IoT device control CLI — for humans and AI agents
Project description
Give your AI agent hands.
One CLI to rule them all. Discover, configure, and control IoT devices across protocols.
Built for AI agents, loved by humans.
Install • Quick Start • AI Integration • Protocols • Architecture
What is iotcli?
iotcli is a universal IoT device control CLI. It unifies smart-home devices behind a single, predictable interface — so you (or your AI agent) can control lights, AC units, feeders, and sensors without memorizing protocol quirks.
Key principles:
- One command shape for every device —
on,off,status,set - Protocol-agnostic — Tuya, miIO, MQTT, HTTP, LG ThinQ, and more
- AI-native — JSON mode, skill files, and an MCP server for Claude Desktop / Cursor / Zed
- Privacy-first — everything local, credentials encrypted, no telemetry
Install
# Global install via pipx (recommended — no venv needed)
pipx install git+https://github.com/iotviaai/iotcli.git
# Or with MCP support for Claude Desktop / Cursor
pipx install git+https://github.com/iotviaai/iotcli.git[mcp]
# From source
git clone https://github.com/iotviaai/iotcli.git
cd iotcli
pip install -e ".[dev]"
Requires Python 3.10+
Quick Start
# Interactive setup wizard (Rich TUI)
iotcli setup
# Discover devices on your network
iotcli discover --network 192.168.1.0/24
# Add a device
iotcli add --name living-room-light --protocol miio \
--ip 192.168.1.100 --token <32chars>
# Control
iotcli control on living-room-light
iotcli control status living-room-light
iotcli control set living-room-light brightness=80
# AI agent mode (structured JSON)
iotcli --json list
iotcli --json control status living-room-light
iotcli --json status-all
Demo
$ iotcli list
╭─────────── Devices ───────────╮
│ Name Protocol IP │
│ living-room-light miio 192.168.1.100 │
│ feeder tuya 192.168.1.4 │
│ lg-ac lgac (cloud) │
╰───────────────────────────────╯
$ iotcli control status lg-ac
╭─── lg-ac — online ───╮
│ power: POWER_OFF │
│ mode: HEAT │
│ fan_speed: HIGH │
│ current_temp: 20.5 │
│ target_temp: 25 │
╰──────────────────────╯
$ iotcli --json control on feeder
{"success": true, "device": "feeder", "action": "on"}
Supported Protocols
| Protocol | Devices | Connection |
|---|---|---|
miio |
Xiaomi / Yeelight | Local (UDP) |
tuya |
Tuya-based (lights, plugs, etc.) | Local (TCP) |
mqtt |
Zigbee / Aqara via MQTT broker | Local (TCP) |
http |
ESPHome / Tasmota | Local (HTTP) |
lgac |
LG Air Conditioner (ThinQ) | Cloud (HTTPS) |
Tuya Profiles
| Profile | Devices | Special Actions |
|---|---|---|
generic |
Any Tuya device | power on/off |
light |
Smart bulbs | brightness, color_temperature, color |
switch |
Smart plugs | power, countdown |
petfeeder |
ROJECO / Tuya feeders | portions, quick_feed, slow_feed, light |
iotcli add --name feeder --protocol tuya --profile petfeeder \
--ip 192.168.1.4 --device-id <id> --local-key <key> --version 3.4
AI Agent Integration
iotcli was built from the ground up for AI agents. Every command supports --json for structured, parseable output.
Skill Files
Generate per-device skill files so your agent knows exactly what each device can do:
iotcli skills generate
Files created in ~/.iotcli/skills/:
<device>/SKILL.md— per-device capability doc (OpenClaw-compatible)iotcli.tools.json— OpenAI/Anthropic tool schemaiotcli.skill.yaml— legacy global skill specsystem_prompt.md— ready-to-use agent system prompt
MCP Server (Claude Desktop / Cursor / Zed)
Connect iotcli directly to your AI assistant via the Model Context Protocol:
# Install with MCP support
pip install iotcli[mcp]
# Start the server
iotcli serve mcp
Add to claude_desktop_config.json:
{
"mcpServers": {
"iotcli": {
"command": "iotcli",
"args": ["serve", "mcp"]
}
}
}
Once connected, Claude can list devices, check status, turn them on/off, and set properties — all through structured tool calls with per-device enums and value validation. No copy-pasting commands.
Agent Workflow
# 1. Discover what's available
iotcli --json list
# 2. Check state before acting
iotcli --json control status "living-room-light"
# 3. Act
iotcli --json control on "living-room-light"
iotcli --json control set "living-room-light" "brightness=80"
Architecture
src/iotcli/
├── core/ # Device model, protocol registry, controller
├── protocols/ # Self-registering protocol handlers
├── config/ # YAML config + Fernet credential vault
├── discovery/ # Async multi-protocol network scanner
├── tui/ # Rich + InquirerPy interactive wizard
├── cli/ # Click commands (discover, control, device, config, skills)
├── skills/ # Jinja2-based AI agent skill generator
└── mcp/ # MCP server for Claude Desktop / Cursor / Zed
Design decisions:
- Protocol registry (
core/registry.py): Decorator-based self-registration. No hardcoded mappings. - Device model (
core/device.py): Dataclass withslugify()for normalized names. - Credentials: Fernet-encrypted vault, never in
devices.yaml. Key stored at0600. - Extensible: Add a protocol by implementing
BaseProtocol— the CLI, wizard, and skill generator pick it up automatically.
Security
- Credentials are never stored in config files
- Secrets encrypted with Fernet at
~/.iotcli/credentials/ - Encryption key has
0600permissions (owner-only) - No telemetry, no analytics, no cloud dependency
- Fully open source — inspect exactly what runs on your machine
See PRIVACY.md for details.
Extending — Add a New Protocol
# src/iotcli/protocols/myproto.py
@register_protocol("myproto")
class MyProtocol(BaseProtocol):
meta = ProtocolMeta(
name="myproto",
display_name="My Protocol",
default_port=9999,
required_credentials=["api_key"],
...
)
def connect(self) -> bool: ...
def disconnect(self) -> None: ...
def turn_on(self) -> bool: ...
def turn_off(self) -> bool: ...
def get_status(self) -> dict: ...
def set_value(self, prop, value) -> bool: ...
Add one import in protocols/__init__.py — the CLI, wizard, and skill generator pick it up automatically.
License
MIT
Made with passion for AI agents and smart homes.
Project details
Release history Release notifications | RSS feed
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 iotcli-0.10.1.tar.gz.
File metadata
- Download URL: iotcli-0.10.1.tar.gz
- Upload date:
- Size: 69.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74f7121cc5213906f1ef02ece96158a766fe8f4a4f284ab56926848a71e4bc72
|
|
| MD5 |
f27d1fe68a8abb87766f08294e05bab2
|
|
| BLAKE2b-256 |
14975f42f5b04a41aca90efdb668a6744de41764a1c7857469de6f72d5c8ab8a
|
Provenance
The following attestation bundles were made for iotcli-0.10.1.tar.gz:
Publisher:
publish.yml on fomyio/iotcli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iotcli-0.10.1.tar.gz -
Subject digest:
74f7121cc5213906f1ef02ece96158a766fe8f4a4f284ab56926848a71e4bc72 - Sigstore transparency entry: 1360057400
- Sigstore integration time:
-
Permalink:
fomyio/iotcli@002912e12c62a474b6cc9025936c82b0978e408f -
Branch / Tag:
refs/tags/v0.10.1 - Owner: https://github.com/fomyio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@002912e12c62a474b6cc9025936c82b0978e408f -
Trigger Event:
push
-
Statement type:
File details
Details for the file iotcli-0.10.1-py3-none-any.whl.
File metadata
- Download URL: iotcli-0.10.1-py3-none-any.whl
- Upload date:
- Size: 85.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1edf8f6f8f032f30b662bcb73711dce5e3777f18d570296ebeceb91d02767643
|
|
| MD5 |
df575061b0ed9f3e4b3e6289f482838c
|
|
| BLAKE2b-256 |
f67f4eb2cedb38e8a34d2981ef9db9e1a7a025e2e3ae12ebea9acf8acafdb604
|
Provenance
The following attestation bundles were made for iotcli-0.10.1-py3-none-any.whl:
Publisher:
publish.yml on fomyio/iotcli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iotcli-0.10.1-py3-none-any.whl -
Subject digest:
1edf8f6f8f032f30b662bcb73711dce5e3777f18d570296ebeceb91d02767643 - Sigstore transparency entry: 1360057439
- Sigstore integration time:
-
Permalink:
fomyio/iotcli@002912e12c62a474b6cc9025936c82b0978e408f -
Branch / Tag:
refs/tags/v0.10.1 - Owner: https://github.com/fomyio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@002912e12c62a474b6cc9025936c82b0978e408f -
Trigger Event:
push
-
Statement type: