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:
+57
-36
@@ -477,7 +477,7 @@ func (c *MIoTHttpClient) getDevRoomPage(maxID string) (map[string]map[string]int
|
||||
}
|
||||
|
||||
// Check for more pages
|
||||
hasMore, _ := result["has_more"].(bool)
|
||||
hasMore := parseBool(result["has_more"])
|
||||
nextMaxID, _ := result["max_id"].(string)
|
||||
if hasMore && nextMaxID != "" {
|
||||
nextList, err := c.getDevRoomPage(nextMaxID)
|
||||
@@ -582,42 +582,43 @@ func (c *MIoTHttpClient) GetHomeInfos() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
// Handle pagination
|
||||
hasMore, _ := result["has_more"].(bool)
|
||||
hasMore := parseBool(result["has_more"])
|
||||
maxID, _ := result["max_id"].(string)
|
||||
if hasMore && maxID != "" {
|
||||
moreList, err := c.getDevRoomPage(maxID)
|
||||
if err == nil {
|
||||
for _, deviceSource := range []string{"homelist", "share_home_list"} {
|
||||
for hidStr, info := range moreList {
|
||||
if _, exists := homeInfos[deviceSource][hidStr]; !exists {
|
||||
continue
|
||||
}
|
||||
h, _ := homeInfos[deviceSource][hidStr].(map[string]interface{})
|
||||
if h == nil {
|
||||
continue
|
||||
}
|
||||
h["dids"] = append(toStringSlice(h["dids"]), toStringSlice(info["dids"])...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, deviceSource := range []string{"homelist", "share_home_list"} {
|
||||
for hidStr, info := range moreList {
|
||||
if _, exists := homeInfos[deviceSource][hidStr]; !exists {
|
||||
continue
|
||||
}
|
||||
h, _ := homeInfos[deviceSource][hidStr].(map[string]interface{})
|
||||
if h == nil {
|
||||
continue
|
||||
}
|
||||
h["dids"] = append(toStringSlice(h["dids"]), toStringSlice(info["dids"])...)
|
||||
|
||||
for rid, rinfo := range info["room_info"].(map[string]map[string]interface{}) {
|
||||
hRoomInfo, _ := h["room_info"].(map[string]interface{})
|
||||
if hRoomInfo == nil {
|
||||
hRoomInfo = make(map[string]interface{})
|
||||
h["room_info"] = hRoomInfo
|
||||
}
|
||||
if hRoomInfo[rid] == nil {
|
||||
hRoomInfo[rid] = map[string]interface{}{
|
||||
"room_id": rid,
|
||||
"room_name": "",
|
||||
"dids": []string{},
|
||||
}
|
||||
}
|
||||
hrEntry, _ := hRoomInfo[rid].(map[string]interface{})
|
||||
if hrEntry != nil {
|
||||
hrEntry["dids"] = append(
|
||||
toStringSlice(hrEntry["dids"]),
|
||||
toStringSlice(rinfo["dids"])...)
|
||||
for rid, rinfo := range info["room_info"].(map[string]map[string]interface{}) {
|
||||
hRoomInfo, _ := h["room_info"].(map[string]interface{})
|
||||
if hRoomInfo == nil {
|
||||
hRoomInfo = make(map[string]interface{})
|
||||
h["room_info"] = hRoomInfo
|
||||
}
|
||||
if hRoomInfo[rid] == nil {
|
||||
hRoomInfo[rid] = map[string]interface{}{
|
||||
"room_id": rid,
|
||||
"room_name": "",
|
||||
"dids": []string{},
|
||||
}
|
||||
}
|
||||
hrEntry, _ := hRoomInfo[rid].(map[string]interface{})
|
||||
if hrEntry != nil {
|
||||
hrEntry["dids"] = append(
|
||||
toStringSlice(hrEntry["dids"]),
|
||||
toStringSlice(rinfo["dids"])...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,13 +726,14 @@ func (c *MIoTHttpClient) getDeviceListPage(dids []string, startDID string) (map[
|
||||
|
||||
// Handle pagination
|
||||
nextStartDID, _ := result["next_start_did"].(string)
|
||||
hasMore, _ := result["has_more"].(bool)
|
||||
hasMore := parseBool(result["has_more"])
|
||||
if hasMore && nextStartDID != "" {
|
||||
nextInfos, err := c.getDeviceListPage(dids, nextStartDID)
|
||||
if err == nil {
|
||||
for k, v := range nextInfos {
|
||||
deviceInfos[k] = v
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range nextInfos {
|
||||
deviceInfos[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1196,3 +1198,22 @@ func containsString(slice []string, val string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseBool 兼容云端多种布尔表达(bool / 0|1 / "true"|"false")。
|
||||
func parseBool(v interface{}) bool {
|
||||
switch n := v.(type) {
|
||||
case bool:
|
||||
return n
|
||||
case float64:
|
||||
return n != 0
|
||||
case float32:
|
||||
return n != 0
|
||||
case int:
|
||||
return n != 0
|
||||
case int64:
|
||||
return n != 0
|
||||
case string:
|
||||
return n == "true" || n == "1"
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user