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
+284
View File
@@ -0,0 +1,284 @@
# 01 - miot_client.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_client.py` (837行) |
| **Go 文件** | `go-miot/miot_client.go` + `miot_client_api.go` + `miot_client_prop.go` + `miot_client_sub.go` |
| **状态** | ⚠️ 部分实现 |
| **优先级** | 🔴 P0 |
| **预计工作量** | 8-12 小时 |
## Python 版本分析
### 核心类
#### MIoTClient
**位置**:第 31-837 行
**主要职责**:
- 小米 IoT 设备的主客户端类
- 管理设备列表、属性刷新、命令发送
- 协调多个子模块(OAuth、Cloud、MIPS)
**核心方法**:
| 方法名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `__init__` | 31 | 初始化客户端,加载配置 | ✅ 已完成 |
| `load_config` | 47 | 加载配置文件 | ✅ 已完成 |
| `save_config` | 68 | 保存配置文件 | ✅ 已完成 |
| `discover_devices` | 89 | 发现设备(从云端或本地) | ⚠️ 部分实现 |
| `get_devices` | 125 | 获取设备列表 | ✅ 已完成 |
| `get_device` | 142 | 根据 DID 获取单个设备 | ✅ 已完成 |
| `refresh_devices` | 163 | 刷新设备列表(从云端) | ⚠️ 部分实现 |
| `refresh_properties` | 201 | 批量刷新设备属性 | ⚠️ 部分实现 |
| `send_command` | 267 | 发送控制命令 | ⚠️ 部分实现 |
| `subscribe_prop` | 345 | 订阅属性变化 | ❌ 缺失 |
| `unsubscribe_prop` | 389 | 取消订阅属性变化 | ❌ 缺失 |
| `start_monitor` | 423 | 启动属性监控线程 | ❌ 缺失 |
| `stop_monitor` | 467 | 停止属性监控线程 | ❌ 缺失 |
| `poll_devices` | 501 | 轮询设备状态 | ❌ 缺失 |
| `call_action` | 567 | 调用设备动作(如开启、关闭) | ⚠️ 部分实现 |
| `get_device_prop` | 623 | 获取设备属性值 | ✅ 已完成 |
| `set_device_prop` | 659 | 设置设备属性值 | ✅ 已完成 |
| `run_mips_script` | 721 | 运行 MIPS 脚本 | ❌ 缺失 |
| `close` | 789 | 关闭客户端,释放资源 | ⚠️ 部分实现 |
### 辅助函数
| 函数名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `load_token_from_env` | 812 | 从环境变量加载 token | ❌ 缺失 |
| `parse_device_list` | 826 | 解析设备列表 JSON | ✅ 已完成 |
## Go 版本现状
### 已实现的文件结构
```
go-miot/
├── miot_client.go # 主客户端类(对应 Python 的 MIoTClient)
├── miot_client_api.go # API 调用方法(对应 Python 的网络请求)
├── miot_client_prop.go # 属性相关方法(对应 Python 的 refresh_properties 等)
├── miot_client_sub.go # 订阅相关方法(对应 Python 的 subscribe_prop 等)
└── miot_device.go # 设备类(对应 Python 的 MIoTDevice)
```
### 缺失的功能
#### 1. 设备发现 (`discover_devices`)
**Python 实现**:
```python
def discover_devices(self, source: str = "cloud"):
"""发现设备"""
if source == "cloud":
return self.refresh_devices()
elif source == "lan":
return self._discover_lan_devices()
else:
raise ValueError(f"Unknown source: {source}")
```
**Go 缺失**:
- ❌ LAN 设备发现(需要 `miot_lan.py`)
- ⚠️ 云端设备发现已部分实现
#### 2. 属性订阅系统 (`subscribe_prop`, `unsubscribe_prop`)
**Python 实现**:
- 使用回调机制
- 支持多设备、多属性订阅
- 后台线程轮询
**Go 缺失**:
- ❌ 完整的订阅系统
- ❌ 回调机制
- ❌ 后台轮询线程
#### 3. 属性监控 (`start_monitor`, `stop_monitor`)
**Python 实现**:
- 启动后台线程
- 定期轮询订阅的属性
- 触发回调
**Go 缺失**:
- ❌ 后台 goroutine 管理
- ❌ 定时轮询
- ❌ 回调触发
#### 4. MIPS 脚本支持 (`run_mips_script`)
**Python 实现**:
- 调用 MIPS 客户端
- 执行自动化脚本
**Go 缺失**:
- ❌ MIPS 客户端集成
- ❌ 脚本执行接口
## 移植建议
### 第一批任务(核心功能)
1. **补全 `discover_devices`** (2小时)
- 实现 LAN 设备发现接口(占位)
- 统一云端和本地发现的返回格式
2. **实现属性订阅系统** (4小时)
- 设计回调接口(`PropertyChangeCallback`)
- 实现 `SubscribeProp` 方法
- 实现 `UnsubscribeProp` 方法
- 管理订阅列表
3. **实现属性监控** (3小时)
- 启动后台 goroutine
- 定时轮询订阅的属性
- 比较属性变化,触发回调
- 实现优雅停止
### 第二批任务(高级功能)
4. **MIPS 脚本支持** (2小时)
- 集成 MIPS 客户端
- 实现 `RunMipsScript` 方法
5. **环境变量支持** (1小时)
- 实现 `load_token_from_env`
- 支持从环境变量读取配置
## 技术难点
### 1. 并发安全
**问题**:Python 版本使用线程,Go 版本需要使用 goroutine
**建议**:
- 使用 `sync.RWMutex` 保护共享状态
- 使用 channel 进行 goroutine 通信
- 避免全局变量
### 2. 回调机制
**问题**:Python 使用函数回调,Go 需要使用接口或 channel
**建议**:
```go
// 方案 1:接口
type PropertyChangeCallback interface {
OnPropertyChange(device *MIoTDevice, prop *Property, oldValue, newValue interface{})
}
// 方案 2:函数类型
type PropertyChangeHandler func(device *MIoTDevice, prop *Property, oldValue, newValue interface{})
// 方案 3:Channel
type PropertyChangeEvent struct {
Device *MIoTDevice
Property *Property
OldValue interface{}
NewValue interface{}
}
var PropertyChangeChan = make(chan PropertyChangeEvent, 100)
```
### 3. 后台任务管理
**问题**:Python 使用 `threading.Thread`,Go 需要使用 goroutine 和 context
**建议**:
```go
type MIoTClient struct {
// ...
monitorCtx context.Context
monitorCancel context.CancelFunc
monitorWg sync.WaitGroup
}
func (c *MIoTClient) StartMonitor(interval time.Duration) error {
c.monitorCtx, c.monitorCancel = context.WithCancel(context.Background())
c.monitorWg.Add(1)
go func() {
defer c.monitorWg.Done()
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-c.monitorCtx.Done():
return
case <-ticker.C:
c.pollSubscribedProperties()
}
}
}()
return nil
}
```
## 测试计划
### 单元测试
1. **设备发现测试**
- 测试云端设备发现
- 测试本地设备发现(需要 mock)
2. **属性订阅测试**
- 测试订阅和取消订阅
- 测试回调触发
- 测试并发订阅
3. **属性监控测试**
- 测试启动和停止
- 测试定时轮询
- 测试优雅停止
### 集成测试
1. **端到端测试**
- 使用真实设备测试
- 测试完整流程:发现 → 订阅 → 监控 → 控制
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_device.py` | 强依赖 | 设备类 |
| `miot_cloud.py` | 强依赖 | 云端 API |
| `miot_oauth.py` | 强依赖 | OAuth 认证 |
| `miot_storage.py` | 强依赖 | 配置存储 |
| `miot_mips.py` | 弱依赖 | MIPS 脚本 |
| `miot_lan.py` | 弱依赖 | LAN 控制 |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 补全 `discover_devices` | 🔴 高 | 核心功能,影响设备发现 |
| 实现属性订阅 | 🔴 高 | 核心功能,影响实时监控 |
| 实现属性监控 | 🔴 高 | 核心功能,影响实时监控 |
| MIPS 脚本支持 | 🟡 中 | 高级功能,可选 |
| 环境变量支持 | 🟢 低 | 辅助功能,方便配置 |
## 进度跟踪
- [ ] 补全 `discover_devices` (预计 2小时)
- [ ] 实现属性订阅系统 (预计 4小时)
- [ ] 实现属性监控 (预计 3小时)
- [ ] MIPS 脚本支持 (预计 2小时)
- [ ] 环境变量支持 (预计 1小时)
- [ ] 单元测试 (预计 4小时)
- [ ] 集成测试 (预计 2小时)
**总计**:18小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+255
View File
@@ -0,0 +1,255 @@
# 02 - miot_device.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_device.py` (469行) |
| **Go 文件** | `go-miot/miot_device.go` |
| **状态** | ⚠️ 部分实现 |
| **优先级** | 🔴 P0 |
| **预计工作量** | 6-10 小时 |
## Python 版本分析
### 核心类
#### MIoTDevice
**位置**:第 18-469 行
**主要职责**:
- 表示单个小米 IoT 设备
- 管理设备的属性、方法、事件
- 提供设备控制和查询接口
**核心方法**:
| 方法名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `__init__` | 18 | 初始化设备对象 | ✅ 已完成 |
| `from_dict` | 45 | 从字典创建设备对象 | ✅ 已完成 |
| `to_dict` | 78 | 转换为字典 | ✅ 已完成 |
| `get_property` | 112 | 获取属性值 | ✅ 已完成 |
| `set_property` | 139 | 设置属性值(本地缓存) | ✅ 已完成 |
| `call_action` | 167 | 调用设备动作 | ⚠️ 部分实现 |
| `get_service` | 223 | 获取服务定义 | ❌ 缺失 |
| `get_property_def` | 251 | 获取属性定义 | ❌ 缺失 |
| `get_action_def` | 279 | 获取动作定义 | ❌ 缺失 |
| `refresh` | 307 | 从云端刷新属性 | ⚠️ 部分实现 |
| `to_string` | 365 | 转换为可读字符串 | ✅ 已完成 |
| `to_json` | 401 | 转换为 JSON | ✅ 已完成 |
### 辅助类
#### DeviceProperty
**位置**:第 415-450 行
**功能**:表示设备属性的元数据
**Go 状态**:✅ 已完成(对应 `Property` 结构体)
#### DeviceService
**位置**:第 451-469 行
**功能**:表示设备服务的元数据
**Go 状态**:❌ 缺失
## Go 版本现状
### 已实现的结构体
```go
type MIoTDevice struct {
DID string
Name string
Model string
Token string
IPAddress string
Port int
Properties map[string]interface{}
PropertyDefs map[string]*Property
// ...
}
```
### 缺失的功能
#### 1. 服务定义查询 (`get_service`, `get_property_def`, `get_action_def`)
**Python 实现**:
```python
def get_service(self, service_id: str) -> dict:
"""获取服务定义"""
spec = self._get_spec()
return spec.get_service(service_id)
def get_property_def(self, siid: int, piid: int) -> dict:
"""获取属性定义"""
spec = self._get_spec()
return spec.get_property(siid, piid)
```
**Go 缺失**:
- ❌ 服务定义查询
- ❌ 属性定义查询
- ❌ 动作定义查询
- ❌ SPEC 集成
#### 2. 完整的 `call_action` 实现
**Python 实现**:
- 支持同步和异步调用
- 支持参数验证
- 支持结果解析
**Go 缺失**:
- ⚠️ 参数验证
- ⚠️ 结果解析
- ❌ 异步调用支持
#### 3. `DeviceService` 类
**Python 实现**:
```python
class DeviceService:
"""设备服务元数据"""
def __init__(self, siid: int, type: str):
self.siid = siid
self.type = type
```
**Go 缺失**:
- ❌ `DeviceService` 结构体
- ❌ 服务元数据管理
## 移植建议
### 第一批任务(核心功能)
1. **集成 SPEC 查询** (3小时)
- 实现 `GetService` 方法
- 实现 `GetPropertyDef` 方法
- 实现 `GetActionDef` 方法
- 集成 `spec_parser.go`
2. **补全 `CallAction`** (2小时)
- 实现参数验证
- 实现结果解析
- 实现异步调用支持(可选)
### 第二批任务(辅助功能)
3. **实现 `DeviceService` 结构体** (1小时)
- 定义结构体
- 实现构造函数
- 实现查询方法
4. **优化属性管理** (2小时)
- 改进属性缓存机制
- 实现属性变更通知
- 实现属性历史记录(可选)
## 技术难点
### 1. SPEC 集成
**问题**:需要从 SPEC 文件查询服务和属性定义
**建议**:
```go
type MIoTDevice struct {
// ...
specParser *SpecParser
}
func (d *MIoTDevice) GetService(serviceID string) (*Service, error) {
if d.specParser == nil {
return nil, errors.New("spec parser not initialized")
}
return d.specParser.GetService(serviceID)
}
```
### 2. 属性缓存同步
**问题**:本地缓存的属性值需要与云端同步
**建议**:
- 实现 `Refresh` 方法,从云端刷新属性
- 实现属性变更通知机制
- 使用时间戳判断属性是否过期
### 3. 动作调用的异步支持
**问题**:某些设备动作可能需要较长时间执行
**建议**:
```go
// 同步调用
func (d *MIoTDevice) CallAction(siid, aiid int, params map[string]interface{}) (map[string]interface{}, error)
// 异步调用
func (d *MIoTDevice) CallActionAsync(siid, aiid int, params map[string]interface{}) <-chan ActionResult
```
## 测试计划
### 单元测试
1. **设备创建测试**
- 测试从字典创建
- 测试转换为字典
- 测试属性管理
2. **属性查询测试**
- 测试 `GetProperty`
- 测试 `SetProperty`
- 测试 `Refresh`
3. **动作调用测试**
- 测试 `CallAction`
- 测试参数验证
- 测试结果解析
### 集成测试
1. **端到端测试**
- 使用真实设备测试
- 测试完整流程:创建 → 查询 → 控制
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_spec.py` | 强依赖 | SPEC 查询 |
| `miot_client.py` | 弱依赖 | 客户端调用 |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 集成 SPEC 查询 | 🔴 高 | 核心功能,影响属性查询 |
| 补全 `CallAction` | 🔴 高 | 核心功能,影响设备控制 |
| 实现 `DeviceService` | 🟡 中 | 辅助功能,提升可用性 |
| 优化属性管理 | 🟢 低 | 优化功能,可选 |
## 进度跟踪
- [ ] 集成 SPEC 查询 (预计 3小时)
- [ ] 补全 `CallAction` (预计 2小时)
- [ ] 实现 `DeviceService` 结构体 (预计 1小时)
- [ ] 优化属性管理 (预计 2小时)
- [ ] 单元测试 (预计 3小时)
- [ ] 集成测试 (预计 2小时)
**总计**:13小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+248
View File
@@ -0,0 +1,248 @@
# 03 - miot_cloud.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_cloud.py` (270行) |
| **Go 文件** | ❌ 缺失 |
| **状态** | ❌ 完全缺失 |
| **优先级** | 🔴 P0 |
| **预计工作量** | 10-14 小时 |
## Python 版本分析
### 核心类
#### MIoTOauthClient(OAuth 客户端)
**位置**:第 73-228 行
**主要职责**:
- OAuth 认证流程管理
- 生成授权 URL
- 获取和刷新 access token
- 管理 token 过期时间
**核心方法**:
| 方法名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `__init__` | 83 | 初始化 OAuth 客户端 | ❌ 缺失 |
| `gen_auth_url` | 121 | 生成授权 URL | ❌ 缺失 |
| `get_access_token_async` | 193 | 使用授权码获取 access token | ❌ 缺失 |
| `refresh_access_token_async` | 212 | 使用 refresh token 刷新 access token | ❌ 缺失 |
| `deinit_async` | 112 | 清理资源 | ❌ 缺失 |
#### MIoTHttpClient(HTTP 客户端)
**位置**:第 231-538 行
**主要职责**:
- 封装小米 IoT 云端 API 调用
- 处理设备查询、属性读写、动作调用
- 管理 HTTP 请求和响应
- 处理 token 过期和刷新
**核心方法**:
| 方法名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `__init__` | 246 | 初始化 HTTP 客户端 | ❌ 缺失 |
| `update_http_header` | 284 | 更新 HTTP 请求头 | ❌ 缺失 |
| `get_user_info_async` | 365 | 获取用户信息 | ❌ 缺失 |
| `get_central_cert_async` | 386 | 获取中央证书 | ❌ 缺失 |
| `get_homeinfos_async` | 459 | 获取家庭信息 | ❌ 缺失 |
| `get_separated_shared_devices_async` | 448 | 获取共享设备 | ❌ 缺失 |
## Go 版本现状
### 缺失的功能
整个 `miot_cloud.py` 模块在 Go 版本中完全缺失。
Go 版本中相关的云端调用分散在:
- `miot_client_api.go` - 部分 API 调用
- `http_client.go` - HTTP 客户端
但是缺少统一的云端客户端封装。
## 移植建议
### 第一批任务(核心功能)
1. **创建 `miot_cloud.go` 文件** (1小时)
- 定义 `MIoTCloud` 结构体
- 实现构造函数
2. **实现登录功能** (2小时)
- 实现 `Login` 方法
- 集成 OAuth token 管理
- 处理 token 过期和刷新
3. **实现设备查询** (2小时)
- 实现 `GetDevices` 方法
- 实现 `GetDeviceInfo` 方法
- 解析设备列表 JSON
4. **实现属性读写** (2小时)
- 实现 `GetDeviceProp` 方法
- 实现 `SetDeviceProp` 方法
- 处理批量读写
5. **实现动作调用** (2小时)
- 实现 `CallDeviceAction` 方法
- 处理同步和异步调用
- 解析返回结果
### 第二批任务(辅助功能)
6. **实现 LAN 命令转发** (2小时)
- 实现 `SendLanCommand` 方法
- 通过云端转发 LAN 命令
7. **优化 HTTP 客户端** (1小时)
- 集成 `http_client.go`
- 实现重试机制
- 实现错误处理
8. **实现请求签名** (2小时)
- 实现 `_build_url` 功能
- 实现请求签名算法
- 处理 API 版本
## 技术难点
### 1. OAuth Token 管理
**问题**:需要处理 token 的存储、读取、刷新
**建议**:
```go
type MIoTCloud struct {
// ...
oauthClient *MIoTOAuth
token *OAuthToken
}
func (c *MIoTCloud) Login() error {
// 尝试从存储加载 token
token, err := c.storage.LoadToken()
if err == nil && !token.IsExpired() {
c.token = token
return nil
}
// 刷新 token
token, err = c.oauthClient.RefreshToken(token)
if err != nil {
return err
}
c.token = token
return c.storage.SaveToken(token)
}
```
### 2. API 请求签名
**问题**:小米 IoT 云端 API 需要签名
**建议**:
- 参考 Python 版本的 `_build_url` 实现
- 实现签名算法(MD5、nonce、timestamp)
- 处理 API 版本差异
### 3. 错误处理
**问题**:云端 API 可能返回各种错误
**建议**:
```go
type CloudError struct {
Code int
Message string
}
func (e *CloudError) Error() string {
return fmt.Sprintf("cloud error: code=%d, message=%s", e.Code, e.Message)
}
func (c *MIoTCloud) handleResponse(resp *http.Response) (interface{}, error) {
// 解析响应
// 检查错误码
// 返回结果或错误
}
```
## 测试计划
### 单元测试
1. **登录测试**
- 测试 token 加载
- 测试 token 刷新
- 测试登录失败
2. **设备查询测试**
- 测试获取设备列表
- 测试获取设备信息
- 测试解析错误
3. **属性读写测试**
- 测试获取属性
- 测试设置属性
- 测试批量操作
4. **动作调用测试**
- 测试调用动作
- 测试参数验证
- 测试结果解析
### 集成测试
1. **端到端测试**
- 使用真实账号测试
- 测试完整流程:登录 → 查询 → 控制
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_oauth.py` | 强依赖 | OAuth 认证 |
| `miot_storage.py` | 强依赖 | Token 存储 |
| `http_client.go` | 强依赖 | HTTP 客户端 |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 创建基础结构 | 🔴 高 | 基础框架 |
| 实现登录功能 | 🔴 高 | 核心功能,其他功能依赖 |
| 实现设备查询 | 🔴 高 | 核心功能 |
| 实现属性读写 | 🔴 高 | 核心功能 |
| 实现动作调用 | 🔴 高 | 核心功能 |
| 实现 LAN 命令转发 | 🟡 中 | 高级功能 |
| 优化 HTTP 客户端 | 🟡 中 | 优化功能 |
| 实现请求签名 | 🟡 中 | 必要功能 |
## 进度跟踪
- [ ] 创建 `miot_cloud.go` 文件 (预计 1小时)
- [ ] 实现登录功能 (预计 2小时)
- [ ] 实现设备查询 (预计 2小时)
- [ ] 实现属性读写 (预计 2小时)
- [ ] 实现动作调用 (预计 2小时)
- [ ] 实现 LAN 命令转发 (预计 2小时)
- [ ] 优化 HTTP 客户端 (预计 1小时)
- [ ] 实现请求签名 (预计 2小时)
- [ ] 单元测试 (预计 4小时)
- [ ] 集成测试 (预计 2小时)
**总计**:20小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+258
View File
@@ -0,0 +1,258 @@
# 05 - miot_storage.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_storage.py` (789行) |
| **Go 文件** | ❌ 缺失 |
| **状态** | ❌ 完全缺失 |
| **优先级** | 🔴 P0 |
| **预计工作量** | 12-16 小时 |
## Python 版本分析
### 核心类
#### MIoTStorage
**位置**:第 90-538 行
**主要职责**:
- 文件管理(同步和异步)
- 支持多种数据类型(bytes、str、dict、list)
- 文件完整性检查(SHA256 哈希)
- 异步操作支持(使用 `asyncio`)
**核心方法**:
| 方法名 | 行号 | 功能 | 说明 |
|--------|------|------|------|
| `__init__` | 100 | 初始化存储 | 设置根路径和事件循环 |
| `load` | 168 | 加载文件(同步) | 支持多种数据类型 |
| `load_async` | 175 | 加载文件(异步) | 使用 `run_in_executor` |
| `save` | 232 | 保存文件(同步) | 支持多种数据类型 |
| `save_async` | 239 | 保存文件(异步) | 使用 `run_in_executor` |
| `remove` | 260 | 删除文件(同步) | |
| `remove_async` | 265 | 删除文件(异步) | |
| `remove_domain` | 288 | 删除域目录(同步) | 递归删除 |
| `remove_domain_async` | 292 | 删除域目录(异步) | |
| `get_names` | 312 | 获取文件名列表 | 按类型过滤 |
| `file_exists` | 322 | 检查文件是否存在 | |
| `save_file` | 326 | 保存二进制文件(同步) | 不添加哈希 |
| `load_file` | 352 | 加载二进制文件(同步) | |
| `clear` | 397 | 清空存储(同步) | |
| `clear_async` | 406 | 清空存储(异步) | |
| `update_user_config` | 421 | 更新用户配置 | 支持部分更新 |
| `load_user_config` | 481 | 加载用户配置 | 支持键过滤 |
**关键特性**:
- 文件完整性检查(SHA256 哈希)
- 异步操作支持
- 操作去重(避免重复执行相同操作)
- 用户配置管理
#### MIoTCert
**位置**:第 540-727 行
**主要职责**:
- 证书管理(CA 证书、用户证书、私钥)
- 证书验证
- 证书生成(CSR)
**核心方法**:
| 方法名 | 行号 | 功能 |
|--------|------|------|
| `verify_ca_cert_async` | 583 | 验证 CA 证书 |
| `user_cert_remaining_time_async` | 605 | 获取用户证书剩余有效期 |
| `gen_user_key` | 655 | 生成用户私钥(Ed25519) |
| `gen_user_csr` | 664 | 生成 CSR |
| `load_user_key_async` | 682 | 加载用户私钥 |
| `update_user_key_async` | 688 | 更新用户私钥 |
| `load_user_cert_async` | 695 | 加载用户证书 |
| `update_user_cert_async` | 701 | 更新用户证书 |
#### DeviceManufacturer
**位置**:第 729-789 行
**主要职责**:
- 设备制造商信息缓存
- 从云端获取制造商信息
- 本地缓存管理
**核心方法**:
| 方法名 | 行号 | 功能 |
|--------|------|------|
| `init_async` | 744 | 初始化(加载缓存或从云端获取) |
| `deinit_async` | 782 | 清理 |
| `get_name` | 785 | 根据缩写获取完整名称 |
## Go 版本现状
### 缺失的功能
整个 `miot_storage.py` 模块在 Go 版本中完全缺失。
Go 版本中可能需要实现:
1. **文件存储管理** - 对应 `MIoTStorage`
2. **证书管理** - 对应 `MIoTCert`
3. **制造商信息缓存** - 对应 `DeviceManufacturer`
## 移植建议
### 第一批任务(核心功能)
1. **创建 `miot_storage.go` 文件** (2小时)
- 定义 `MIoTStorage` 结构体
- 实现构造函数
2. **实现文件读写** (4小时)
- 实现 `Load` 和 `Save` 方法
- 支持多种数据类型([]byte、string、map、slice)
- 实现哈希检查
3. **实现异步操作** (3小时)
- 使用 goroutine 实现异步
- 实现操作去重(避免重复执行)
- 实现优雅关闭
4. **实现用户配置管理** (2小时)
- 实现 `UpdateUserConfig` 方法
- 实现 `LoadUserConfig` 方法
### 第二批任务(证书管理)
5. **创建 `miot_cert.go` 文件** (1小时)
- 定义 `MIoTCert` 结构体
6. **实现证书管理** (4小时)
- 实现 CA 证书验证
- 实现用户证书管理
- 实现证书生成(如果需要)
### 第三批任务(制造商信息)
7. **创建 `miot_manufacturer.go` 文件** (1小时)
- 定义 `DeviceManufacturer` 结构体
8. **实现制造商信息缓存** (2小时)
- 实现初始化
- 实现缓存更新
## 技术难点
### 1. 异步操作
**问题**:Python 使用 `asyncio`,Go 使用 goroutine
**建议**:
```go
type MIoTStorage struct {
rootPath string
mu sync.RWMutex
// 操作去重
pendingOps map[string]*PendingOp
}
type PendingOp struct {
done chan struct{}
result interface{}
err error
}
```
### 2. 文件完整性检查
**问题**:需要在文件中嵌入 SHA256 哈希
**建议**:
```go
func (s *MIoTStorage) Save(domain, name string, data interface{}) error {
var bytes []byte
switch v := data.(type) {
case []byte:
bytes = v
case string:
bytes = []byte(v)
case map[string]interface{}, []interface{}:
bytes, _ = json.Marshal(v)
}
// 添加哈希
hash := sha256.Sum256(bytes)
bytesWithHash := append(bytes, hash[:]...)
// 写入文件
return ioutil.WriteFile(s.getFullPath(domain, name, data), bytesWithHash, 0644)
}
```
### 3. 证书管理
**问题**:需要使用加密库
**建议**:
- 使用 Go 标准库 `crypto`
- 使用第三方库 `golang.org/x/crypto/ed25519`
## 测试计划
### 单元测试
1. **文件读写测试**
- 测试各种数据类型的读写
- 测试哈希检查
- 测试错误处理
2. **异步操作测试**
- 测试并发读写
- 测试操作去重
- 测试优雅关闭
3. **证书管理测试**
- 测试证书验证
- 测试证书生成
- 测试证书加载
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_error.py` | 强依赖 | 错误定义 |
| `const.py` | 强依赖 | 常量定义 |
| `crypto` 库 | 强依赖 | 证书管理 |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 创建基础结构 | 🔴 高 | 基础框架 |
| 实现文件读写 | 🔴 高 | 核心功能 |
| 实现异步操作 | 🔴 高 | 核心功能 |
| 实现用户配置 | 🔴 高 | 核心功能 |
| 实现证书管理 | 🟡 中 | 重要功能 |
| 实现制造商信息 | 🟢 低 | 辅助功能 |
## 进度跟踪
- [ ] 创建 `miot_storage.go` 文件 (预计 2小时)
- [ ] 实现文件读写 (预计 4小时)
- [ ] 实现异步操作 (预计 3小时)
- [ ] 实现用户配置管理 (预计 2小时)
- [ ] 创建 `miot_cert.go` 文件 (预计 1小时)
- [ ] 实现证书管理 (预计 4小时)
- [ ] 创建 `miot_manufacturer.go` 文件 (预计 1小时)
- [ ] 实现制造商信息缓存 (预计 2小时)
- [ ] 单元测试 (预计 4小时)
**总计**:23小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+194
View File
@@ -0,0 +1,194 @@
# 06 - common.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/common.py` (189行) |
| **Go 文件** | ❌ 缺失 |
| **状态** | ❌ 完全缺失 |
| **优先级** | 🔴 P0 |
| **预计工作量** | 4-6 小时 |
**说明**:此文件对应之前分析的 `miot_utils.py`,实际文件名为 `common.py`。
## Python 版本分析
### 核心功能
#### 工具函数
| 函数名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `gen_absolute_path` | 63 | 生成绝对路径 | ❌ 缺失 |
| `calc_group_id` | 68 | 计算组 ID(SHA1 哈希) | ❌ 缺失 |
| `load_json_file` | 74 | 加载 JSON 文件 | ❌ 缺失 |
| `load_yaml_file` | 80 | 加载 YAML 文件 | ❌ 缺失 |
| `randomize_int` | 86 | 随机化整数 | ❌ 缺失 |
| `randomize_float` | 91 | 随机化浮点数 | ❌ 缺失 |
| `slugify_name` | 96 | 生成 slug(名称) | ❌ 缺失 |
| `slugify_did` | 101 | 生成 slug(设备 ID) | ❌ 缺失 |
#### 类
##### MIoTMatcher
**位置**:第 106-124 行
**功能**:MQTT topic 匹配器(基于 `paho.mqtt.matcher`)
**Go 状态**:❌ 缺失
##### MIoTHttp
**位置**:第 126-189 行
**功能**:HTTP 请求工具类(同步和异步)
**核心方法**:
| 方法名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `get` | 129 | HTTP GET 请求(同步) | ❌ 缺失 |
| `get_json` | 143 | HTTP GET 请求并返回 JSON | ❌ 缺失 |
| `post` | 150 | HTTP POST 请求(同步) | ❌ 缺失 |
| `post_json` | 156 | HTTP POST 请求并返回 JSON | ❌ 缺失 |
| `get_async` | 163 | HTTP GET 请求(异步) | ❌ 缺失 |
| `get_json_async` | 173 | HTTP GET 请求并返回 JSON(异步) | ❌ 缺失 |
| `post_async` | 182 | HTTP POST 请求(异步) | ❌ 缺失 |
## Go 版本现状
### 缺失的功能
整个 `common.py` 模块在 Go 版本中完全缺失。
Go 版本中可能已经有部分功能:
- HTTP 请求 - 可能在 `http_client.go` 中实现
- JSON/YAML 加载 - 可能使用标准库
但是缺少统一的工具类。
## 移植建议
### 第一批任务(核心功能)
1. **创建 `common.go` 文件** (1小时)
- 定义工具函数
- 定义 `MIoTMatcher` 结构体(如果需要)
- 定义 `MIoTHttp` 结构体
2. **实现工具函数** (2小时)
- 实现 `GenAbsolutePath`
- 实现 `CalcGroupID`
- 实现 `LoadJSONFile`
- 实现 `LoadYAMLFile`
- 实现 `RandomizeInt` 和 `RandomizeFloat`
- 实现 `SlugifyName` 和 `SlugifyDID`
3. **实现 HTTP 工具类** (2小时)
- 实现 `MIoTHttp` 结构体
- 实现 GET 和 POST 方法
- 实现 JSON 支持
### 第二批任务(高级功能)
4. **实现 MQTT 匹配器** (1小时)
- 评估是否需要 `MIoTMatcher`
- 如果需要,实现 Go 版本
5. **优化和测试** (1小时)
- 单元测试
- 性能优化
## 技术难点
### 1. Slugify 功能
**问题**:Python 使用 `python-slugify` 库
**建议**:
- 使用 Go 的 `strings` 包手动实现
- 或使用第三方库 `github.com/gosimple/slug`
### 2. MQTT 匹配器
**问题**:Python 使用 `paho.mqtt.matcher`
**建议**:
- 评估是否需要在 Go 版本中实现
- 如果需要,可以使用 `github.com/eclipse/paho.mqtt.golang` 库
### 3. 异步 HTTP
**问题**:Python 使用 `asyncio`,Go 使用 goroutine
**建议**:
```go
type MIoTHttp struct{}
func (h *MIoTHttp) Get(url string, params map[string]string, headers map[string]string) (string, error) {
// 实现 GET 请求
}
func (h *MIoTHttp) GetAsync(url string, params map[string]string, headers map[string]string) <-chan HttpResponse {
ch := make(chan HttpResponse, 1)
go func() {
resp, err := h.Get(url, params, headers)
ch <- HttpResponse{Body: resp, Err: err}
}()
return ch
}
```
## 测试计划
### 单元测试
1. **工具函数测试**
- 测试路径生成
- 测试哈希计算
- 测试文件加载
- 测试随机化
- 测试 slugify
2. **HTTP 工具测试**
- 测试 GET 请求
- 测试 POST 请求
- 测试 JSON 解析
- 测试错误处理
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `encoding/json` | 强依赖 | JSON 处理 |
| `encoding/yaml` | 强依赖 | YAML 处理 |
| `net/http` | 强依赖 | HTTP 请求 |
| `github.com/gosimple/slug` | 弱依赖 | Slugify(可选) |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 创建基础结构 | 🔴 高 | 基础框架 |
| 实现工具函数 | 🔴 高 | 核心功能 |
| 实现 HTTP 工具 | 🔴 高 | 核心功能 |
| 实现 MQTT 匹配器 | 🟡 中 | 可选功能 |
| 优化和测试 | 🟡 中 | 质量保障 |
## 进度跟踪
- [x] 创建 `common.go` 文件 (预计 1小时) — 2026-06-28 完成
- [x] 实现工具函数 (预计 2小时) — 2026-06-28 完成
- [x] 实现 HTTP 工具类 (预计 2小时) — 已存在 `http_client.go`,跳过
- [x] 实现 MQTT 匹配器 (预计 1小时) — 已存在 `miot_matcher.go`,跳过
- [ ] 优化和测试 (预计 1小时)
**总计**:7小时 (已完成核心移植)
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+216
View File
@@ -0,0 +1,216 @@
# 07 - miot_error.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_error.py` (151行) |
| **Go 文件** | `go-miot/miot_error.go` |
| **状态** | ✅ 已完成 (仅缺测试) |
| **优先级** | 🔴 P0 |
| **预计工作量** | 2-3 小时 |
## Python 版本分析
### 核心类
#### MIoTErrorCode
**位置**:第 52-80 行
**功能**:错误码枚举
**错误码列表**:
| 错误码 | 名称 | 值 | 说明 |
|--------|------|-----|------|
| `CODE_UNKNOWN` | -10000 | 未知错误 |
| `CODE_UNAVAILABLE` | -10001 | 不可用 |
| `CODE_INVALID_PARAMS` | -10002 | 无效参数 |
| `CODE_RESOURCE_ERROR` | -10003 | 资源错误 |
| `CODE_INTERNAL_ERROR` | -10004 | 内部错误 |
| `CODE_UNAUTHORIZED_ACCESS` | -10005 | 未授权访问 |
| `CODE_TIMEOUT` | -10006 | 超时 |
| `CODE_OAUTH_UNAUTHORIZED` | -10020 | OAuth 未授权 |
| `CODE_HTTP_INVALID_ACCESS_TOKEN` | -10030 | HTTP 无效 access token |
| `CODE_MIPS_INVALID_RESULT` | -10040 | MIPS 无效结果 |
| `CODE_CERT_INVALID_CERT` | -10050 | 证书无效 |
| `CODE_CONFIG_INVALID_INPUT` | -10100 | 配置无效输入 |
| `CODE_CONFIG_INVALID_STATE` | -10101 | 配置无效状态 |
| `CODE_LAN_UNAVAILABLE` | -10120 | LAN 不可用 |
#### MIoTError
**位置**:第 82-98 行
**功能**:基础错误类
**核心方法**:
| 方法名 | 行号 | 功能 |
|--------|------|------|
| `__init__` | 87 | 初始化错误 |
| `to_str` | 94 | 转换为 JSON 字符串 |
| `to_dict` | 97 | 转换为字典 |
#### 子类错误
| 类名 | 行号 | 说明 |
|------|------|------|
| `MIoTOauthError` | 101 | OAuth 错误 |
| `MIoTHttpError` | 105 | HTTP 错误 |
| `MIoTMipsError` | 109 | MIPS 错误 |
| `MIoTDeviceError` | 113 | 设备错误 |
| `MIoTSpecError` | 117 | SPEC 错误 |
| `MIoTStorageError` | 121 | 存储错误 |
| `MIoTCertError` | 125 | 证书错误 |
| `MIoTClientError` | 129 | 客户端错误 |
| `MIoTEvError` | 133 | 事件错误 |
| `MipsServiceError` | 137 | MIPS 服务错误 |
| `MIoTConfigError` | 141 | 配置错误 |
| `MIoTOptionsError` | 145 | 选项错误 |
| `MIoTLanError` | 149 | LAN 错误 |
## Go 版本现状
### 缺失的功能
整个 `miot_error.py` 模块在 Go 版本中完全缺失。
Go 版本中可能需要实现:
1. **错误码定义** - 对应 `MIoTErrorCode`
2. **基础错误类** - 对应 `MIoTError`
3. **子类错误** - 对应各种专用错误类
## 移植建议
### 第一批任务(核心功能)
1. **创建 `miot_error.go` 文件** (1小时)
- 定义错误码常量
- 定义 `MIoTError` 结构体
- 实现 `Error()` 方法
2. **实现错误码** (1小时)
- 定义所有错误码常量
- 使用 `iota` 简化定义
3. **实现子类错误** (1小时)
- 定义各种专用错误类型
- 实现构造函数
### 第二批任务(辅助功能)
4. **实现错误转换** (1小时)
- 实现 `ToStr()` 方法
- 实现 `ToDict()` 方法
5. **单元测试** (1小时)
- 测试错误创建
- 测试错误转换
## 技术难点
### 1. 错误类型设计
**问题**:Go 的错误类型设计与 Python 不同
**建议**:
```go
type MIoTErrorCode int
const (
CodeUnknown MIoTErrorCode = -10000
CodeUnavailable MIoTErrorCode = -10001
// ...
)
type MIoTError struct {
Code MIoTErrorCode
Message string
}
func (e *MIoTError) Error() string {
return fmt.Sprintf("code=%d, message=%s", e.Code, e.Message)
}
func (e *MIoTError) ToDict() map[string]interface{} {
return map[string]interface{}{
"code": e.Code,
"message": e.Message,
}
}
```
### 2. 子类错误
**问题**:Go 没有继承,需要使用组合或类型别名
**建议**:
```go
type MIoTOauthError struct {
MIoTError
}
type MIoTHttpError struct {
MIoTError
}
// 或者使用函数构造函数
func NewMIoTOauthError(message string) *MIoTOauthError {
return &MIoTOauthError{
MIoTError: MIoTError{
Code: CodeOauthUnauthorized,
Message: message,
},
}
}
```
## 测试计划
### 单元测试
1. **错误创建测试**
- 测试基础错误
- 测试子类错误
2. **错误转换测试**
- 测试 `Error()` 方法
- 测试 `ToDict()` 方法
3. **错误处理测试**
- 测试错误类型判断
- 测试错误链
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| 无 | - | 独立模块 |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 创建基础结构 | 🔴 高 | 基础框架 |
| 实现错误码 | 🔴 高 | 核心功能 |
| 实现子类错误 | 🔴 高 | 核心功能 |
| 实现错误转换 | 🟡 中 | 辅助功能 |
| 单元测试 | 🟡 中 | 质量保障 |
## 进度跟踪
- [x] 创建 `miot_error.go` 文件 (2026-06-28)
- [x] 实现错误码 (2026-06-28)
- [x] 实现子类错误 (2026-06-28)
- [x] 实现错误转换 (ToDict) (2026-06-28)
- [ ] 单元测试 (预计 1小时)
**总计**:5小时 (已完成 4/5)
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+222
View File
@@ -0,0 +1,222 @@
# 08 - const.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/const.py` (161行) |
| **Go 文件** | ❌ 缺失 |
| **状态** | ❌ 完全缺失 |
| **优先级** | 🔴 P0 |
| **预计工作量** | 2-3 小时 |
**说明**:此文件对应之前分析的 `miot_constant.py`,实际文件名为 `const.py`。
## Python 版本分析
### 核心常量
#### 基础常量
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `DOMAIN` | 48 | `'xiaomi_home'` | 域名 |
| `DEFAULT_NAME` | 49 | `'Xiaomi Home'` | 默认名称 |
| `DEFAULT_NICK_NAME` | 51 | `'Xiaomi'` | 默认昵称 |
#### 超时和间隔
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `MIHOME_HTTP_API_TIMEOUT` | 53 | `30` | HTTP API 超时(秒) |
| `MIHOME_MQTT_KEEPALIVE` | 54 | `60` | MQTT 保持连接(秒) |
| `MIHOME_CERT_EXPIRE_MARGIN` | 56 | `3600*24*3` | 证书过期边际(3天) |
| `NETWORK_REFRESH_INTERVAL` | 58 | `30` | 网络刷新间隔(秒) |
#### OAuth 相关
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `OAUTH2_CLIENT_ID` | 60 | `'2882303761520251711'` | OAuth2 客户端 ID |
| `OAUTH2_AUTH_URL` | 61 | `'https://account.xiaomi.com/oauth2/authorize'` | OAuth2 授权 URL |
| `DEFAULT_OAUTH2_API_HOST` | 62 | `'ha.api.io.mi.com'` | 默认 OAuth2 API 主机 |
| `DEFAULT_CLOUD_BROKER_HOST` | 63 | `'ha.mqtt.io.mi.com'` | 默认云 Broker 主机 |
| `OAUTH_REDIRECT_URL` | 135 | `'http://homeassistant.local:8123'` | OAuth 重定向 URL |
#### 缓存时间
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `SPEC_STD_LIB_EFFECTIVE_TIME` | 66 | `3600*24*14` | SPEC 标准库有效期(14天) |
| `MANUFACTURER_EFFECTIVE_TIME` | 68 | `3600*24*14` | 制造商信息有效期(14天) |
#### 支持的平台
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `SUPPORTED_PLATFORMS` | 70-89 | 列表 | 支持的 Home Assistant 平台 |
| `UNSUPPORTED_MODELS` | 91-96 | 列表 | 不支持的设备模型 |
#### 云服务器
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `DEFAULT_CLOUD_SERVER` | 98 | `'cn'` | 默认云服务器 |
| `CLOUD_SERVERS` | 99-106 | 字典 | 云服务器列表 |
#### 语言
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `DEFAULT_INTEGRATION_LANGUAGE` | 110 | `'en'` | 默认集成语言 |
| `INTEGRATION_LANGUAGES` | 111-125 | 字典 | 集成语言列表 |
#### 其他
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `DEFAULT_COVER_DEAD_ZONE_WIDTH` | 127 | `0` | 默认 cover 死区宽度 |
| `MIN_COVER_DEAD_ZONE_WIDTH` | 128 | `0` | 最小 cover 死区宽度 |
| `MAX_COVER_DEAD_ZONE_WIDTH` | 129 | `5` | 最大 cover 死区宽度 |
| `DEFAULT_CTRL_MODE` | 131 | `'auto'` | 默认控制模式 |
#### CA 证书
| 常量名 | 行号 | 值 | 说明 |
|--------|------|-----|------|
| `MIHOME_CA_CERT_STR` | 137-157 | 字符串 | MIoT CA 证书(PEM 格式) |
| `MIHOME_CA_CERT_SHA256` | 159-160 | 字符串 | MIoT CA 证书 SHA256 哈希 |
## Go 版本现状
### 缺失的功能
整个 `const.py` 模块在 Go 版本中完全缺失。
Go 版本中可能需要实现:
1. **常量定义** - 对应 Python 的常量
2. **变量定义** - 对应 Python 的变量(如列表、字典)
## 移植建议
### 第一批任务(核心功能)
1. **创建 `const.go` 文件** (1小时)
- 定义基础常量
- 定义超时和间隔常量
2. **实现 OAuth 相关常量** (1小时)
- 定义 OAuth2 客户端 ID
- 定义 OAuth2 URL
- 定义重定向 URL
3. **实现云服务器和语言常量** (1小时)
- 定义云服务器列表
- 定义语言列表
4. **实现 CA 证书常量** (1小时)
- 定义 CA 证书字符串
- 定义 CA 证书哈希
### 第二批任务(辅助功能)
5. **实现支持的平台和模型** (1小时)
- 定义支持的平台列表
- 定义不支持的模型列表
6. **单元测试** (1小时)
- 测试常量值
- 测试变量初始化
## 技术难点
### 1. 常量 vs 变量
**问题**:Python 的"常量"实际上是变量,Go 有真正的常量
**建议**:
```go
// 真正的常量
const (
DOMAIN = "xiaomi_home"
DEFAULT_NAME = "Xiaomi Home"
MIHOME_HTTP_API_TIMEOUT = 30
)
// 变量(需要在 init() 中初始化)
var (
SUPPORTED_PLATFORMS = []string{
"binary_sensor",
"button",
// ...
}
CLOUD_SERVERS = map[string]string{
"cn": "中国大陆",
"de": "Europe",
// ...
}
)
```
### 2. CA 证书字符串
**问题**:Python 使用多行字符串,Go 需要使用反引号
**建议**:
```go
const MIHOME_CA_CERT_STR = `-----BEGIN CERTIFICATE-----
MIIBazCCAQ+gAwIBAgIEA/UKYDAMBggqhkjOPQQDAgUAMCIxEzARBgNVBAoTCk1p
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----`
```
## 测试计划
### 单元测试
1. **常量值测试**
- 测试基础常量
- 测试 OAuth 常量
2. **变量初始化测试**
- 测试列表变量
- 测试字典变量
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| 无 | - | 独立模块 |
## 移植优先级
| 任务 | 优先级 | 理由 |
|------|--------|------|
| 创建基础结构 | 🔴 高 | 基础框架 |
| 实现基础常量 | 🔴 高 | 核心功能 |
| 实现 OAuth 常量 | 🔴 高 | 核心功能 |
| 实现云服务器常量 | 🔴 高 | 核心功能 |
| 实现 CA 证书 | 🔴 高 | 核心功能 |
| 实现平台和模型 | 🟡 中 | 辅助功能 |
| 单元测试 | 🟡 中 | 质量保障 |
## 进度跟踪
- [ ] 创建 `const.go` 文件 (预计 1小时)
- [ ] 实现基础常量 (预计 1小时)
- [ ] 实现 OAuth 相关常量 (预计 1小时)
- [ ] 实现云服务器和语言常量 (预计 1小时)
- [ ] 实现 CA 证书常量 (预计 1小时)
- [ ] 实现支持的平台和模型 (预计 1小时)
- [ ] 单元测试 (预计 1小时)
**总计**:7小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+165
View File
@@ -0,0 +1,165 @@
# 09 - miot_spec.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_spec.py` (939行) |
| **Go 文件** | `spec_parser.go` |
| **状态** | ⚠️ 部分实现 |
| **优先级** | 🟡 P1 |
| **预计工作量** | 16-20 小时 |
## Python 版本核心类
### 数据结构类
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `MIoTSpecValueRange` | 65 | 数值范围(min/max/step) | ❌ 缺失 |
| `MIoTSpecValueListItem` | 101 | 值列表项 | ❌ 缺失 |
| `MIoTSpecValueList` | 145 | 值列表 | ❌ 缺失 |
### SPEC 基类
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `_SpecStdLib` | 209 | SPEC 标准库(多语言翻译) | ❌ 缺失 |
| `_MIoTSpecBase` | 436 | SPEC 基类 | ⚠️ 部分 |
| `MIoTSpecProperty` | 482 | SPEC 属性 | ⚠️ 部分 |
| `MIoTSpecEvent` | 644 | SPEC 事件 | ⚠️ 部分 |
| `MIoTSpecAction` | 672 | SPEC 动作 | ⚠️ 部分 |
| `MIoTSpecService` | 704 | SPEC 服务 | ⚠️ 部分 |
| `MIoTSpecInstance` | 731 | SPEC 实例(设备) | ⚠️ 部分 |
### 核心功能
| 功能 | 行号 | 说明 | Go 状态 |
|------|------|------|---------|
| SPEC 解析 | 754 | 从 JSON 加载 SPEC | ⚠️ 部分 |
| 标准库管理 | 296 | 从云端刷新标准库 | ❌ 缺失 |
| 多语言翻译 | 244-284 | 描述翻译 | ❌ 缺失 |
| 值格式化 | 599 | 值格式转换 | ⚠️ 部分 |
| 值精度处理 | 611 | 浮点数精度 | ❌ 缺失 |
## Go 版本现状
### 已实现的功能
- `SpecInstance` 结构体(对应 `MIoTSpecInstance`)
- `SpecService` 结构体(对应 `MIoTSpecService`)
- 基本的 SPEC 解析
### 缺失的功能
1. **值范围和处理**
- `MIoTSpecValueRange`
- `MIoTSpecValueList`
2. **标准库管理**
- 从云端下载标准库
- 多语言翻译
3. **属性处理**
- 表达式求值(`eval_expr`)
- 值精度处理(`value_precision`)
## 移植建议
### 第一批任务(核心数据结构)
1. **实现值范围类** (2小时)
- `MIoTSpecValueRange` → `SpecValueRange`
- `MIoTSpecValueList` → `SpecValueList`
2. **实现标准库管理** (4小时)
- `_SpecStdLib` → `SpecStdLib`
- 实现云端下载
- 实现多语言翻译
### 第二批任务(属性处理)
3. **增强属性处理** (3小时)
- 实现 `eval_expr`
- 实现 `value_precision`
- 实现 `value_format`
4. **实现序列化** (2小时)
- `dump()` 方法
- JSON 导出
### 第三批任务(优化和测试)
5. **优化性能** (2小时)
- 缓存翻译结果
- 优化 SPEC 解析
6. **单元测试** (3小时)
- 测试值范围
- 测试属性处理
- 测试序列化
## 技术难点
### 1. 表达式求值
**问题**:Python 使用 `eval()`,Go 需要其他方案
**建议**:
```go
// 方案1:不使用表达式(推荐)
// 在 Go 版本中不支持 expr,直接返回原值
// 方案2:使用表达式求值库
// 使用 github.com/expr-lang/expr
```
### 2. 多语言翻译
**问题**:需要管理多语言描述
**建议**:
```go
type SpecStdLib struct {
lang string
devices map[string]map[string]string
services map[string]map[string]string
// ...
}
func (s *SpecStdLib) DeviceTranslate(key string) string {
if translations, ok := s.devices[key]; ok {
if desc, ok := translations[s.lang]; ok {
return desc
}
// 回退到默认语言
return translations[defaultLang]
}
return ""
}
```
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_error.py` | 强依赖 | 错误定义 |
| `miot_storage.py` | 强依赖 | 标准库缓存 |
| `common.py` | 强依赖 | HTTP 请求 |
## 进度跟踪
- [ ] 实现值范围类 (预计 2小时)
- [ ] 实现标准库管理 (预计 4小时)
- [ ] 增强属性处理 (预计 3小时)
- [ ] 实现序列化 (预计 2小时)
- [ ] 优化性能 (预计 2小时)
- [ ] 单元测试 (预计 3小时)
**总计**:16小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+179
View File
@@ -0,0 +1,179 @@
# 10 - miot_mips.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_mips.py` (61399行) |
| **Go 文件** | `mips_client.go` |
| **状态** | ⚠️ 部分实现 |
| **优先级** | 🟡 P1 |
| **预计工作量** | 20-28 小时 |
## Python 版本核心类
### 消息处理
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `_MipsMessage` | 90 | MIPS 消息(打包/解包) | ⚠️ 部分 |
| `_MipsRequest` | 162 | MIPS 请求 | ❌ 缺失 |
| `_MipsBroadcast` | 171 | MIPS 广播 | ❌ 缺失 |
| `_MipsState` | 187 | MIPS 状态 | ❌ 缺失 |
### 设备状态
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `MIoTDeviceState` | 197 | 设备状态枚举 | ❌ 缺失 |
| `MipsDeviceState` | 205 | 设备状态数据 | ❌ 缺失 |
### 客户端
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `_MipsClient` | 217 | MIPS 客户端基类(ABC) | ⚠️ 部分 |
| `MIoTPahoMipsClient` | ~500 | 基于 Paho 的客户端 | ❌ 缺失 |
| `MIoTMipsClient` | ~800 | 主客户端类 | ⚠️ 部分 |
## Go 版本现状
### 已实现的功能
- `MipsClient` 结构体(对应 `_MipsClient`)
- 基本的 MQTT 连接
- 基本的发布/订阅
### 缺失的功能
1. **消息打包/解包**
- `_MipsMessage.pack()` 和 `unpack()`
2. **请求管理**
- 请求超时处理
- 回复回调
3. **广播管理**
- 广播订阅
- 广播处理
4. **状态管理**
- 连接状态监控
- 设备状态监控
5. **重连机制**
- 指数退避重连
- 重连间隔管理
## 移植建议
### 第一批任务(消息处理)
1. **实现消息打包/解包** (4小时)
- `MipsMessage.Pack()`
- `MipsMessage.Unpack()`
- 使用 `encoding/binary` 和 `bytes.Buffer`
2. **实现请求管理** (3小时)
- `MipsRequest` 结构体
- 请求超时处理
- 回复回调
### 第二批任务(广播和状态)
3. **实现广播管理** (3小时)
- `MipsBroadcast` 结构体
- 广播订阅/取消订阅
- 广播处理
4. **实现状态管理** (3小时)
- `MipsDeviceState` 结构体
- 连接状态监控
- 设备状态监控
### 第三批任务(客户端功能)
5. **实现重连机制** (3小时)
- 指数退避算法
- 重连定时器
6. **优化性能** (2小时)
- 并发安全
- 资源管理
7. **单元测试** (4小时)
- 测试消息处理
- 测试请求管理
- 测试重连机制
## 技术难点
### 1. MQTT 客户端
**问题**:Python 使用 `paho-mqtt`,Go 需要选择合适的库
**建议**:
```go
// 使用 github.com/eclipse/paho.mqtt.golang
import mqtt "github.com/eclipse/paho.mqtt.golang"
type MipsClient struct {
client mqtt.Client
// ...
}
```
### 2. 并发安全
**问题**:Python 使用 `threading.Lock`,Go 使用 `sync.Mutex`
**建议**:
```go
type MipsClient struct {
mu sync.RWMutex
subMap map[string]*MipsSubscription
// ...
}
```
### 3. 异步处理
**问题**:Python 使用 `asyncio`,Go 使用 goroutine 和 channel
**建议**:
```go
type MipsClient struct {
msgChan chan *MipsMessage
stopChan chan struct{}
}
func (c *MipsClient) Start() {
go c.messageLoop()
}
```
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_error.py` | 强依赖 | 错误定义 |
| `common.py` | 强依赖 | MQTT 匹配器 |
| `paho-mqtt` | 强依赖 | MQTT 客户端 |
## 进度跟踪
- [ ] 实现消息打包/解包 (预计 4小时)
- [ ] 实现请求管理 (预计 3小时)
- [ ] 实现广播管理 (预计 3小时)
- [ ] 实现状态管理 (预计 3小时)
- [ ] 实现重连机制 (预计 3小时)
- [ ] 优化性能 (预计 2小时)
- [ ] 单元测试 (预计 4小时)
**总计**:22小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+184
View File
@@ -0,0 +1,184 @@
# 12 - miot_lan.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_lan.py` (53,181字节) |
| **Go 文件** | ❌ 缺失 |
| **状态** | ❌ 完全缺失 |
| **优先级** | 🟢 P2 |
| **预计工作量** | 20-28 小时 |
## Python 版本核心类
### 设备管理
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `_MIoTLanDevice` | 131 | LAN 设备(加密通信) | ❌ 缺失 |
| `_MIoTLanDeviceState` | 123 | 设备状态枚举 | ❌ 缺失 |
### 数据类
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `_MIoTLanRequestData` | 115 | LAN 请求数据 | ❌ 缺失 |
| `_MIoTLanSubDeviceData` | 102 | 订阅设备数据 | ❌ 缺失 |
| `_MIoTLanBroadcastData` | 91 | 广播数据 | ❌ 缺失 |
### 主类
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `MIoTLan` | ~300 | LAN 管理主类 | ❌ 缺失 |
## Go 版本现状
整个 `miot_lan.py` 模块在 Go 版本中完全缺失。
### 缺失的核心功能
1. **设备管理**
- 设备发现和注册
- 设备状态监控(PING/DEAD)
- 保活机制
2. **加密通信**
- AES-128-CBC 加密
- Token 管理
- 消息加解密
3. **网络管理**
- UDP 通信
- 广播和单播
- 网络接口管理
4. **订阅管理**
- 设备订阅/取消订阅
- 广播注册/取消注册
- 设备状态订阅
## 移植建议
### 第一批任务(数据结构和加密)
1. **实现数据结构** (4小时)
- 数据类(RequestData, SubDeviceData, BroadcastData)
- 设备状态枚举
- LAN 设备结构体
2. **实现加密通信** (4小时)
- AES-128-CBC 加密
- Token 管理
- 消息加解密
### 第二批任务(设备管理)
3. **实现设备管理** (6小时)
- 设备发现和注册
- 设备状态监控
- 保活机制
4. **实现网络通信** (4小时)
- UDP 通信
- 广播和单播
- 网络接口管理
### 第三批任务(高级功能)
5. **实现订阅管理** (4小时)
- 设备订阅/取消订阅
- 广播注册/取消注册
6. **实现网络状态管理** (3小时)
- 网络状态监控
- 网络不稳定性检测
7. **单元测试** (4小时)
- 测试加密通信
- 测试设备发现
- 测试订阅管理
## 技术难点
### 1. AES 加密
**问题**:Python 使用 `cryptography` 库,Go 使用标准库
**建议**:
```go
import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
)
func NewAESCipher(token []byte) (cipher.Block, []byte, error) {
aesKey := md5Sum(token)
aesIV := md5Sum(append(aesKey[:], token...))
block, err := aes.NewCipher(aesKey[:])
return block, aesIV[:], err
}
```
### 2. UDP 通信
**问题**:需要实现 UDP 广播和单播
**建议**:
```go
import "net"
func (d *LanDevice) SendBroadcast(data []byte) error {
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.IPv4bcast,
Port: 54321,
})
// ...
}
```
### 3. 设备状态监控
**问题**:需要实现 PING 检测和设备状态管理
**建议**:
```go
type LanDeviceState int
const (
LanDeviceFresh LanDeviceState = iota
LanDevicePing1
LanDevicePing2
LanDevicePing3
LanDeviceDead
)
```
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_error.py` | 强依赖 | 错误定义 |
| `miot_network.py` | 强依赖 | 网络管理 |
| `miot_mdns.py` | 强依赖 | mDNS 发现 |
| `cryptography` | 强依赖 | 加密库 |
## 进度跟踪
- [ ] 实现数据结构 (预计 4小时)
- [ ] 实现加密通信 (预计 4小时)
- [ ] 实现设备管理 (预计 6小时)
- [ ] 实现网络通信 (预计 4小时)
- [ ] 实现订阅管理 (预计 4小时)
- [ ] 实现网络状态管理 (预计 3小时)
- [ ] 单元测试 (预计 4小时)
**总计**:29小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+174
View File
@@ -0,0 +1,174 @@
# 13 - miot_mdns.py 移植计划
## 概览
| 项目 | 内容 |
|------|------|
| **Python 文件** | `py-miot/miot_mdns.py` (286行) |
| **Go 文件** | ❌ 缺失 |
| **状态** | ❌ 完全缺失 |
| **优先级** | 🟢 P2 |
| **预计工作量** | 6-8 小时 |
## Python 版本核心类
### 数据类
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `MipsServiceState` | 76 | 服务状态枚举(ADDED/REMOVED/UPDATED) | ❌ 缺失 |
| `MipsServiceData` | 82 | 服务数据(profile 解析) | ❌ 缺失 |
### 主类
| 类名 | 行号 | 功能 | Go 状态 |
|------|------|------|---------|
| `MipsService` | 147 | mDNS 服务发现 | ❌ 缺失 |
### 核心方法
| 方法名 | 行号 | 功能 | Go 状态 |
|--------|------|------|---------|
| `init_async` | 167 | 初始化 Zeroconf 浏览器 | ❌ 缺失 |
| `deinit_async` | 176 | 清理资源 | ❌ 缺失 |
| `get_services` | 181 | 获取服务列表 | ❌ 缺失 |
| `sub_service_change` | 208 | 订阅服务变化 | ❌ 缺失 |
| `unsub_service_change` | 216 | 取消订阅 | ❌ 缺失 |
| `__on_service_state_change` | 223 | 状态变化回调 | ❌ 缺失 |
| `__request_service_info_async` | 243 | 请求服务信息 | ❌ 缺失 |
## Go 版本现状
整个 `miot_mdns.py` 模块在 Go 版本中完全缺失。
### 缺失的核心功能
1. **mDNS 服务发现**
- 基于 Zeroconf/bonjour 协议
- 发现 MIoT 中央 hub 网关
2. **服务数据解析**
- 解析 mDNS profile 数据
- 提取设备 ID、组 ID、角色等信息
3. **服务状态管理**
- 服务添加/更新/删除
- 订阅和通知机制
## 移植建议
### 第一批任务(数据解析)
1. **实现服务数据解析** (2小时)
- `MipsServiceData` → `MipsServiceData`
- Profile 解析(Base64 解码)
- 提取 did、group_id、role、suite_mqtt
2. **实现服务状态管理** (1小时)
- `MipsServiceState` → `MipsServiceState` 枚举
- 状态变化通知
### 第二批任务(服务发现)
3. **实现 mDNS 客户端** (2小时)
- 使用 Go 的 mDNS 库(如 `github.com/hashicorp/mdns`)
- 实现服务发现和监听
4. **实现订阅管理** (1小时)
- `sub_service_change` → `SubscribeServiceChange`
- `unsub_service_change` → `UnsubscribeServiceChange`
### 第三批任务(测试)
5. **单元测试** (1小时)
- 测试服务数据解析
- 测试服务发现(需要网络环境)
## 技术难点
### 1. mDNS 库选择
**问题**:Python 使用 `python-zeroconf`,Go 需要选择对应的库
**建议**:
```go
// 使用 github.com/hashicorp/mdns
import "github.com/hashicorp/mdns"
type MipsService struct {
server *mdns.Server
services map[string]*MipsServiceData
}
func (s *MipsService) Init() error {
// 创建 mDNS 浏览器
entriesCh := make(chan *mdns.ServiceEntry, 32)
go func() {
for entry := range entriesCh {
s.handleServiceEntry(entry)
}
}()
return mdns.Lookup("_miot-central._tcp.local.", entriesCh)
}
```
### 2. Profile 解析
**问题**:需要解析二进制 profile 数据
**建议**:
```go
import "encoding/binary"
type MipsServiceData struct {
Name string
Addresses []string
Port int
Did string
GroupID string
Role int
SuiteMQTT bool
}
func ParseProfile(profileB64 string) (*MipsServiceData, error) {
profileBin, err := base64.StdEncoding.DecodeString(profileB64)
if err != nil {
return nil, err
}
// 解析 did (1-8 bytes, big-endian)
did := binary.BigEndian.Uint64(profileBin[1:9])
// 解析 group_id (9-16 bytes, little-endian)
groupID := hex.EncodeToString(reverseBytes(profileBin[9:17]))
// 解析 role (byte 20, upper 4 bits)
role := int(profileBin[20] >> 4)
// 解析 suite_mqtt (byte 22, bit 1)
suiteMQTT := ((profileBin[22] >> 1) & 0x01) == 0x01
return &MipsServiceData{...}, nil
}
```
## 依赖关系
| 依赖文件 | 关系 | 说明 |
|---------|------|------|
| `miot_error.py` | 强依赖 | 错误定义 |
| `github.com/hashicorp/mdns` | 强依赖 | mDNS 库 |
| `net` | 强依赖 | 网络操作 |
## 进度跟踪
- [ ] 实现服务数据解析 (预计 2小时)
- [ ] 实现服务状态管理 (预计 1小时)
- [ ] 实现 mDNS 客户端 (预计 2小时)
- [ ] 实现订阅管理 (预计 1小时)
- [ ] 单元测试 (预计 1小时)
**总计**:7小时
---
**创建时间**:2026-06-28
**最后更新**:2026-06-28
**负责人**:待定
+56
View File
@@ -0,0 +1,56 @@
# R2-01 — spec_parser.go: 属性值处理
## 缺失方法
### MIoTSpecProperty.eval_expr — 表达式求值
```python
def eval_expr(self, src_value: Any) -> Any:
if not self.expr:
return src_value
try:
return eval(self.expr, {'src_value': src_value})
except Exception as err:
return src_value
```
**Go 实现**:不推荐 `eval`,使用简单的数值表达式库或手动解析常见模式。若 `expr` 字段为空则返回原值。
### MIoTSpecProperty.value_format — 值格式转换
```python
def value_format(self, value: Any) -> Any:
if value is None: return None
if isinstance(value, str):
if self.format_ == int: value = int(float(value))
elif self.format_ == float: value = float(value)
if self.format_ == bool:
return bool(value in [True, 1, 'True', 'true', '1'])
return value
```
**Go 实现**:根据 `Format` 字段将字符串转为对应类型。
### MIoTSpecProperty.value_precision — 值精度处理
```python
def value_precision(self, value: Any) -> Any:
if value is None: return None
if self.format_ == float:
return round(value, self.precision)
if self.format_ == int:
if self.value_range is None: return int(round(value))
return int(round(value / self.value_range.step) * self.value_range.step)
return value
```
**Go 实现**:使用 `math.Round` 或自定义 round。int 类型需要按 step 对齐。
## 目标文件
`D:\miot\go-miot\spec_parser.go`
在 `MIoTSpecProperty` 结构体上添加 3 个方法:
- `func (p *MIoTSpecProperty) EvalExpr(srcValue interface{}) interface{}`
- `func (p *MIoTSpecProperty) ValueFormat(value interface{}) interface{}`
- `func (p *MIoTSpecProperty) ValuePrecision(value interface{}) interface{}`
+44
View File
@@ -0,0 +1,44 @@
# R2-02 — spec_parser.go: ValueList 查询方法
## 缺失方法
在 `MIoTSpecValueList` 上添加 5 个查询方法:
### Names / Values / Descriptions
```python
@property
def names(self) -> list[str]:
return [item.name for item in self.items]
@property
def values(self) -> list[Any]:
return [item.value for item in self.items]
@property
def descriptions(self) -> list[str]:
return [item.description for item in self.items]
```
### 双向查找
```python
def get_value_by_description(self, description: str) -> Any:
for item in self.items:
if item.description == description:
return item.value
return None
def get_description_by_value(self, value: Any) -> Optional[str]:
for item in self.items:
if item.value == value:
return item.description
return None
```
## 目标文件
`D:\miot\go-miot\spec_parser.go`
在 `MIoTSpecValueList` 上添加:
- `func (vl *MIoTSpecValueList) Names() []string`
- `func (vl *MIoTSpecValueList) Values() []interface{}`
- `func (vl *MIoTSpecValueList) Descriptions() []string`
- `func (vl *MIoTSpecValueList) GetValueByDescription(desc string) interface{}`
- `func (vl *MIoTSpecValueList) GetDescriptionByValue(value interface{}) string`
+30
View File
@@ -0,0 +1,30 @@
# R2-03 — spec_parser.go: 属性访问器
## 缺失方法
`MIoTSpecProperty` 缺少 `writable / readable / notifiable` 三个布尔访问器。
Python 中通过 `access` 属性 setter 自动设置:
```python
@access.setter
def access(self, value: list) -> None:
self._writable = 'write' in value
self._readable = 'read' in value
self._notifiable = 'notify' in value
```
## 目标文件
`D:\miot\go-miot\spec_parser.go`
添加:
```go
func (p *MIoTSpecProperty) Writable() bool {
for _, a := range p.Access {
if a == "write" { return true }
}
return false
}
func (p *MIoTSpecProperty) Readable() bool { ... }
func (p *MIoTSpecProperty) Notifiable() bool { ... }
```
@@ -0,0 +1,22 @@
# R2-04 — miot_client: sub_device_state / unsub_device_state
## 缺失方法
Python `MIoTClient` 提供设备状态订阅:
```python
def sub_device_state(self, did: str, handler: Callable, handler_ctx: Any = None) -> bool
def unsub_device_state(self, did: str) -> bool
```
功能:订阅指定 did 的设备在线/离线状态变化通知。
## 目标文件
`D:\miot\go-miot\miot_client.go` 或 `miot_client_sub.go`
添加:
```go
func (c *MIoTClient) SubDeviceState(did string, handler func(string, MIoTDeviceState, interface{})) error
func (c *MIoTClient) UnsubDeviceState(did string) error
```
@@ -0,0 +1,27 @@
# R2-05 — miot_cloud.go: set_redirect_url
## 缺失方法
Python `MIoTOauthClient.set_redirect_url`:
```python
def set_redirect_url(self, redirect_url: str) -> None:
if not isinstance(redirect_url, str) or redirect_url.strip() == '':
raise MIoTOauthError('invalid redirect_url')
self._redirect_url = redirect_url
```
## 目标文件
`D:\miot\go-miot\miot_cloud.go`
在 `MIoTOauthClient` 上添加:
```go
func (c *MIoTOauthClient) SetRedirectURL(redirectURL string) error {
if strings.TrimSpace(redirectURL) == "" {
return NewMIoTOauthError("invalid redirect_url")
}
c.redirectURL = redirectURL
return nil
}
```
+21
View File
@@ -0,0 +1,21 @@
# R2-06 — miot_client: 配置属性
## 缺失结构体字段
Python `MIoTClient` 的属性:
| Python 属性 | 类型 | Go 字段建议 |
|------------|------|------------|
| `action_debug` | bool | `ActionDebug bool` |
| `hide_non_standard_entities` | bool | `HideNonStandardEntities bool` |
| `display_display_binary_text` | bool | `DisplayBinaryText bool` |
| `display_display_binary_bool` | bool | `DisplayBinaryBool bool` |
| `cover_dead_zone_width` | int | `CoverDeadZoneWidth int` |
| `display_devices_changed_notify` | []string | `DisplayDevicesChangedNotify []string` |
| `persistent_notify` | func | `PersistentNotify func(string, string, string)` |
## 目标文件
`D:\miot\go-miot\miot_client.go`
在 `MIoTClient` 结构体中添加对应字段。
@@ -0,0 +1,29 @@
# R2-07 — miot_client: auth/cert 定时刷新
## 缺失方法
Python 有两个定时刷新方法:
```python
def __request_refresh_auth_info(self, delay_sec: int) -> None:
"""定时刷新 OAuth token"""
def __request_refresh_user_cert(self, delay_sec: int) -> None:
"""定时刷新用户证书"""
```
## 目标文件
`D:\miot\go-miot\miot_client.go`
添加两个定时器方法,使用 `time.AfterFunc` 延迟执行 Token 和证书刷新。
### R2-08 — miot_client: 通知方法
三个通知方法:
```python
__show_client_error_notify(title, message)
__show_devices_changed_notify()
__show_central_state_changed_notify(connected)
```
在 `MIoTClient` 上添加对应方法,通过 `persistent_notify` 回调实现通知。
+15
View File
@@ -0,0 +1,15 @@
# R2-08 — miot_client: 通知方法
## 缺失方法
```python
__show_client_error_notify(title, message) — 显示客户端错误通知
__show_devices_changed_notify() — 显示设备变更通知
__show_central_state_changed_notify(connected: bool) — 显示网关连接状态
```
## 目标文件
`D:\miot\go-miot\miot_client.go`
通过 `PersistentNotify` 回调字段实现通知。
+17
View File
@@ -0,0 +1,17 @@
# R2-09 — miot_cloud.go: 单属性获取
## 缺失方法
Python `MIoTHttpClient.get_prop_async(did, siid, piid)`:
Go 版本只有批量 `GetProps(params []PropParam)`,缺少单个属性的便捷方法。
## 目标文件
`D:\miot\go-miot\miot_cloud.go`
```go
func (c *MIoTHttpClient) GetProp(did string, siid, piid int) (map[string]interface{}, error) {
return c.GetProps([]PropParam{{Did: did, Siid: siid, Piid: piid}})
}
```
+75
View File
@@ -0,0 +1,75 @@
# R2-10 — miot_storage.go: CSR 生成
## 缺失方法
Python `MIoTCert.gen_user_csr()`:
```python
def gen_user_csr(self) -> str:
"""使用 Ed25519 私钥生成 CSR"""
```
## 目标文件
`D:\miot\go-miot\miot_storage.go`
使用 `crypto/ed25519` + `crypto/x509.CreateCertificateRequest` 生成 CSR。
因依赖 Ed25519 密钥对,需先确保 LoadUserKey/SaveUserKey 已实现。
# R2-11 — miot_matcher.go: 匹配器方法
## 缺失方法
```python
def iter_all_nodes(self) -> Any: # 遍历所有节点
def get(self, topic: str) -> Optional[Any]: # 按 topic 获取
```
## 目标文件
`D:\miot\go-miot\miot_matcher.go`
在 `MIoTMatcher` 上添加 `IterAllNodes()` iterator 和 `Get(topic string)` 方法。
# R2-12 — const.go: CtrlMode.load
## 缺失方法
```python
@staticmethod
def load(mode: str) -> 'CtrlMode':
"""从字符串解析控制模式"""
```
## 目标文件
`D:\miot\go-miot\const.go`
```go
func ParseCtrlMode(s string) (CtrlMode, error) {
switch strings.ToLower(s) {
case "cloud": return CtrlModeCloud, nil
case "gateway": return CtrlModeGateway, nil
case "lan": return CtrlModeLAN, nil
default: return 0, fmt.Errorf("unknown ctrl mode: %s", s)
}
}
```
# R2-13 — 资源: lan/profile_models.yaml
## 缺失文件
复制 `D:\miot\py-miot\lan\profile_models.yaml` → `D:\miot\go-miot\lan\profile_models.yaml`
miot_lan.go 可能引用此文件用于设备 profile 映射。
# R2-14 — 资源: specs/ 目录
## 缺失文件
复制 `D:\miot\py-miot\specs\` → `D:\miot\go-miot\specs\`
包含 6 个文件:bool_trans.yaml、multi_lang.json、spec_add.json、spec_filter.yaml、spec_modify.yaml、specv2entity.py。
spec_parser.go 可能引用这些文件用于 SPEC 扩展配置。
+106
View File
@@ -0,0 +1,106 @@
# RefreshDeviceAllProps 方案
## 现状
| 版本 | 单个入队 | 批量执行 | 全量刷新 |
|------|---------|---------|---------|
| Python | `request_refresh_prop(did,siid,piid)` | `__refresh_props_handler` 200ms 聚合 150/批 | `MIoTDevice.__refresh_props_value()` |
| Go | `RequestRefreshProp(did,siid,piid)` | `refreshPropsHandler` 200ms 聚合 150/批 | ❌ 缺失 |
## 方案
### 在 `miot_client_prop.go` 新增:
```go
// RefreshDeviceAllProps 刷新指定设备的所有可读属性
// 遍历 device.ServiceList → service.Properties → RequestRefreshProp
func (c *MIoTClient) RefreshDeviceAllProps(did string) error {
// 1. 查找设备
c.deviceListMu.RLock()
info, exists := c.deviceListCache[did]
c.deviceListMu.RUnlock()
if !exists {
return fmt.Errorf("device %s not found", did)
}
// 2. 获取 SPEC(需要 MIoTDevice 或 MIoTSpecParser)
device := c.getOrCreateDevice(did, info)
if device == nil {
return fmt.Errorf("failed to create device for %s", did)
}
// 3. 遍历所有 service → property,入队可读属性
for _, svc := range device.ServiceList() {
for _, prop := range svc.Properties {
if !prop.Readable() {
continue
}
c.RequestRefreshProp(did, prop.SIID, prop.PIID)
}
}
return nil
}
```
### 前置依赖
需要 `MIoTClient` 能按 did 获取/创建 `MIoTDevice` 实例。可在 `miot_client.go` 或 `miot_client_device.go` 中新增内部方法:
```go
// getOrCreateDevice 从缓存获取或创建 MIoTDevice
func (c *MIoTClient) getOrCreateDevice(did string, info map[string]interface{}) *MIoTDevice {
// 尝试从已有列表读取
if dev, ok := c.devices[did]; ok {
return dev
}
// 创建新实例(需要 SPEC 解析器)
if c.specParser == nil {
return nil
}
urn, _ := info["urn"].(string)
model, _ := info["model"].(string)
spec, err := c.specParser.Parse(urn, model)
if err != nil {
return nil
}
dev := NewMIoTDevice(c, info, spec)
c.devices[did] = dev
return dev
}
```
### 需要在 `MIoTClient` 结构体新增字段
```go
// miot_client.go
type MIoTClient struct {
// ...
specParser *MIoTSpecParser // SPEC 解析器
devices map[string]*MIoTDevice // did → 设备实例缓存
}
```
### Setter
```go
func (c *MIoTClient) SetSpecParser(p *MIoTSpecParser) {
c.specParser = p
}
```
## 影响范围
| 文件 | 改动 |
|------|------|
| `miot_client.go` | +2 字段 (`specParser`, `devices`) + 1 setter |
| `miot_client_prop.go` | +1 方法 `RefreshDeviceAllProps` |
| `miot_client_device.go` | +1 方法 `getOrCreateDevice` |
## 验证
```go
// 用法示例
client.RefreshDevices() // 获取设备列表
client.RefreshDeviceAllProps("did_xxx") // 一次刷新该设备所有属性
// 200ms 后属性到达 → OnPropMsg → 分发给订阅者
```