- 新增 xiaomi/examples/ 下 8 个示例程序(用户/家庭查询、设备列表、开关/灯光/空调控制、属性订阅、高级过滤分类、SPEC 解析) - miot_client_sub.go: 重构 SubProp/SubEvent,使用 buildPropTopic/buildEventTopic 支持通配符订阅(siid/piid=0 → +),并修复锁顺序问题(将 RequestRefreshProp 移到 Lock 外) - spec_parser.go: 新增 downloadSpecFile 方法,本地 SPEC 文件缺失时自动从 miot-spec.org 下载 - ARCH_PLAN.md: 架构设计从 Proposed 更新为 Accepted(v1.0→v1.1),补充设备分类/工厂/SPEC 映射等模块设计 - xiaomi/: 新增 miot 上层强类型封装模块,包含 Client 主入口、用户/家庭/设备 API、属性读写、动作调用、订阅通知,以及 devices/ 设备控制抽象(Switch/Light/AirConditioner/Fan/Cover/Humidifier/Vacuum/WaterHeater/Thermostat)和 specs/ SPEC 查询辅助 - 更多 xiaomi 示例(风扇/窗帘/传感器控制)
121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package specs
|
|
|
|
import "xiaomihome/miot"
|
|
|
|
// PropertyMapper provides bidirectional mapping between SPEC raw values (integers)
|
|
// and human-readable enum strings. For example, an air conditioner mode property
|
|
// might use raw value 0 for "cool", 1 for "heat", etc.
|
|
//
|
|
// The mapper is constructed from the SPEC value-list combined with an external
|
|
// lookup table that maps raw values to their semantic names.
|
|
type PropertyMapper struct {
|
|
rawToEnum map[interface{}]string
|
|
enumToRaw map[string]interface{}
|
|
}
|
|
|
|
// NewPropertyMapper creates a PropertyMapper from a SPEC value-list and
|
|
// a mapping of raw values → enum strings.
|
|
//
|
|
// Example:
|
|
//
|
|
// mapper := NewPropertyMapper(prop.ValueList, map[interface{}]string{
|
|
// 0: "cool",
|
|
// 1: "heat",
|
|
// 2: "fan",
|
|
// 3: "dry",
|
|
// 4: "auto",
|
|
// })
|
|
func NewPropertyMapper(vlist miot.MIoTSpecValueList, valueMap map[interface{}]string) *PropertyMapper {
|
|
m := &PropertyMapper{
|
|
rawToEnum: make(map[interface{}]string),
|
|
enumToRaw: make(map[string]interface{}),
|
|
}
|
|
|
|
// Build from the provided valueMap
|
|
for raw, enum := range valueMap {
|
|
m.rawToEnum[raw] = enum
|
|
m.enumToRaw[enum] = raw
|
|
}
|
|
|
|
// Also build from SPEC value-list descriptions (as a fallback)
|
|
for _, item := range vlist {
|
|
if item.Desc != "" {
|
|
name := item.Desc
|
|
if item.Name != "" {
|
|
name = item.Name
|
|
}
|
|
m.rawToEnum[item.Value] = name
|
|
m.enumToRaw[name] = item.Value
|
|
}
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
// ToEnum converts a raw SPEC value to its enum string representation.
|
|
// Returns ("", false) if the raw value is not in the mapping.
|
|
func (m *PropertyMapper) ToEnum(raw interface{}) (string, bool) {
|
|
if m == nil {
|
|
return "", false
|
|
}
|
|
s, ok := m.rawToEnum[raw]
|
|
return s, ok
|
|
}
|
|
|
|
// ToRaw converts an enum string to its raw SPEC value.
|
|
// Returns (nil, false) if the enum string is not in the mapping.
|
|
func (m *PropertyMapper) ToRaw(enum string) (interface{}, bool) {
|
|
if m == nil {
|
|
return nil, false
|
|
}
|
|
v, ok := m.enumToRaw[enum]
|
|
return v, ok
|
|
}
|
|
|
|
// HasEnum checks whether the given enum string exists in the mapping.
|
|
func (m *PropertyMapper) HasEnum(enum string) bool {
|
|
if m == nil {
|
|
return false
|
|
}
|
|
_, ok := m.enumToRaw[enum]
|
|
return ok
|
|
}
|
|
|
|
// HasRaw checks whether the given raw value exists in the mapping.
|
|
func (m *PropertyMapper) HasRaw(raw interface{}) bool {
|
|
if m == nil {
|
|
return false
|
|
}
|
|
_, ok := m.rawToEnum[raw]
|
|
return ok
|
|
}
|
|
|
|
// FromValueList creates a PropertyMapper purely from the SPEC value list.
|
|
// Uses the ValueItem.Desc or ValueItem.Name as the enum string.
|
|
func FromValueList(vlist miot.MIoTSpecValueList) *PropertyMapper {
|
|
if len(vlist) == 0 {
|
|
return &PropertyMapper{
|
|
rawToEnum: make(map[interface{}]string),
|
|
enumToRaw: make(map[string]interface{}),
|
|
}
|
|
}
|
|
|
|
m := &PropertyMapper{
|
|
rawToEnum: make(map[interface{}]string),
|
|
enumToRaw: make(map[string]interface{}),
|
|
}
|
|
|
|
for _, item := range vlist {
|
|
name := item.Name
|
|
if name == "" {
|
|
name = item.Desc
|
|
}
|
|
if name != "" {
|
|
m.rawToEnum[item.Value] = name
|
|
m.enumToRaw[name] = item.Value
|
|
}
|
|
}
|
|
|
|
return m
|
|
}
|