chore: 提交高层 xiaomi 封装库及示例
- 新增 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 示例(风扇/窗帘/传感器控制)
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user