Files
xiaomihome/miot/miot_client_api.go
T
4566704 86c21ce91c 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 示例
2026-08-23 19:42:55 +08:00

141 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package miot provides MIoT core client for Xiaomi Home devices.
// It's a Golang port of MIoTClient from xiaomihome-py/miot/.
package miot
import (
"fmt"
)
// ============================================================================
// Cloud API calls (aligned with Python miot_client.py)
// ============================================================================
// SetProp sets a device property via cloud API.
// Aligns with Python: set_prop_async.
// did: device ID
// siid: service IID
// piid: property IID
// value: property value
// Returns: error if failed.
func (c *MIoTClient) SetProp(did string, siid, piid int, value interface{}) error {
if c.http == nil {
return fmt.Errorf("HTTP client not available")
}
params := []PropParam{
{DID: did, Siid: siid, Piid: piid, Value: value},
}
results, err := c.http.SetProp(params)
if err != nil {
return err
}
// Aligns with Python: 空 result 视为失败(Python 会 raise device_exec_error)
if len(results) == 0 {
return fmt.Errorf("set property failed: empty result (device may be offline)")
}
// code=0 或 code=1 均视为成功(0=读取成功,1=设置成功)
if results[0].Code != 0 && results[0].Code != 1 {
// 设备移除或离线:刷新设备列表(Aligns with Python)
if results[0].Code == -704010000 || results[0].Code == -704042011 {
c.lgr.Errorf("[MIoTClient] device may be removed or offline, %s\n", did)
if devs, rerr := c.http.GetDevices(nil); rerr == nil {
c.deviceListMu.Lock()
for k := range c.deviceListCloud {
if _, ok := devs[k]; !ok {
delete(c.deviceListCloud, k)
}
}
c.deviceListMu.Unlock()
}
}
return fmt.Errorf("set property failed, code=%d", results[0].Code)
}
c.lgr.Infof("[MIoTClient] SetProp: %s/%d/%d = %v\n", did, siid, piid, value)
return nil
}
// GetProp gets a device property via cloud API.
// Aligns with Python: get_prop_async.
// did: device ID
// siid: service IID
// piid: property IID
// Returns: property value and error.
func (c *MIoTClient) GetProp(did string, siid, piid int) (interface{}, error) {
if c.http == nil {
return nil, fmt.Errorf("HTTP client not available")
}
params := []PropParam{
{DID: did, Siid: siid, Piid: piid},
}
results, err := c.http.GetProps(params)
if err != nil {
return nil, err
}
if len(results) == 0 {
return nil, fmt.Errorf("no result for property %d.%d", siid, piid)
}
if results[0].Code != 0 {
return nil, fmt.Errorf("get property failed, code=%d", results[0].Code)
}
c.lgr.Infof("[MIoTClient] GetProp: %s/%d/%d = %v\n", did, siid, piid, results[0].Value)
return results[0].Value, nil
}
// Action executes a device action via cloud API.
// Aligns with Python: action_async.
// did: device ID
// siid: service IID
// aiid: action IID
// inList: input parameters
// Returns: action result and error.
func (c *MIoTClient) Action(did string, siid, aiid int, inList []interface{}) (map[string]interface{}, error) {
if c.http == nil {
return nil, fmt.Errorf("HTTP client not available")
}
result, err := c.http.DoAction(did, siid, aiid, inList)
if err != nil {
return nil, err
}
c.lgr.Infof("[MIoTClient] Action: %s/%d/%d, result=%v\n", did, siid, aiid, result)
return result, nil
}
// ============================================================================
// Batch operations (aligned with Python miot_client.py)
// ============================================================================
// SetProps sets multiple device properties in batch.
// Aligns with Python: set_props_async.
// params: slice of PropParam
// Returns: slice of PropResult and error.
func (c *MIoTClient) SetProps(params []PropParam) ([]PropResult, error) {
if c.http == nil {
return nil, fmt.Errorf("HTTP client not available")
}
return c.http.SetProp(params)
}
// GetProps gets multiple device properties in batch.
// Aligns with Python: get_props_async.
// params: slice of PropParam
// Returns: slice of PropResult and error.
func (c *MIoTClient) GetProps(params []PropParam) ([]PropResult, error) {
if c.http == nil {
return nil, fmt.Errorf("HTTP client not available")
}
return c.http.GetProps(params)
}