feyagate-skill 1.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ """FeyaGate Skill - MCP Smart Home Gateway for AI Agents."""
2
+
3
+ __version__ = "1.2.2"
4
+ __author__ = "panzuji"
5
+
6
+ DEFAULT_INSTALL_DIR = "~/.feyagate"
7
+ FOTA_URL = "https://oneapi.sooncore.com/ota/fota.json"
8
+ MCP_DEFAULT_PORT = 38080
9
+ MCP_DEFAULT_HOST = "127.0.0.1"
feyagate_skill/auth.py ADDED
@@ -0,0 +1,133 @@
1
+ """Xiaomi account authorization tool."""
2
+
3
+ import json
4
+ import sys
5
+ import time
6
+ from pathlib import Path
7
+ from urllib.parse import urlparse, parse_qs
8
+
9
+ from . import MCP_DEFAULT_HOST, MCP_DEFAULT_PORT
10
+ from .mcp import mcp_call
11
+
12
+ COLORS = {
13
+ 'reset': '\033[0m', 'red': '\033[91m', 'green': '\033[92m',
14
+ 'yellow': '\033[93m', 'blue': '\033[94m', 'cyan': '\033[96m',
15
+ 'bold': '\033[1m',
16
+ }
17
+
18
+
19
+ def _c(name, text):
20
+ return f"{COLORS.get(name, '')}{text}{COLORS['reset']}"
21
+
22
+
23
+ def _tool_map(tool):
24
+ mapping = {
25
+ "auth/status": "xiaomi/auth_status",
26
+ "auth/url": "xiaomi/auth_url",
27
+ "auth/callback": "xiaomi/auth_callback",
28
+ }
29
+ return mapping.get(tool, tool)
30
+
31
+
32
+ def _mcp(host, port, tool, arguments=None):
33
+ return mcp_call(host, port, _tool_map(tool), arguments)
34
+
35
+
36
+ def check_status(host, port):
37
+ status = _mcp(host, port, "auth/status")
38
+ authorized = status.get("authorized", False)
39
+ remaining = status.get("remaining_seconds", 0)
40
+
41
+ if authorized:
42
+ hours = remaining // 3600
43
+ mins = (remaining % 3600) // 60
44
+ days = hours // 24
45
+ hours = hours % 24
46
+ time_str = f"{days}d " if days > 0 else ""
47
+ time_str += f"{hours}h {mins}m" if hours > 0 or mins > 0 else "expiring soon"
48
+ print(_c('green', f" Authorized, remaining: {time_str}"))
49
+ return True
50
+ else:
51
+ print(_c('red', " Not authorized"))
52
+ return False
53
+
54
+
55
+ def get_auth_url(host, port):
56
+ result = _mcp(host, port, "auth/url")
57
+ return result.get("url", "")
58
+
59
+
60
+ def submit_code(host, port, code):
61
+ code_input = code.strip()
62
+ if code_input.startswith("http://") or code_input.startswith("https://"):
63
+ parsed = urlparse(code_input)
64
+ params = parse_qs(parsed.query)
65
+ code_list = params.get("code", [])
66
+ if not code_list:
67
+ print(_c('red', " No 'code' parameter found in URL"))
68
+ return False
69
+ code_input = code_list[0]
70
+
71
+ print(_c('yellow', f" Submitting auth code: {code_input[:10]}..."))
72
+ result = _mcp(host, port, "auth/callback", {"code": code_input})
73
+
74
+ if "error" in result:
75
+ print(_c('red', f" Auth failed: {result['error']}"))
76
+ return False
77
+
78
+ time.sleep(1)
79
+ if check_status(host, port):
80
+ return True
81
+ else:
82
+ print(_c('yellow', " Code submitted but status not updated."))
83
+ return False
84
+
85
+
86
+ def do_auth(host=None, port=None, code=None, status_only=False):
87
+ """Run the auth flow."""
88
+ host = host or MCP_DEFAULT_HOST
89
+ port = port or MCP_DEFAULT_PORT
90
+
91
+ if status_only:
92
+ print("=== Auth Status ===")
93
+ check_status(host, port)
94
+ return
95
+
96
+ if code:
97
+ print("=== Submit Auth Code ===")
98
+ if submit_code(host, port, code):
99
+ print(_c('green', "\nAuthorization successful!"))
100
+ return
101
+
102
+ # Interactive flow
103
+ print("=" * 50)
104
+ print(_c('blue', " Xiaomi Account Authorization"))
105
+ print("=" * 50)
106
+ print()
107
+
108
+ print("Step 1: Check current status")
109
+ if check_status(host, port):
110
+ print(_c('yellow', "\nAlready authorized. Re-auth after token expires."))
111
+ return
112
+
113
+ print()
114
+ print("Step 2: Get authorization URL")
115
+ auth_url = get_auth_url(host, port)
116
+ if not auth_url:
117
+ print(_c('red', " Cannot get auth URL. Is MCP server running?"))
118
+ return
119
+
120
+ print(_c('green', " Auth URL generated"))
121
+ print(f"\n {_c('cyan', auth_url)}")
122
+ print(_c('yellow', "\n Open URL in browser, then copy the full redirect URL"))
123
+ print(_c('yellow', " (The 'page not found' error is normal)"))
124
+ print()
125
+
126
+ print("Step 3: Submit auth code")
127
+ callback_url = input("Paste the full callback URL: ").strip()
128
+ if not callback_url:
129
+ print(_c('red', " No input"))
130
+ return
131
+
132
+ if submit_code(host, port, callback_url):
133
+ print(_c('green', "\nAuthorization complete!"))
feyagate_skill/cli.py ADDED
@@ -0,0 +1,212 @@
1
+ """FeyaGate Skill CLI - Main entry point."""
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ from . import __version__, DEFAULT_INSTALL_DIR, MCP_DEFAULT_PORT
10
+
11
+
12
+ def _install_claude():
13
+ """Configure Claude Code MCP settings."""
14
+ claude_config = Path.home() / ".claude.json"
15
+ install_dir = Path(os.path.expanduser(DEFAULT_INSTALL_DIR))
16
+ binary = install_dir / "bin" / "miloco-mcp-server"
17
+
18
+ if not binary.exists():
19
+ print("ERROR: MCP server not installed. Run: feyagate setup")
20
+ return False
21
+
22
+ config = {}
23
+ if claude_config.exists():
24
+ try:
25
+ config = json.loads(claude_config.read_text(encoding="utf-8"))
26
+ except Exception:
27
+ config = {}
28
+
29
+ mcp_servers = config.setdefault("mcpServers", {})
30
+ mcp_servers["feyagate"] = {
31
+ "type": "streamable-http",
32
+ "url": "http://localhost:38080/mcp/http",
33
+ }
34
+
35
+ claude_config.write_text(json.dumps(config, indent=2, ensure_ascii=False), encoding="utf-8")
36
+ print(f"Added 'feyagate' MCP server to {claude_config}")
37
+ print(f" URL: http://localhost:38080/mcp/http")
38
+ print()
39
+ print("Make sure to start the server: feyagate start")
40
+ return True
41
+
42
+
43
+ def _install_cursor():
44
+ """Configure Cursor MCP settings."""
45
+ cursor_config = Path.home() / ".cursor" / "mcp.json"
46
+ install_dir = Path(os.path.expanduser(DEFAULT_INSTALL_DIR))
47
+ binary = install_dir / "bin" / "miloco-mcp-server"
48
+
49
+ if not binary.exists():
50
+ print("ERROR: MCP server not installed. Run: feyagate setup")
51
+ return False
52
+
53
+ cursor_config.parent.mkdir(parents=True, exist_ok=True)
54
+
55
+ config = {}
56
+ if cursor_config.exists():
57
+ try:
58
+ config = json.loads(cursor_config.read_text(encoding="utf-8"))
59
+ except Exception:
60
+ config = {}
61
+
62
+ mcp_servers = config.setdefault("mcpServers", {})
63
+ mcp_servers["feyagate"] = {
64
+ "type": "streamable-http",
65
+ "url": "http://localhost:38080/mcp/http",
66
+ }
67
+
68
+ cursor_config.write_text(json.dumps(config, indent=2, ensure_ascii=False), encoding="utf-8")
69
+ print(f"Added 'feyagate' MCP server to {cursor_config}")
70
+ print(f" URL: http://localhost:38080/mcp/http")
71
+ print()
72
+ print("Make sure to start the server: feyagate start")
73
+ return True
74
+
75
+
76
+ def main():
77
+ parser = argparse.ArgumentParser(
78
+ prog="feyagate",
79
+ description="FeyaGate Skill - MCP Smart Home Gateway for AI Agents",
80
+ )
81
+ parser.add_argument("--version", action="version", version=f"feyagate-skill {__version__}")
82
+
83
+ sub = parser.add_subparsers(dest="command", help="Available commands")
84
+
85
+ # setup
86
+ p_setup = sub.add_parser("setup", help="Download and install MCP server binary")
87
+ p_setup.add_argument("--dir", default=None, help="Install directory (default: ~/.feyagate)")
88
+
89
+ # start
90
+ p_start = sub.add_parser("start", help="Start MCP server")
91
+ p_start.add_argument("--port", type=int, default=None, help="HTTP port (default: from config)")
92
+
93
+ # stop
94
+ sub.add_parser("stop", help="Stop MCP server")
95
+
96
+ # restart
97
+ p_restart = sub.add_parser("restart", help="Restart MCP server")
98
+ p_restart.add_argument("--port", type=int, default=None, help="HTTP port")
99
+
100
+ # status
101
+ sub.add_parser("status", help="Show server status")
102
+
103
+ # log
104
+ p_log = sub.add_parser("log", help="Show server log")
105
+ p_log.add_argument("-n", "--lines", type=int, default=30, help="Number of lines")
106
+
107
+ # auth
108
+ p_auth = sub.add_parser("auth", help="Xiaomi account authorization")
109
+ p_auth.add_argument("--host", default=None, help="MCP host")
110
+ p_auth.add_argument("--port", type=int, default=None, help="MCP port")
111
+ p_auth.add_argument("--status", action="store_true", help="Check auth status only")
112
+ p_auth.add_argument("--code", default=None, help="Submit auth code directly")
113
+
114
+ # snapshot
115
+ p_snap = sub.add_parser("snapshot", help="Camera snapshot capture")
116
+ p_snap.add_argument("--host", default=None)
117
+ p_snap.add_argument("--port", type=int, default=None)
118
+ p_snap.add_argument("--list", action="store_true", help="List cameras")
119
+ p_snap.add_argument("--camera-id", default=None, help="Camera DID")
120
+ p_snap.add_argument("--connect", action="store_true", help="Connect before snapshot")
121
+ p_snap.add_argument("--channel", type=int, default=0)
122
+ p_snap.add_argument("--count", type=int, default=1)
123
+ p_snap.add_argument("--output-dir", default=None)
124
+
125
+ # scheduled
126
+ p_sched = sub.add_parser("scheduled", help="Scheduled camera analysis")
127
+ p_sched.add_argument("--host", default=None)
128
+ p_sched.add_argument("--port", type=int, default=None)
129
+ p_sched.add_argument("--camera-id", action="append", required=True, help="Camera DID (repeatable)")
130
+ p_sched.add_argument("--channel", type=int, default=0)
131
+ p_sched.add_argument("--interval", type=int, default=300, help="Seconds between captures")
132
+ p_sched.add_argument("--output-dir", default=None)
133
+ p_sched.add_argument("--prompt", default="", help="AI analysis prompt")
134
+ p_sched.add_argument("--auto-connect", action="store_true")
135
+ p_sched.add_argument("--max-runs", type=int, default=0, help="0 = unlimited")
136
+ p_sched.add_argument("--one-shot", action="store_true")
137
+
138
+ # install-claude
139
+ sub.add_parser("install-claude", help="Configure Claude Code MCP settings")
140
+
141
+ # install-cursor
142
+ sub.add_parser("install-cursor", help="Configure Cursor MCP settings")
143
+
144
+ # upgrade
145
+ sub.add_parser("upgrade", help="Upgrade MCP server to latest version")
146
+
147
+ args = parser.parse_args()
148
+
149
+ if not args.command:
150
+ parser.print_help()
151
+ return
152
+
153
+ if args.command == "setup":
154
+ from .installer import do_setup
155
+ do_setup(args.dir)
156
+
157
+ elif args.command == "start":
158
+ from .service import do_start
159
+ do_start(args.port)
160
+
161
+ elif args.command == "stop":
162
+ from .service import do_stop
163
+ do_stop()
164
+
165
+ elif args.command == "restart":
166
+ from .service import do_stop, do_start
167
+ do_stop()
168
+ do_start(args.port)
169
+
170
+ elif args.command == "status":
171
+ from .service import do_status
172
+ do_status()
173
+
174
+ elif args.command == "log":
175
+ from .service import do_log
176
+ do_log(args.lines)
177
+
178
+ elif args.command == "auth":
179
+ from .auth import do_auth
180
+ do_auth(host=args.host, port=args.port, code=args.code, status_only=args.status)
181
+
182
+ elif args.command == "snapshot":
183
+ from .snapshot import do_snapshot
184
+ do_snapshot(
185
+ host=args.host, port=args.port, camera_id=args.camera_id,
186
+ connect=args.connect, channel=args.channel, count=args.count,
187
+ output_dir=args.output_dir, list_cameras=args.list,
188
+ )
189
+
190
+ elif args.command == "scheduled":
191
+ from .scheduled import do_scheduled
192
+ do_scheduled(
193
+ host=args.host, port=args.port, camera_ids=args.camera_id,
194
+ channel=args.channel, interval=args.interval,
195
+ output_dir=args.output_dir, prompt=args.prompt,
196
+ auto_connect=args.auto_connect, max_runs=args.max_runs,
197
+ one_shot=args.one_shot,
198
+ )
199
+
200
+ elif args.command == "install-claude":
201
+ _install_claude()
202
+
203
+ elif args.command == "install-cursor":
204
+ _install_cursor()
205
+
206
+ elif args.command == "upgrade":
207
+ from .installer import do_setup
208
+ do_setup()
209
+
210
+
211
+ if __name__ == "__main__":
212
+ main()
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: feyagate
3
+ description: MCP smart home gateway skill for AI agents (OpenClaw, Claude Code, Hermes, Codex, Windsurf, Copilot, 小智AI). Control multi-platform IoT devices via MCP protocol — supports Xiaomi/Mi Home, Tuya, Midea, eWeLink, Serial, and GPIO platforms. Provides cross-platform device discovery and control, MIOT device properties, XiaoAI speaker TTS/music, camera P2P streaming and snapshots, scheduled tasks, trigger automation, vision AI analysis, memory system, room management, and skill management. Use when working with smart home, IoT device control, home automation, Xiaomi, Tuya, Midea, eWeLink, MIOT protocol, cameras, surveillance, XiaoAI speakers, TTS, automation, scheduling, OpenClaw skill, Hermes skill, MCP server, MCP skill, or AI agent tool.
4
+ ---
5
+
6
+ # FeyaGate Skill — MCP Smart Home Gateway for AI Agents
7
+
8
+ MCP-based multi-platform smart home gateway supporting Xiaomi, Tuya, Midea, eWeLink, Serial, and GPIO. Compatible with OpenClaw, Claude Code, Hermes, Codex, Windsurf, Copilot, 小智AI and other MCP-compatible AI agents.
9
+
10
+ **Dual API endpoints:**
11
+
12
+ | Endpoint | Protocol | URL |
13
+ |----------|----------|-----|
14
+ | MCP (PC proxy) | Streamable HTTP JSON-RPC 2.0 | `http://localhost:38080/mcp/http` |
15
+ | MCP (ESP32 gateway) | WebSocket / Streamable HTTP | `ws://<gateway>:8765/mcp` / `http://<gateway>:8765/mcp/http` |
16
+ | HTTP REST (ESP32 gateway) | REST API | `http://<gateway>:8080/api/v1/...` |
17
+
18
+ > **Note:** The PC proxy (miloco-mcp-server) provides all gateway MCP tools plus additional extensions (camera P2P, Xiaomi auth, etc.).
19
+
20
+ ## Server Lifecycle
21
+
22
+ | Action | macOS/Linux | Windows |
23
+ |--------|-------------|---------|
24
+ | Install | `bash scripts/install.sh` | `scripts\install.ps1` |
25
+ | Setup | `bash scripts/setup.sh` | `scripts\setup.bat` |
26
+ | Start | `bash scripts/start.sh` | `scripts\start.bat` |
27
+ | Stop | `bash scripts/stop.sh` | `scripts\stop.bat` |
28
+ | Verify | `bash scripts/verify.sh` | `scripts\verify.bat` |
29
+ | Status | `bash scripts/health_check.sh` | `scripts\health_check.bat` |
30
+ | Custom port | `bash scripts/start.sh --port 9090` | `scripts\start.bat --port 9090` |
31
+ | Upgrade | `bash scripts/upgrade.sh` | `powershell -File scripts\upgrade.ps1` |
32
+ | Check updates | `bash scripts/upgrade.sh --check` | `powershell -File scripts\upgrade.ps1 -Check` |
33
+
34
+ ### System Dependencies (Linux)
35
+
36
+ ```bash
37
+ sudo apt-get install -y libfmt8 libmosquitto1 libyaml-cpp0.7
38
+ ldd bin/miloco-mcp-server | grep "not found" # verify
39
+ ```
40
+
41
+ ## Cross-Platform Tools
42
+
43
+ Unified interfaces that work across all platforms. System auto-detects device platform.
44
+
45
+ | Tool | Arguments | Returns |
46
+ |------|-----------|---------|
47
+ | `device/list` | `filter` (string[]), `platform` (opt) | `devices[]` with `platform` field |
48
+ | `device/specs` | `deviceId` (string) | Platform-specific spec: properties, actions |
49
+ | `platform/status` | — | All platform connection/auth/sync status |
50
+ | `gateway/info` | — | Version, device count, ports |
51
+ | `scene/list` | `platform` (string) | `scenes[]` |
52
+ | `scene/trigger` | `platform` (string), `sceneId` (string) | Trigger result |
53
+
54
+ > **Parameter convention:** `device/specs` uses `deviceId` (camelCase); platform-specific tools (`xiaomi/*`, `tuya/*`, etc.) use `device_id` (snake_case).
55
+
56
+ ## Platform Skill Modules
57
+
58
+ Detailed tool references are split into sub-skill files by platform. Load as needed:
59
+
60
+ | Module | File | Covers |
61
+ |--------|------|--------|
62
+ | **Xiaomi** | [skills/xiaomi.md](skills/xiaomi.md) | MIOT device control, OAuth auth, camera P2P, XiaoAI speaker |
63
+ | **Tuya** | [skills/tuya.md](skills/tuya.md) | DP property read/write, QR code auth |
64
+ | **Midea** | [skills/midea.md](skills/midea.md) | AC/appliance control, account auth |
65
+ | **eWeLink** | [skills/ewelink.md](skills/ewelink.md) | Sonoff/eWeLink switches, multi-channel |
66
+ | **Automation** | [skills/automation.md](skills/automation.md) | Schedule, trigger engine, room, memory, skill system |
67
+ | **Extension** | [skills/extension.md](skills/extension.md) | Serial, GPIO, Xiaozhi AI, license, config, stats |
68
+
69
+ ## License System
70
+
71
+ - **Free edition**: Xiaomi platform only (device control, cameras, XiaoAI, MCP proxy)
72
+ - **Licensed edition**: All platforms (Xiaomi + Tuya + Midea + eWeLink)
73
+ - `tuya/set_property`, `midea/set_property`, `ewelink/set_property` return `license_required` on free edition
74
+ - `get_properties` and all other tools work without license
75
+
76
+ ## Configuration
77
+
78
+ `config/config.yaml`:
79
+
80
+ ```yaml
81
+ server:
82
+ http_port: 38080
83
+ ws_port: 8765
84
+ bind_address: "0.0.0.0"
85
+ auth:
86
+ cloud_server: "cn" # cn / de / sg / us / ru / i2
87
+ token_file: "data/auth_token.json"
88
+ camera:
89
+ frame_interval: 500
90
+ buffer_max_size: 20
91
+ buffer_ttl: 300
92
+ jpeg_quality: 90
93
+ tuya:
94
+ token_file: "data/tuya_token.json"
95
+ midea:
96
+ token_file: "data/midea_token.json"
97
+ ewelink:
98
+ token_file: "data/ewelink_token.json"
99
+ xiaozhi:
100
+ endpoint: "" # ws:// or wss:// (empty = disabled)
101
+ ```
102
+
103
+ ## Troubleshooting
104
+
105
+ | Symptom | Fix |
106
+ |---------|-----|
107
+ | `connection refused` | Start server: `bash scripts/start.sh` |
108
+ | `authorized: false` | Authorize via `xiaomi/auth_url` → `xiaomi/auth_callback` |
109
+ | `cannot open shared object file` | `sudo apt-get install -y libfmt8 libmosquitto1 libyaml-cpp0.7` |
110
+ | `Tool not found` | Check tool name (see `tools/list` output) |
111
+ | `key 'device_id' not found` | Platform tools use `device_id`; cross-platform `device/specs` uses `deviceId` |
112
+ | `license_required` error | Set license key via `license/set` tool |
113
+ | Library load error | `ldd bin/miloco-mcp-server \| grep "not found"` |
114
+
115
+ Full API reference: [FeyaGate_MCP_API.md](FeyaGate_MCP_API.md), [FeyaGate_HTTP_API.md](FeyaGate_HTTP_API.md)
@@ -0,0 +1,51 @@
1
+ support_classes:
2
+ - camera
3
+ extra_info:
4
+ chuangmi.camera.068ac1:
5
+ channel_count: 2
6
+ name: 小白智能户外摄像机Q2 双摄照明版
7
+ vendor: 上海创米科技
8
+ chuangmi.camera.111ac1:
9
+ channel_count: 2
10
+ name: 小白智能摄像机 A2双摄版
11
+ vendor: 上海创米科技
12
+ chuangmi.camera.72ac1:
13
+ channel_count: 2
14
+ name: 小米智能摄像机C300双摄版
15
+ vendor: 上海创米科技
16
+ isa.camera.cw501d:
17
+ channel_count: 2
18
+ name: 小米室外摄像机 4 双摄版
19
+ vendor: 天津华来科技有限公司
20
+ isa.camera.hlmax:
21
+ channel_count: 2
22
+ name: 小米室外摄像机CW500双摄版
23
+ vendor: 天津华来科技有限公司
24
+ mxiang.camera.c500ch:
25
+ channel_count: 2
26
+ name: 小米智能摄像机C500双摄版
27
+ vendor: 上海摩象网络科技有限公司
28
+ xiaomi.camera.082ac1:
29
+ channel_count: 2
30
+ name: 小米智能摄像机 4 双摄版
31
+ vendor: 小米
32
+ xiaomi.camera.083ac1:
33
+ channel_count: 1
34
+ name: 小米智能摄像机 4 变焦版
35
+ vendor: 小米
36
+ blacklist:
37
+ - chuangmi.camera.ipc004b
38
+ - miir.camera.ir01
39
+ - mxiang.camera.mwc11
40
+ - isa.camera.hl5
41
+ - xiaovv.camera.xva3
42
+ - xzh.camera.camera
43
+ - cgzn.camera.camera
44
+ - isa.camera.virtual
45
+ - lumi.camera.aq1
46
+ - fimi.camera.c1b
47
+ - yunyi.camera.v1
48
+ - fimi.camera.c1
49
+ - chuangmi.camera.v4
50
+ - chuangmi.camera.ipc007b
51
+ - chuangmi.camera.ipc010
@@ -0,0 +1,17 @@
1
+ server:
2
+ ws_port: 8765
3
+ http_port: 38080
4
+ bind_address: "0.0.0.0"
5
+ webui_dir: "webui" # path to WebUI static files (empty = disabled)
6
+
7
+ auth:
8
+ cloud_server: "cn" # cn / de / sg / us / ru / i2
9
+ token_file: "data/auth_token.json"
10
+
11
+ camera:
12
+ frame_interval: 500 # ms between JPEG captures
13
+ buffer_max_size: 20 # max frames per camera/channel
14
+ buffer_ttl: 300 # seconds before frames expire
15
+ reconnect_min: 3 # seconds, initial reconnect delay
16
+ reconnect_max: 1200 # seconds, max reconnect delay
17
+ jpeg_quality: 90 # JPEG encode quality (1-100)
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: feyagate-automation
3
+ description: Automation tools for FeyaGate. Schedule tasks (timed device control), trigger engine (camera-based automation), room management, and memory/note system. Use when setting up scheduled actions, automated triggers, room organization, or persistent memory.
4
+ ---
5
+
6
+ # Automation & Utility Tools
7
+
8
+ ## Schedule
9
+
10
+ | Tool | Arguments | Returns |
11
+ |------|-----------|---------|
12
+ | `schedule/add` | `name`, `scheduledTime`, `toolName`, `toolArgs`, `repeat`, `repeatDays` (opt) | Task ID |
13
+ | `schedule/list` | — | `tasks[]` |
14
+ | `schedule/get` | `id` | Task detail |
15
+ | `schedule/update` | `id` + fields to update | Update result |
16
+ | `schedule/delete` | `id` | Delete result |
17
+ | `schedule/cancel` | `id` | Cancel result |
18
+
19
+ **Repeat types:** `none` / `daily` / `weekdays` / `weekends` / `weekly` / `custom_days`
20
+
21
+ **Example:**
22
+ ```json
23
+ {
24
+ "name": "schedule/add",
25
+ "arguments": {
26
+ "name": "睡前关灯",
27
+ "scheduledTime": "2026-05-16T23:00:00+08:00",
28
+ "toolName": "xiaomi/set_property",
29
+ "toolArgs": "{\"device_id\":\"xxx\",\"siid\":2,\"piid\":1,\"value\":false}",
30
+ "repeat": "daily"
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Trigger Engine (PC proxy)
36
+
37
+ | Tool | Arguments | Returns |
38
+ |------|-----------|---------|
39
+ | `trigger/create` | `name`, `cameras`, `condition`, `actions` | Rule ID |
40
+ | `trigger/list` | — | `rules[]` |
41
+ | `trigger/update` | `id`, fields to update | Update result |
42
+ | `trigger/delete` | `id` | Delete result |
43
+ | `trigger/toggle` | `id`, `enabled` | Toggle result |
44
+ | `trigger/logs` | `limit`, `rule_id` (opt) | `logs[]` |
45
+
46
+ ## Room Management
47
+
48
+ | Tool | Arguments | Returns |
49
+ |------|-----------|---------|
50
+ | `room/list` | — | Unique room name list |
51
+ | `room/set_device` | `device_ids` (string[]), `room_name` (string) | Assignment result |
52
+
53
+ ## Memory System
54
+
55
+ | Tool | Arguments | Returns |
56
+ |------|-----------|---------|
57
+ | `memory/read` | — | All long-term memories |
58
+ | `memory/add` | `content`, `category` (opt) | Added entry |
59
+ | `memory/update` | `id`, `content` | Update result |
60
+ | `memory/delete` | `id` | Delete result |
61
+ | `memory/search` | `keyword` | Matching entries |
62
+ | `memory/note` | `content` | Add today's note |
63
+ | `memory/today` | — | Today's notes |
64
+
65
+ ## Skill System
66
+
67
+ | Tool | Arguments | Returns |
68
+ |------|-----------|---------|
69
+ | `skill/list` | — | Available skills |
70
+ | `skill/read` | `id` | Skill content |
71
+ | `skill/manage` | `action` (add/update/delete) + other fields | Manage result |