Files
xiaomihome/xiaomi/specs/mapper.go
T
4566704 a3d94c4b9f 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 示例(风扇/窗帘/传感器控制)
2026-06-29 08:51:21 +08:00

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
}