feat: AC 三合一设备支持 + 新增 Plug/Gateway 驱动 + Cover 结构化重构

**AC 驱动增强**
- 支持 thermostat + air-conditioner + air-fresh 多服务三合一设备,属性跨服务合并解析
- 新增 specResolver.findValListInService/findInService/hasService/serviceShortName 方法
- 移除 KindThermostat,heater/electric-blanket/thermostat 重新归类为 KindAirConditioner

**Cover 窗帘重构**
- CoverProps 结构化:Position/Status/Fault 分离
- SetPosition 优先写 target-position,回退 current-position
- OnPropsChanged/FetchProps 支持多属性同步刷新

**新增设备类型**
- Plug 驱动:插座/插头,支持开合、在线状态、属性变更订阅
- Gateway 驱动:网关设备类型识别
- miot/miot_errors.go:新增 MIoT 云端错误码定义

**MIoT 客户端健壮性**
- SetProp 空结果视为失败;设备被移除或离线时自动刷新设备列表
- GetDevices 的 has_more 改用 parseBool 严格解析
- MIPS SubscribeMany 批量订阅减少往返
- matchURN 改为按段精确匹配,避免 tofan 误匹配 fan

**Bridge**
- 移除 Thermostat case,Cover 改用结构化 CoverProps
- 新增设备创建后自动订阅属性变更

