sufn-smart-home
> **技能激活说明**:
> - 用户发送「三峰登录 [账号] [密码]」时,这是三峰智能家居登录指令,必须调用本技能。
> - 用户发送设备控制指令(打开/关闭 + 设备名)时,必须调用本技能。
> - 用户说任何模式或场景名称时,必须调用本技能。
# 智能家居控制技能
## 重要规则
- **禁止**模拟或伪造任何执行结果
- **禁止**在回复末尾添加建议、提示或表情
- 所有操作必须真实调用 API
- 回复格式保持简洁,只包含操作结果
- **每次操作只发一条消息**,禁止发送多条消息
---
## 状态文件
登录状态和设备数据持久化存储在 `{baseDir}/state.json`。
读取用 `read` 工具,path 填 `{baseDir}/state.json`。
**写入必须用 exec 工具执行 PowerShell**,不要用 write 工具。
所有脚本中的 `$statePath` 值为 `{baseDir}/state.json`,Agent 生成脚本时须将 `{baseDir}` 替换为技能文件的实际目录路径。
文件不存在时视为未登录。
---
## API 调用方式
**重要:运行环境是 Windows PowerShell,必须用 Invoke-RestMethod,禁止用 curl 或 curl.exe。**
每次 exec 脚本开头必须加编码设置:
```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
```
---
## API 说明
Base URL:`https://open.aibasis.cc`
认证:所有接口 Header 加 `Authorization: Bearer <token>`
### 1. 登录
```
POST /api/user/login
Body: { "user": "xxx", "psw": "xxx" }
返回: { "code": 0, "data": { "token": "xxx", "home": { "id": "xxx", "name": "xxx" } } }
```
### 2. 获取家庭列表
```
GET /api/getHomeList
Headers: Authorization: Bearer <token> (必须带,否则返回缺少Token错误)
返回: { "code": 0, "data": [{ "ID": "xxx", "NAME": "xxx" }] }
注意:字段名是大写 ID 和 NAME
```
### 3. 进入指定家庭
```
POST /api/inHome
Body: { "homeId": "xxx" }
返回: { "code": 0, "data": { "token": "xxx", "home": { "id": "xxx", "name": "xxx" } } }
注意:进入后 token 会更新,必须保存新 token
```
### 4. 同步家庭数据
```
POST /api/syncHomeData
Body: { "requestId": "sync_001", "timestamp": <毫秒时间戳>, "version": "1.0", "data": {} }
返回 data 包含: devices[](含 id、name、model、roomId)、rooms[](含 id、name)、scenes[](含 id、name)
```
### 5. 控制设备或执行场景
```
POST /api/control
Body: {
"requestId": "cmd_001",
"timestamp": <毫秒时间戳>,
"version": "1.0",
"commands": [{ "id": "<设备id或场景id>", "model": "<设备model,场景为scene>", "properties": { <参数> } }]
}
```
lamp_5 设备 properties:{"open":1} 开、{"open":0} 关、{"brightness":80} 亮度、{"colorTemperature":4000} 色温、{"h":120,"s":100,"l":50} 颜色
执行场景:model="scene",properties={}
---
## 操作流程
### 一、登录
触发词:`三峰登录 账号 密码`
```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$statePath = '{baseDir}/state.json'
$body = @{ user = "账号"; psw = "密码" } | ConvertTo-Json
$res = Invoke-RestMethod -Method POST -Uri "https://open.aibasis.cc/api/user/login" -ContentType "application/json" -Body $body
if ($res.code -eq 0) {
$token = $res.data.token
$syncBody = @{ requestId = "sync_001"; timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds(); version = "1.0"; data = @{} } | ConvertTo-Json
$syncRes = Invoke-RestMethod -Method POST -Uri "https://open.aibasis.cc/api/syncHomeData" -ContentType "application/json" -Headers @{ Authorization = "Bearer $token" } -Body $syncBody
$devices = $syncRes.data.devices | ForEach-Object { @{ id = $_.id; name = $_.name; model = $_.model; roomId = $_.roomId } }
$rooms = $syncRes.data.rooms | ForEach-Object { @{ id = [string]$_.id; name = $_.name } }
$scenes = $syncRes.data.scenes | ForEach-Object { @{ id = $_.id; name = $_.name } }
$state = @{ token = $token; home = @{ id = $res.data.home.id; name = $res.data.home.name }; devices = $devices; rooms = $rooms; scenes = $scenes }
$json = $state | ConvertTo-Json -Depth 5 -Compress
[System.IO.File]::WriteAllText($statePath, $json, [System.Text.Encoding]::UTF8)
Write-Output "OK home:$($res.data.home.name) devices:$($devices.Count) scenes:$($scenes.Count)"
} else {
Write-Output "FAIL $($res.msg)"
}
```
输出 `OK home:xxx devices:N scenes:M` 时回复:`✅ 登录成功,家庭:xxx,已同步设备 N 个、场景 M 个`,回复后立即结束。
输出 `FAIL xxx` 时回复:`❌ 登录失败:xxx`
未提供账号密码时回复:`请用格式登录:三峰登录 账号 密码`
---
### 二、家庭列表
触发词:`家庭列表`、`我的家庭`、`有哪些家庭`
```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$statePath = '{baseDir}/state.json'
$state = Get-Content $statePath -Encoding UTF8 | ConvertFrom-Json
$res = Invoke-RestMethod -Method GET -Uri "https://open.aibasis.cc/api/getHomeList" -Headers @{ Authorization = "Bearer $($state.token)" }
$total = $res.data.Count
$names = ($res.data | Select-Object -First 10 | ForEach-Object { $_.NAME }) -join "、"
Write-Output "OK total:$total names:$names"
```
回复:`🏠 共 N 个家庭,前10个:名称1、名称2...,发送「进入家庭 名称」切换`
---
### 三、进入家庭
触发词:`进入家庭 <名称>`、`切换家庭 <名称>`
先从用户消息提取家庭名称关键词,替换下方脚本中的 `$keyword`:
```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$statePath = '{baseDir}/state.json'
$state = Get-Content $statePath -Encoding UTF8 | ConvertFrom-Json
$keyword = "用户输入的名称"
$listRes = Invoke-RestMethod -Method GET -Uri "https://open.aibasis.cc/api/getHomeList" -Headers @{ Authorization = "Bearer $($state.token)" }
$home = $listRes.data | Where-Object { $_.NAME -like "*$keyword*" -or $keyword -like "*$($_.NAME)*" } | Select-Object -First 1
if ($home) {
$body = @{ homeId = $home.ID } | ConvertTo-Json
$res = Invoke-RestMethod -Method POST -Uri "https://open.aibasis.cc/api/inHome" -ContentType "application/json" -Headers @{ Authorization = "Bearer $($state.token)" } -Body $body
$token = $res.data.token
$syncBody = @{ requestId = "sync_001"; timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds(); version = "1.0"; data = @{} } | ConvertTo-Json
$syncRes = Invoke-RestMethod -Method POST -Uri "https://open.aibasis.cc/api/syncHomeData" -ContentType "application/json" -Headers @{ Authorization = "Bearer $token" } -Body $syncBody
$devices = $syncRes.data.devices | ForEach-Object { @{ id = $_.id; name = $_.name; model = $_.model; roomId = $_.roomId } }
$rooms = $syncRes.data.rooms | ForEach-Object { @{ id = [string]$_.id; name = $_.name } }
$scenes = $syncRes.data.scenes | ForEach-Object { @{ id = $_.id; name = $_.name } }
$newState = @{ token = $token; home = @{ id = $res.data.home.id; name = $res.data.home.name }; devices = $devices; rooms = $rooms; scenes = $scenes }
$json = $newState | ConvertTo-Json -Depth 5 -Compress
[System.IO.File]::WriteAllText($statePath, $json, [System.Text.Encoding]::UTF8)
Write-Output "OK home:$($res.data.home.name) devices:$($devices.Count) scenes:$($scenes.Count)"
} else {
$available = ($listRes.data | Select-Object -First 5 | ForEach-Object { $_.NAME }) -join "、"
Write-Output "FAIL 未找到「$keyword」,可用:$available..."
}
```
输出 `OK home:xxx devices:N scenes:M` 时回复:`✅ 已进入家庭:xxx,已同步设备 N 个、场景 M 个`,回复后立即结束。
输出 `FAIL xxx` 时回复:`❌ 切换失败:xxx`
---
### 四、同步设备
触发词:`同步设备`、`刷新设备`
```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$statePath = '{baseDir}/state.json'
$state = Get-Content $statePath -Encoding UTF8 | ConvertFrom-Json
$token = $state.token
$body = @{ requestId = "sync_001"; timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds(); version = "1.0"; data = @{} } | ConvertTo-Json
$res = Invoke-RestMethod -Method POST -Uri "https://open.aibasis.cc/api/syncHomeData" -ContentType "application/json" -Headers @{ Authorization = "Bearer $token" } -Body $body
$devices = $res.data.devices | ForEach-Object { @{ id = $_.id; name = $_.name; model = $_.model; roomId = $_.roomId } }
$rooms = $res.data.rooms | ForEach-Object { @{ id = [string]$_.id; name = $_.name } }
$scenes = $res.data.scenes | ForEach-Object { @{ id = $_.id; name = $_.name } }
$newState = @{ token = $token; home = $state.home; devices = $devices; rooms = $rooms; scenes = $scenes }
$json = $newState | ConvertTo-Json -Depth 5 -Compress
[System.IO.File]::WriteAllText($statePath, $json, [System.Text.Encoding]::UTF8)
Write-Output "OK devices:$($devices.Count) scenes:$($scenes.Count)"
```
回复:`✅ 同步完成,设备 N 个,场景 M 个`
---
### 五、设备列表
触发词:`设备列表`、`有哪些设备`
读取 state.json,按房间分组,回复:`📋 设备列表(共N个)房间1:设备1、设备2 房间2:设备3`
---
### 六、场景列表
触发词:`场景列表`、`有哪些场景`
读取 state.json,回复:`🎬 场景列表(共N个):场景1、场景2、场景3...`
---
### 七、控制设备
触发词:打开/关闭/开启/关掉/调节/设置 + 设备名
1. 读取 state.json,检查 token 和 devices
2. 无 token 提示登录;无 devices 提示同步设备
3. 从用户指令提取设备名,模糊匹配 devices,获取 model 字段
4. 构造 properties:开 {"open":1}、关 {"open":0}、亮度 {"brightness":XX}、色温 {"colorTemperature":XXXX}、HSL 颜色
5. 调用控制接口,commands 必须带 model
6. 成功回复:`✅ 已执行:设备名 操作描述`
7. 失败回复:`❌ 控制失败:错误信息`
8. 找不到:`❌ 未找到「关键词」,当前设备:设备1、设备2...`
---
### 八、场景模式(智能场景)
触发词:任何模式名称(观影模式、阅读模式、回家、离家、睡眠等)
**处理逻辑:**
1. 读取 state.json,提取用户说的场景关键词
2. 在 scenes 列表中模糊匹配(场景名包含关键词,或关键词包含场景名)
3. **若找到匹配场景**:直接调用控制接口执行,回复:`✅ 已执行场景:场景名`
4. **若未找到场景**:根据关键词语义推断灯光参数,对所有设备批量控制:
常见模式推断规则(若未匹配则根据语义自行判断):
- 观影:brightness:20, colorTemperature:2700
- 阅读:brightness:100, colorTemperature:6500
- 睡眠/休息:brightness:5, colorTemperature:2700
- 起床/早晨:brightness:70, colorTemperature:5500
- 浪漫:brightness:20, colorTemperature:2700
- 专注/工作:brightness:100, colorTemperature:5500
- 聚会/会客:brightness:80, colorTemperature:4000
- 全开:open:1
- 全关/离家:open:0
批量控制时在一次 control 请求里将所有设备放入 commands 数组,不要逐个发请求。
**重要:PowerShell 序列化嵌套对象时必须先把每个 command 转成 JSON 再合并,否则 properties 会变成 System.Collections.Hashtable 字符串。正确做法如下:**
```powershell
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$statePath = '{baseDir}/state.json'
$state = Get-Content $statePath -Encoding UTF8 | ConvertFrom-Json
$token = $state.token
$ts = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
# 构造 commands JSON 字符串(直接用字符串拼接避免序列化问题)
$props = '{"brightness":20,"colorTemperature":2700}' # 根据场景替换此处参数
$cmds = ($state.devices | ForEach-Object { '{"id":"' + $_.id + '","model":"' + $_.model + '","properties":' + $props + '}' }) -join ","
$bodyStr = '{"requestId":"cmd_001","timestamp":' + $ts + ',"version":"1.0","commands":[' + $cmds + ']}'
$res = Invoke-RestMethod -Method POST -Uri "https://open.aibasis.cc/api/control" -ContentType "application/json" -Headers @{ Authorization = "Bearer $token" } -Body $bodyStr
Write-Output "OK code:$($res.code)"
```
回复:`✅ 已模拟「用户说的场景名」:亮度XX%,色温XXXXK`
---
### 九、未登录时收到任何控制指令
回复:`请先登录,发送:三峰登录 账号 密码`
---
### 十、帮助
触发词:`帮助`、`三峰帮助`、`怎么用`、`有什么功能`
直接回复(不调用 API):
`🏠 三峰智能家居指令:三峰登录 账号 密码 | 家庭列表 | 进入家庭 名称 | 同步设备 | 设备列表 | 场景列表 | 打开/关闭 设备名 | 设备名 亮度XX% | 设备名 色温XXXX | 观影模式/阅读模式/回家 等场景名`
标签
skill
ai