Skip to main content

Universal IoT device control CLI — for humans and AI agents

Project description

image 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.

PyPI version Python versions CI Coverage License Privacy

InstallQuick StartAI IntegrationProtocolsArchitecture


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 schema
  • iotcli.skill.yaml — legacy global skill spec
  • system_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 with slugify() for normalized names.
  • Credentials: Fernet-encrypted vault, never in devices.yaml. Key stored at 0600.
  • 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 0600 permissions (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


Download files

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

Source Distribution

iotcli-0.10.1.tar.gz (69.0 kB view details)

Uploaded Source

Built Distribution

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

iotcli-0.10.1-py3-none-any.whl (85.3 kB view details)

Uploaded Python 3

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

Hashes for iotcli-0.10.1.tar.gz
Algorithm Hash digest
SHA256 74f7121cc5213906f1ef02ece96158a766fe8f4a4f284ab56926848a71e4bc72
MD5 f27d1fe68a8abb87766f08294e05bab2
BLAKE2b-256 14975f42f5b04a41aca90efdb668a6744de41764a1c7857469de6f72d5c8ab8a

See more details on using hashes here.

Provenance

The following attestation bundles were made for iotcli-0.10.1.tar.gz:

Publisher: publish.yml on fomyio/iotcli

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

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

Hashes for iotcli-0.10.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1edf8f6f8f032f30b662bcb73711dce5e3777f18d570296ebeceb91d02767643
MD5 df575061b0ed9f3e4b3e6289f482838c
BLAKE2b-256 f67f4eb2cedb38e8a34d2981ef9db9e1a7a025e2e3ae12ebea9acf8acafdb604

See more details on using hashes here.

Provenance

The following attestation bundles were made for iotcli-0.10.1-py3-none-any.whl:

Publisher: publish.yml on fomyio/iotcli

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