**其他**
- 日志整体 Info → Debug 降噪
- .gitignore 忽略 /.codebuddy/memory
- 更新 devices_test 与 08_adv_filter_classify 示例
This commit is contained in:
2026-08-23 19:42:55 +08:00
parent 04333750ab
commit 86c21ce91c
25 changed files with 1129 additions and 155 deletions
+142
View File
@@ -0,0 +1,142 @@
package miot
// MIoT 云端错误码
// 来源: https://iot.mi.com/v2/new/doc/help-support/faq/spec/error-code
const (
ErrCodeOK = -702000000 // OK
ErrCodeAccept = -702010000 // accept
ErrCodeProcessing = -702022036 // 操作正在处理中
ErrCodeBadRequest = -704000000 // 错误的请求
ErrCodeBadBody = -704000001 // 错误的请求体
ErrCodeScheduleOnlyMi = -704001000 // 定时只支持小米设备
ErrCodeDeviceError = -704002000 // 设备错误(通用)
ErrCodeUnauthenticated = -704010000 // 未认证
ErrCodeTokenExpired = -704012901 // token 不存在或过期
ErrCodeTokenInvalid = -704012902 // token 非法
ErrCodeAuthExpired = -704012903 // 授权过期
ErrCodeNotAuthToXiaoAi = -704012904 // 设备未授权控制能力给小爱
ErrCodeDeviceUnbound = -704012905 // 设备未绑定
ErrCodeAuthFailed = -704012906 // 认证失败
ErrCodeIRNotSupported = -704013101 // 红外设备不支持此操作
ErrCodePropertyNotRead = -704030013 // 属性不可读
ErrCodePropertyNotWrite = -704030023 // 属性不可写
ErrCodePropertyNotNotify = -704030033 // 属性不可上报
ErrCodeTooFrequent = -704030992 // 请求过于频繁
ErrCodeServiceNotFound = -704040002 // 服务不存在
ErrCodePropertyNotFound = -704040003 // 属性不存在
ErrCodeEventNotFound = -704040004 // 事件不存在
ErrCodeMethodNotFound = -704040005 // 方法不存在
ErrCodeFeatureOffline = -704040999 // 功能未上线
ErrCodeCloudNotFound = -704041007 // cloud not found
ErrCodeDeviceNotFound2 = -704042001 // 未找到设备
ErrCodeSceneNotFound = -704042009 // 未找到场景
ErrCodeSceneError = -704042010 // 触发场景异常
ErrCodeDeviceOffline = -704042011 // 设备离线
ErrCodeSceneNoPermission = -704042012 // 场景无权限
ErrCodeSpecNotFound = -704044006 // 未找到功能定义
ErrCodeCannotExecute = -704053100 // 无法执行此操作
ErrCodeCameraSleeping = -704053101 // 摄像机休眠中
ErrCodeTimeout = -704083036 // 操作超时
ErrCodeDeviceNotFound = -704090001 // 未找到设备
ErrCodeInvalidID = -704220008 // 非法的 ID
ErrCodeInvalidUID = -704220009 // 非法的 uid
ErrCodeInvalidSubID = -704220010 // 非法的订阅 ID
ErrCodeActionParamCount = -704220025 // 方法输入参数数量不匹配
ErrCodeActionParamError = -704220035 // 方法输入参数错误
ErrCodeInvalidPropValue = -704220043 // 属性值不正确
ErrCodeEventParamCount = -704222034 // 事件参数数量不匹配
ErrCodeActionOutParamError = -704222035 // 方法输出参数错误
ErrCodeOpenPlatformError = -705001000 // 开放平台服务器内部错误
ErrCodeSpecServerError = -705004000 // MIoT Spec 服务器内部错误
ErrCodeSubIDEncodeError = -705005000 // 订阅 ID 编码错误
ErrCodeNotifyError = -705006000 // notify error
ErrCodeReadPropFailed = -705201013 // 读属性失败
ErrCodeActionFailed = -705201015 // 方法执行失败
ErrCodeWritePropFailed = -705201023 // 写属性失败
ErrCodeReportPropFailed = -705201033 // 上报属性失败
ErrCodeInvalidSpec = -705204006 // 非法的功能定义
ErrCodeInstanceNotLoaded = -705204007 // 实例未加载
ErrCodeRemoteServiceError = -706010002 // 远程服务异常
ErrCodeMIoTError = -706010004 // MIoT 错误
ErrCodePropCacheFailed = -706010005 // 属性缓存失败
ErrCodeThirdPartyError = -706012000 // 三方云服务器内部错误
ErrCodeThirdReadPropFailed = -706012013 // 三方云读属性失败
ErrCodeThirdActionFailed = -706012015 // 三方云方法执行失败
ErrCodeThirdWritePropFailed = -706012023 // 三方云写属性失败
ErrCodeThirdReportPropFailed = -706012033 // 三方云上报属性失败
ErrCodeThirdSubFailed = -706012043 // 三方云订阅失败
)
// errDescriptions 错误码说明
var errDescriptions = map[int]string{
ErrCodeOK: "OK",
ErrCodeAccept: "accept",
ErrCodeProcessing: "操作正在处理中",
ErrCodeBadRequest: "错误的请求",
ErrCodeBadBody: "错误的请求体",
ErrCodeScheduleOnlyMi: "定时只支持小米设备",
ErrCodeDeviceError: "设备错误(通用)",
ErrCodeUnauthenticated: "未认证",
ErrCodeTokenExpired: "token 不存在或过期",
ErrCodeTokenInvalid: "token 非法",
ErrCodeAuthExpired: "授权过期",
ErrCodeNotAuthToXiaoAi: "设备未授权控制能力给小爱",
ErrCodeDeviceUnbound: "设备未绑定",
ErrCodeAuthFailed: "认证失败",
ErrCodeIRNotSupported: "红外设备不支持此操作",
ErrCodePropertyNotRead: "属性不可读",
ErrCodePropertyNotWrite: "属性不可写",
ErrCodePropertyNotNotify: "属性不可上报",
ErrCodeTooFrequent: "请求过于频繁",
ErrCodeServiceNotFound: "服务不存在",
ErrCodePropertyNotFound: "属性不存在",
ErrCodeEventNotFound: "事件不存在",
ErrCodeMethodNotFound: "方法不存在",
ErrCodeFeatureOffline: "功能未上线",
ErrCodeCloudNotFound: "cloud not found",
ErrCodeDeviceNotFound2: "未找到设备",
ErrCodeSceneNotFound: "未找到场景",
ErrCodeSceneError: "触发场景异常",
ErrCodeDeviceOffline: "设备离线",
ErrCodeSceneNoPermission: "场景无权限",
ErrCodeSpecNotFound: "未找到功能定义",
ErrCodeCannotExecute: "无法执行此操作",
ErrCodeCameraSleeping: "摄像机休眠中",
ErrCodeTimeout: "操作超时",
ErrCodeDeviceNotFound: "未找到设备",
ErrCodeInvalidID: "非法的 ID",
ErrCodeInvalidUID: "非法的 uid",
ErrCodeInvalidSubID: "非法的订阅 ID",
ErrCodeActionParamCount: "方法输入参数数量不匹配",
ErrCodeActionParamError: "方法输入参数错误",
ErrCodeInvalidPropValue: "属性值不正确",
ErrCodeEventParamCount: "事件参数数量不匹配",
ErrCodeActionOutParamError: "方法输出参数错误",
ErrCodeOpenPlatformError: "开放平台服务器内部错误",
ErrCodeSpecServerError: "MIoT Spec 服务器内部错误",
ErrCodeSubIDEncodeError: "订阅 ID 编码错误",
ErrCodeNotifyError: "notify error",
ErrCodeReadPropFailed: "读属性失败",
ErrCodeActionFailed: "方法执行失败",
ErrCodeWritePropFailed: "写属性失败",
ErrCodeReportPropFailed: "上报属性失败",
ErrCodeInvalidSpec: "非法的功能定义",
ErrCodeInstanceNotLoaded: "实例未加载",
ErrCodeRemoteServiceError: "远程服务异常",
ErrCodeMIoTError: "MIoT 错误",
ErrCodePropCacheFailed: "属性缓存失败",
ErrCodeThirdPartyError: "三方云服务器内部错误",
ErrCodeThirdReadPropFailed: "三方云读属性失败",
ErrCodeThirdActionFailed: "三方云方法执行失败",
ErrCodeThirdWritePropFailed: "三方云写属性失败",
ErrCodeThirdReportPropFailed: "三方云上报属性失败",
ErrCodeThirdSubFailed: "三方云订阅失败",
}
// ErrDesc 返回错误码的中文说明。
func ErrDesc(code int) string {
if s, ok := errDescriptions[code]; ok {
return s
}
return "未知错误"
}