feat: 初始化小米 IoT (MIoT) 智能家居 Go 库

- 实现 MIoT 客户端核心功能(MQTT 连接、设备管理、属性读写)
- 支持云端 API 调用与局域网设备发现(mDNS)
- 集成国际化(i18n)多语言支持
- 添加 MIoT 设备规约解析器(spec_parser)
- 包含单元测试与使用示例
This commit is contained in:
2026-06-28 22:05:49 +08:00
parent ac442812b4
commit 3a44cb9e6a
118 changed files with 31630 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
// Package miot provides MIoT core client for Xiaomi Home devices.
// This file is a direct port of py-miot/miot_i18n.py.
package miot
import (
"log"
"strings"
)
// MIoTI18n provides internationalization translation.
// Translate by Copilot, which does not guarantee the accuracy of the
// translation. If there is a problem with the translation, please submit
// the ISSUE feedback. After the review, we will modify it as soon as possible.
type MIoTI18n struct {
lang string
data map[string]interface{}
}
// NewMIoTI18n creates a new MIoTI18n instance.
func NewMIoTI18n(lang string) *MIoTI18n {
return &MIoTI18n{
lang: lang,
data: make(map[string]interface{}),
}
}
// Init loads the i18n JSON file for the configured language.
func (i *MIoTI18n) Init() {
if len(i.data) > 0 {
return
}
i.data = make(map[string]interface{})
data, err := LoadJSONFile(GenAbsolutePath("i18n/" + i.lang + ".json"))
if err != nil {
log.Printf("load i18n file error: %v", err)
return
}
if data == nil {
log.Printf("invalid i18n file: nil data")
return
}
i.data = data
}
// Deinit clears the loaded translation data.
func (i *MIoTI18n) Deinit() {
i.data = make(map[string]interface{})
}
// Translate looks up a translation by dot-separated key.
// It traverses nested JSON objects, e.g. "device.light.name"
// -> data["device"]["light"]["name"].
// If the key is not found, returns an empty string.
// Optional replace map performs placeholder substitution: {key} -> value.
func (i *MIoTI18n) Translate(key string, replace map[string]string) string {
result := i.lookup(strings.Split(key, "."))
s, ok := result.(string)
if !ok {
return ""
}
if replace != nil {
for k, v := range replace {
s = strings.ReplaceAll(s, "{"+k+"}", v)
}
}
return s
}
// lookup traverses the nested map using the given key segments.
func (i *MIoTI18n) lookup(keys []string) interface{} {
var cur interface{} = i.data
for _, k := range keys {
m, ok := cur.(map[string]interface{})
if !ok {
return nil
}
cur = m[k]
if cur == nil {
return nil
}
}
return cur
}