IoT platform management toolkit: manage devices, products, alarms, thing models, and device communication. Use this when users need to interact with IoT devices, query device status, set device properties, call device services, manage IoT products, or handle IoT alarms.
If iotapi MCP tools are already available, no setup is needed — just use them.
Otherwise, the user needs to configure their IoT platform connection. Direct them to set up credentials using one of these methods:
If the user already has a token from the web UI:
mkdir -p ~/.config/iotapi && cat > ~/.config/iotapi/credentials.json << 'EOF'
{
"base_url": "https://iot.iwillcloud.com",
"token": "YOUR_TOKEN_HERE"
}
EOF
For long-term use with automatic token refresh:
mkdir -p ~/.config/iotapi && cat > ~/.config/iotapi/credentials.json << 'EOF'
{
"base_url": "https://iot.iwillcloud.com",
"app_key": "YOUR_APP_KEY",
"app_secret": "YOUR_APP_SECRET"
}
EOF
export IOTAPI_BASE_URL="https://iot.iwillcloud.com"
export IOTAPI_TOKEN="your_token_here"
# OR
export IOTAPI_APP_KEY="your_app_key"
export IOTAPI_APP_SECRET="your_app_secret"
When MCP tools are NOT available, call the API directly using curl via Bash.
Read in order, use the first one found:
IOTAPI_BASE_URL, IOTAPI_TOKEN (or IOTAPI_APP_KEY + IOTAPI_APP_SECRET)~/.config/iotapi/credentials.json (macOS/Linux) or %APPDATA%\iotapi\credentials.json (Windows)
{
"base_url": "https://iot.iwillcloud.com",
"token": "...",
"app_key": "...",
"app_secret": "..."
}
If only app_key and app_secret are available, obtain a token first:
curl -X POST "${IOTAPI_BASE_URL}/api/v1/oauth/auth" \
-H "Content-Type: application/json" \
-d '{
"appKey": "'"${IOTAPI_APP_KEY}"'",
"appSecret": "'"${IOTAPI_APP_SECRET}"'"
}'
Response:
{
"code": 200,
"success": true,
"data": "77e7368a-fe49-4bb7-8755-50756ebf26f4",
"errorMessage": ""
}
Extract the token from data field and use it in subsequent requests.
Important: This platform uses a custom token header, NOT the standard Authorization: Bearer format.
curl -X POST "${IOTAPI_BASE_URL}/api/v1/{endpoint}" \
-H "Content-Type: application/json" \
-H "token: ${IOTAPI_TOKEN}" \
-d '{
"param1": "value1",
"param2": "value2"
}'
All requests are POST with JSON body. Responses follow this format:
{
"code": 200,
"success": true,
"data": { ... },
"errorMessage": ""
}
code: 200 = success, other values indicate errorssuccess: boolean indicating if request succeededdata: response payload (structure varies by endpoint)errorMessage: error description (empty on success)Endpoint: POST /api/v1/oauth/auth
Parameters:
{
"appKey": "string",
"appSecret": "string"
}
Response: Token string in data field (valid for 24 hours)
Endpoint: POST /api/v1/alarm/queryAlarmListAll
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| startTime | string | No | Start time (ISO 8601 or timestamp) |
| endTime | string | No | End time (ISO 8601 or timestamp) |
| status | string | No | Alarm status: Trigger, ManualRelieve, AutoRelieve |
Response: Array of alarm objects with fields:
name: Alarm namecategory: Category (e.g., "Point")level: Level (e.g., "Level1")generateValue: Trigger valuerestoreValue: Restore valuerestoreTime: Restore timestampstatus: Current statusdevice: Device objectcreateTime: Creation timestampEndpoint: POST /api/v1/product/create
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productName | string | Yes | Product name |
| productKey | string | No | Product key (auto-generated if not provided) |
| authType | string | No | Auth type: Default, Once, Dynamic (default: Default) |
| productSecret | string | No | Product secret (required for Dynamic auth, auto-generated otherwise) |
Endpoint: POST /api/v1/product/query
Parameters: Provide one of:
productKey: Product keyproductId: Product IDEndpoint: POST /api/v1/product/queryListAll
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productName | string | No | Product name (supports fuzzy search) |
Response: Array of products with fields:
productKey: Product identifierproductName: Product nameauthType: Authentication typeproductSecret: Product secretdeviceNumber: Number of devicespropertyNumber: Number of propertieseventNumber: Number of eventsserviceNumber: Number of servicesEndpoint: POST /api/v1/product/delete
Parameters: Provide one of:
productKey: Product keyproductId: Product IDEndpoint: POST /api/v1/quickdevice/register
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productKey | string | Yes | Product key |
| deviceName | string | No | Device code (auto-generated if not provided) |
| nickName | string | No | Device nickname (defaults to deviceName) |
Endpoint: POST /api/v1/quickdevice/detail
Parameters: Provide one of:
deviceName: Device codedeviceId: Device IDResponse: Device object with fields:
deviceId: Device unique IDdeviceName: Device codenickName: Device nicknameproductKey: Product keyproductName: Product namedeviceSecret: Device secretstatus: Device status (ONLINE, OFFLINE, UNACTIVE)ipAddress: IP addressactiveTime: Activation timestamponlineTime: Last online timestampcreateTime: Creation timestampfirmwareVersion: Firmware version (if reported)Endpoint: POST /api/v1/quickdevice/status
Parameters: Provide one of:
deviceName: Device codedeviceId: Device IDResponse: Status string (ONLINE, OFFLINE, UNACTIVE)
Endpoint: POST /api/v1/quickdevice/batchGetDeviceState
Parameters: Provide one of (max 100 devices):
deviceName: Array of device codesdeviceId: Array of device IDsResponse: Array of device state objects
Endpoint: POST /api/v1/quickdevice/batchQueryDeviceDetail
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productKey | string | Yes | Product key |
| deviceName | array | No | Device codes (returns all if not provided) |
Endpoint: POST /api/v1/quickdevice/queryDevice
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productKey | string | Yes | Product key |
Response: Array of all devices under the product
Endpoint: POST /api/v1/thing/queryThingModel
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productKey | string | Yes | Product key |
Response: Thing model definition with properties, events, and services
Endpoint: POST /api/v1/thing/setDevicesProperty
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| pointList | array | Yes | Array of property objects: [{"identifier": "prop1", "value": "val1"}] |
Endpoint: POST /api/v1/thing/setBatchDevicesProperty
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | array | Yes | Array of device codes |
| pointList | array | Yes | Array of property objects |
Endpoint: POST /api/v1/thing/invokeThingsService
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| servicePoint | object | Yes | Service info: {"identifier": "service_name"} |
| pointList | array | Yes | Service input parameters: [{"identifier": "param1", "value": "val1"}] |
Endpoint: POST /api/v1/thing/invokeBatchThingsService
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | array | Yes | Array of device codes |
| servicePoint | object | Yes | Service info |
| pointList | array | Yes | Service input parameters |
Endpoint: POST /api/v1/thing/queryDevicePropertyData
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| identifier | string | Yes | Property identifier |
| startTime | string | Yes | Start time |
| endTime | string | Yes | End time |
| downSampling | string | No | Down-sampling interval (default: "1s") |
Endpoint: POST /api/v1/thing/queryDevicePropertiesData
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| identifier | string | Yes | Comma-separated property identifiers |
| startTime | string | Yes | Start time |
| endTime | string | Yes | End time |
| downSampling | string | No | Down-sampling interval (default: "1s") |
Endpoint: POST /api/v1/thing/queryDeviceEventData
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| identifier | string | No | Event identifier (all events if not provided) |
| startTime | string | Yes | Start time |
| endTime | string | Yes | End time |
Endpoint: POST /api/v1/thing/queryDeviceServiceData
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| identifier | string | No | Service identifier (all services if not provided) |
| startTime | string | Yes | Start time |
| endTime | string | Yes | End time |
Response: Array of service call records with fields:
send: Sent contentreceive: Response contentreceiveTime: Response timestampresult: ResultresultTime: Result timestampservicePoint: Service point infoFor devices that don't use thing model, the platform supports custom topics for transparent message passing.
Topics:
/{productKey}/{deviceName}/user/get/{productKey}/{deviceName}/user/update/{productKey}/{deviceName}/user/update/errorEndpoint: POST /api/v1/device/down/record/add/custom
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceName | string | Yes | Device code |
| messageContent | string | Yes | Base64-encoded message content |
Example: To send binary Modbus command 01 03 00 00 00 01 84 0A:
# Convert to Base64: AQMAAAABhAo=
curl -X POST "${IOTAPI_BASE_URL}/api/v1/device/down/record/add/custom" \
-H "Content-Type: application/json" \
-H "token: ${IOTAPI_TOKEN}" \
-d '{
"deviceName": "Wk9kOa5NLX",
"messageContent": "AQMAAAABhAo="
}'
RRPC enables synchronous request-response communication with devices over MQTT.
Device subscribes to: /sys/${productKey}/${deviceName}/rrpc/request/+
Device responds to: /sys/${productKey}/${deviceName}/rrpc/response/${requestId}
Endpoint: POST /api/v1/device/rrpc
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| productKey | string | Yes | Product key |
| deviceName | string | Yes | Device code |
| requestBase64Byte | string | Yes | Base64-encoded request message |
| timeout | long | Yes | Timeout in milliseconds |
Response:
{
"code": 200,
"success": true,
"data": {
"rrpcCode": "SUCCESS", // or "TIMEOUT", "OFFLINE"
"payloadBase64Byte": "base64_encoded_response"
}
}
RRPC Codes:
SUCCESS: Device responded successfullyTIMEOUT: No response within timeout periodOFFLINE: Device is offlineNote: Platform automatically handles Base64 encoding/decoding. Device receives raw bytes and should respond with raw bytes.
| Error | Solution |
|-------|----------|
| 401 | Invalid or expired token — obtain new token via /api/v1/oauth/auth |
| 403 | Insufficient permissions — check appKey permissions configuration |
| Connection refused | Verify IOTAPI_BASE_URL is correct and platform is accessible |
| code != 200 | Check errorMessage field in response for details |
1. Device Management Flow:
Query products → Select product → Query devices → Get device details/status
2. Device Control Flow:
Query thing model → Identify properties/services → Set property or invoke service
3. Data Query Flow:
Get device list → Query property/event/service data for time range
Check device online status before control:
# 1. Check status
curl -X POST "${IOTAPI_BASE_URL}/api/v1/quickdevice/status" \
-H "Content-Type: application/json" \
-H "token: ${IOTAPI_TOKEN}" \
-d '{"deviceName": "sensor_001"}'
# 2. If online, set property
curl -X POST "${IOTAPI_BASE_URL}/api/v1/thing/setDevicesProperty" \
-H "Content-Type: application/json" \
-H "token: ${IOTAPI_TOKEN}" \
-d '{
"deviceName": "sensor_001",
"pointList": [{"identifier": "temperature_threshold", "value": "25"}]
}'
Query historical data with time range:
curl -X POST "${IOTAPI_BASE_URL}/api/v1/thing/queryDevicePropertyData" \
-H "Content-Type: application/json" \
-H "token: ${IOTAPI_TOKEN}" \
-d '{
"deviceName": "sensor_001",
"identifier": "temperature",
"startTime": "2025-01-01T00:00:00.000Z",
"endTime": "2025-01-31T23:59:59.999Z",
"downSampling": "1h"
}'
| Limitation | Mitigation |
|-----------|------------|
| Token expires after 24 hours | Store appKey/appSecret for auto-refresh, or regenerate token |
| Batch operations limited to 100 devices | Split large operations into multiple requests |
| Property/event data queries return paginated results | Use appropriate time ranges and down-sampling |
| RRPC timeout is user-defined | Set reasonable timeout based on device response time (typically 5-10 seconds) |
| Custom topic messages must be Base64 encoded | Use base64 command or programming language libraries |
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer