feat: add Go API library
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
# mijia-go-api
|
||||
|
||||
`mijia-go-api` 是一个纯 Go 米家 API 库,支持二维码登录与 token 刷新、家庭/设备/场景/耗材查询、属性读写、action 执行、统计查询,以及基于 MIoT 设备描述的高级 `Device` 操作。
|
||||
|
||||
本项目只提供 Go 库,不提供 CLI、MCP、skills 或 HAR decrypt 功能。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
go get git.misaka.ren/m1saka/mijia-go-api
|
||||
```
|
||||
|
||||
## 登录
|
||||
|
||||
`NewClient` 的认证路径传空字符串时,默认使用 `~/.config/mijia-api/auth.json`。`Login` 会优先尝试刷新已有 token;需要重新登录时,会在终端输出二维码供米家 App 扫描。
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
mijia "git.misaka.ren/m1saka/mijia-go-api"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client, err := mijia.NewClient("")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := client.Login(context.Background()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
auth := client.AuthData()
|
||||
log.Printf("已登录 userId=%s", auth.UserID)
|
||||
}
|
||||
```
|
||||
|
||||
`auth.json` 包含 `serviceToken`、`passToken`、`ssecurity` 等敏感认证数据。库写入该文件时使用 `0600` 权限;请保持此权限,并且不要将该文件提交到版本库。
|
||||
|
||||
## 底层 API
|
||||
|
||||
以下示例展示设备、属性和 action 的直接调用。`GetDevices` 的 `homeID` 传空字符串时查询所有家庭。
|
||||
|
||||
```go
|
||||
devices, err := client.GetDevices(ctx, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
properties, err := client.GetProperties(ctx, []mijia.PropertyRequest{
|
||||
{DID: devices[0].DID, SIID: 2, PIID: 1},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.SetProperties(ctx, []mijia.PropertySetRequest{
|
||||
{DID: devices[0].DID, SIID: 2, PIID: 1, Value: true},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.RunActions(ctx, []mijia.ActionRequest{
|
||||
{DID: devices[0].DID, SIID: 2, AIID: 1},
|
||||
})
|
||||
```
|
||||
|
||||
家庭、场景、耗材和统计分别使用 `GetHomes`、`GetScenes`、`RunScene`、`GetConsumables` 和 `GetStatistics`。
|
||||
|
||||
## 高级 Device
|
||||
|
||||
`NewDevice` 可通过 `DeviceSelector.DID` 或 `DeviceSelector.Name` 选择设备;名称匹配到多个设备时会返回 `MultipleDevicesFoundError`。设备描述默认缓存到认证文件所在目录,每次成功的 `Get`、`Set`、`RunAction` 后默认等待 `500ms`。
|
||||
|
||||
```go
|
||||
device, err := mijia.NewDevice(ctx, client, mijia.DeviceSelector{DID: "设备 DID"})
|
||||
// 也可以按名称选择:mijia.DeviceSelector{Name: "客厅灯"}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value, err := device.Get(ctx, "on")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := device.Set(ctx, "on", true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = device.RunAction(ctx, "toggle", nil)
|
||||
_ = value
|
||||
```
|
||||
|
||||
可通过实际导出的 `DeviceOption` 调整行为:
|
||||
|
||||
```go
|
||||
device, err := mijia.NewDevice(
|
||||
ctx,
|
||||
client,
|
||||
mijia.DeviceSelector{Name: "客厅灯"},
|
||||
mijia.WithDeviceDelay(0),
|
||||
mijia.WithDeviceCacheDir("./miot-cache"),
|
||||
mijia.WithDeviceHTTPClient(http.DefaultClient),
|
||||
)
|
||||
```
|
||||
|
||||
## 超时与错误
|
||||
|
||||
所有网络和设备操作都接收 `context.Context`,建议设置超时:
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
devices, err := client.GetDevices(ctx, "")
|
||||
```
|
||||
|
||||
API 错误和高级设备错误可使用 `errors.As` 判断:
|
||||
|
||||
```go
|
||||
var apiErr *mijia.APIError
|
||||
var deviceErr *mijia.DeviceGetError
|
||||
|
||||
switch {
|
||||
case errors.As(err, &apiErr):
|
||||
log.Printf("API 错误: code=%d message=%s", apiErr.Code, apiErr.Message)
|
||||
case errors.As(err, &deviceErr):
|
||||
log.Printf("设备读取错误: device=%s property=%s code=%d", deviceErr.DeviceName, deviceErr.Name, deviceErr.Code)
|
||||
}
|
||||
```
|
||||
|
||||
写属性和执行 action 时,对应错误类型为 `DeviceSetError` 和 `DeviceActionError`;设备选择还可能返回 `DeviceNotFoundError` 或 `MultipleDevicesFoundError`。
|
||||
Reference in New Issue
Block a user