Documentation
¶
Overview ¶
Package miio speaks the local protocol of Xiaomi Mi Home Wi-Fi devices: miIO packets on UDP port 54321 with the token-derived encryption (Client, Discover), the legacy JSON-RPC methods, the MIoT property and action requests (GetProperties, SetProperties, DoAction) with the models' MIoT specifications (HTTPSpecs, or SpecMirror for sites without internet, with their translations) mapped to names (Model), discovery by mDNS through the application's browser (DiscoverMDNS), helpers for vacuums, lights, plugs and air purifiers (Vacuum, Light, Plug, Purifier; the vacuum also with the Roborock consumables, history, schedule and settings), Wi-Fi setup (ConfigureWiFi), gateway sub-devices (Gateway), firmware update (Update), device pushes (PushServer), and the Mi account client that lists an account's devices with their tokens, completes its verification steps and controls devices through the account (Cloud).
Xiaomi does not document the local protocol or the account API; this package follows public descriptions (see PROVENANCE.md). The module github.com/cB-Sigma/miio-sim simulates devices, gateways, the account and the specification service for tests.
Example ¶
List the account's devices with their tokens, then switch a plug on its LAN. It needs a Mi account and a device, so it is not run; github.com/cB-Sigma/miio-sim runs the same steps against a simulated account and plug.
package main
import (
"context"
"encoding/hex"
"fmt"
"time"
"github.com/cB-Sigma/miio"
)
func main() {
ctx := context.Background()
cloud := &miio.Cloud{Username: "user@example.invalid", Password: "secret"}
devs, err := cloud.Devices(ctx, []string{"i2"}) // India; miio.Regions lists all
if err != nil || len(devs) == 0 {
fmt.Println(devs, err)
return
}
tok, _ := hex.DecodeString(devs[0].Token)
c := &miio.Client{Addr: devs[0].LocalIP + ":54321", Token: tok, Timeout: 3 * time.Second}
_, err = c.Call(ctx, "set_power", []any{"on"})
fmt.Println(devs[0].Model, err)
}
Output:
Index ¶
- Constants
- Variables
- func CheckAction(raw json.RawMessage) error
- func ConfigureWiFi(ctx context.Context, c *Client, ssid, password string, uid int64, ...) error
- func Decrypt(token, ct []byte) ([]byte, error)
- func DefaultAPIBase(region string) string
- func Discover(ctx context.Context, bcast string, wait time.Duration) (map[uint32]string, error)
- func DoAction(ctx context.Context, c *Client, did string, siid, aiid int, in []any) error
- func EncSignature(method, path string, params [][2]string, signedNonce string) string
- func Encrypt(token, plain []byte) []byte
- func GetProp(ctx context.Context, c *Client, keys []string, max int) ([]any, error)
- func Hello() []byte
- func Keys(token []byte) (key, iv []byte)
- func Packet(token []byte, deviceID, stamp uint32, plain []byte) []byte
- func ParseMDNSInstance(name string) (model string, did uint32, ok bool)
- func RC4Decrypt(signedNonce, v string) ([]byte, error)
- func RC4Encrypt(signedNonce, v string) string
- func SignedNonce(ssecurity, nonce string) string
- func SubDeviceModel(typeID int) string
- func SupportsMIoT(ctx context.Context, c *Client) (bool, error)
- func TextKey(siid, piid, aiid, value int) string
- func TokenEnc(token []byte) string
- func URNName(urn string) (string, bool)
- func Update(ctx context.Context, c *Client, url, md5Hex string) error
- func UpdateProgress(ctx context.Context, c *Client) (int, error)
- func UpdateState(ctx context.Context, c *Client) (string, error)
- func WaitUpdate(ctx context.Context, c *Client, interval time.Duration, ...) error
- type Action
- type BrowseFunc
- type Browser
- type CarpetMode
- type CleanRecord
- type CleanSummary
- type Client
- type Cloud
- func (c *Cloud) Captcha(ctx context.Context) ([]byte, error)
- func (c *Cloud) CloudCall(ctx context.Context, region, did, method string, params any) (json.RawMessage, error)
- func (c *Cloud) CloudDoAction(ctx context.Context, region, did string, siid, aiid int, in []any) error
- func (c *Cloud) CloudGetProperties(ctx context.Context, region string, refs []PropRef) ([]PropResult, error)
- func (c *Cloud) CloudSetProperties(ctx context.Context, region string, refs []PropRef) ([]PropResult, error)
- func (c *Cloud) Devices(ctx context.Context, regions []string) ([]CloudDevice, error)
- func (c *Cloud) Login(ctx context.Context) error
- func (c *Cloud) SendCode(ctx context.Context, by string) error
- func (c *Cloud) VerifyCode(ctx context.Context, by, code string) error
- type CloudDevice
- type Consumable
- type Consumables
- type DND
- type DeviceError
- type EventInfo
- type Family
- type Gateway
- func (g *Gateway) RemoveSubDevice(ctx context.Context, sid string) error
- func (g *Gateway) SetSubProp(ctx context.Context, sid, name string, v any) error
- func (g *Gateway) SubBattery(ctx context.Context, sid string) (int, error)
- func (g *Gateway) SubDevices(ctx context.Context) ([]SubDevice, error)
- func (g *Gateway) SubProp(ctx context.Context, sid, name string) (any, error)
- func (g *Gateway) SubProps(ctx context.Context, sid string, names ...string) ([]any, error)
- type HTTPSpecs
- func (s *HTTPSpecs) Index(ctx context.Context) ([]SpecInstance, error)
- func (s *HTTPSpecs) RawIndex(ctx context.Context) ([]byte, error)
- func (s *HTTPSpecs) RawInstance(ctx context.Context, urn string) ([]byte, error)
- func (s *HTTPSpecs) RawTranslations(ctx context.Context, urn string) ([]byte, error)
- func (s *HTTPSpecs) Spec(ctx context.Context, model string) (*Spec, error)
- func (s *HTTPSpecs) Translations(ctx context.Context, urn string) (Translations, error)
- type Header
- type Light
- func (l *Light) Off(ctx context.Context) error
- func (l *Light) On(ctx context.Context) error
- func (l *Light) SetBrightness(ctx context.Context, pct int) error
- func (l *Light) SetColor(ctx context.Context, rgb int) error
- func (l *Light) SetColorTemperature(ctx context.Context, kelvin int) error
- func (l *Light) SetColorTemperatureScale(ctx context.Context, v int) error
- func (l *Light) Status(ctx context.Context) (LightStatus, error)
- type LightStatus
- type MDNSDevice
- type MDNSEntry
- type MappedAction
- type MappedProperty
- type Model
- func (m *Model) Action(name string) (MappedAction, error)
- func (m *Model) Actions() []MappedAction
- func (m *Model) Do(ctx context.Context, c *Client, did, name string, in ...any) error
- func (m *Model) Get(ctx context.Context, c *Client, did string, names ...string) (map[string]any, error)
- func (m *Model) Has(name string) bool
- func (m *Model) Properties() []MappedProperty
- func (m *Model) Property(name string) (MappedProperty, error)
- func (m *Model) Set(ctx context.Context, c *Client, did, name string, v any) error
- func (m *Model) SetMany(ctx context.Context, c *Client, did string, vals map[string]any) error
- type Plug
- type PlugStatus
- type PropError
- type PropRef
- type PropResult
- type Property
- type Purifier
- func (p *Purifier) Off(ctx context.Context) error
- func (p *Purifier) On(ctx context.Context) error
- func (p *Purifier) SetFanLevel(ctx context.Context, level int) error
- func (p *Purifier) SetMode(ctx context.Context, mode string) error
- func (p *Purifier) Status(ctx context.Context) (PurifierStatus, error)
- type PurifierStatus
- type Push
- type PushServer
- func (s *PushServer) Close() error
- func (s *PushServer) LocalAddr() net.Addr
- func (s *PushServer) Register(c *Client, handler func(Push)) error
- func (s *PushServer) Start() error
- func (s *PushServer) Subscribe(ctx context.Context, c *Client, ev EventInfo) (string, error)
- func (s *PushServer) Subscriptions(c *Client) []string
- func (s *PushServer) Unsubscribe(ctx context.Context, c *Client, id string) error
- type Service
- type Spec
- type SpecInstance
- type SpecMirror
- func (m *SpecMirror) Add(model string, version int, raw []byte) error
- func (m *SpecMirror) AddTranslations(urn string, raw []byte) error
- func (m *SpecMirror) Fill(ctx context.Context, models ...string) error
- func (m *SpecMirror) FillAll(ctx context.Context, workers int) error
- func (m *SpecMirror) FillTranslations(ctx context.Context, models ...string) error
- func (m *SpecMirror) Handler() http.Handler
- func (m *SpecMirror) Models() []string
- func (m *SpecMirror) RawInstance(ctx context.Context, urn string) ([]byte, error)
- func (m *SpecMirror) RawTranslations(ctx context.Context, urn string) ([]byte, error)
- func (m *SpecMirror) Spec(ctx context.Context, model string) (*Spec, error)
- func (m *SpecMirror) Stored(model string) bool
- func (m *SpecMirror) Translations(ctx context.Context, urn string) (Translations, error)
- func (m *SpecMirror) URN(ctx context.Context, model string) (string, error)
- type SpecSource
- type SubDevice
- type Translations
- type Vacuum
- func (v *Vacuum) AddTimer(ctx context.Context, id, cron string) (string, error)
- func (v *Vacuum) CarpetMode(ctx context.Context) (CarpetMode, error)
- func (v *Vacuum) CleanRecord(ctx context.Context, id int64) (CleanRecord, error)
- func (v *Vacuum) CleanSummary(ctx context.Context) (CleanSummary, error)
- func (v *Vacuum) Consumables(ctx context.Context) (Consumables, error)
- func (v *Vacuum) DND(ctx context.Context) (DND, error)
- func (v *Vacuum) DeleteTimer(ctx context.Context, id string) error
- func (v *Vacuum) DisableDND(ctx context.Context) error
- func (v *Vacuum) EnableTimer(ctx context.Context, id string, on bool) error
- func (v *Vacuum) FanSpeed(ctx context.Context) (int, error)
- func (v *Vacuum) FanSpeedPresets() (map[string]int, error)
- func (v *Vacuum) Find(ctx context.Context) error
- func (v *Vacuum) Home(ctx context.Context) error
- func (v *Vacuum) Pause(ctx context.Context) error
- func (v *Vacuum) ResetConsumable(ctx context.Context, part Consumable) error
- func (v *Vacuum) SetCarpetMode(ctx context.Context, on bool) error
- func (v *Vacuum) SetCarpetModeSettings(ctx context.Context, c CarpetMode) error
- func (v *Vacuum) SetDND(ctx context.Context, startHour, startMinute, endHour, endMinute int) error
- func (v *Vacuum) SetFanSpeed(ctx context.Context, speed int) error
- func (v *Vacuum) SetVolume(ctx context.Context, pct int) error
- func (v *Vacuum) Spot(ctx context.Context) error
- func (v *Vacuum) Start(ctx context.Context) error
- func (v *Vacuum) Status(ctx context.Context) (VacuumStatus, error)
- func (v *Vacuum) Stop(ctx context.Context) error
- func (v *Vacuum) TestVolume(ctx context.Context) error
- func (v *Vacuum) Timers(ctx context.Context) ([]VacuumTimer, error)
- func (v *Vacuum) Timezone(ctx context.Context) (string, error)
- func (v *Vacuum) Volume(ctx context.Context) (int, error)
- type VacuumStatus
- type VacuumTimer
- type ValueItem
- type VerifyError
Examples ¶
Constants ¶
const ( ByEmail = "email" ByPhone = "phone" )
Verification ways for SendCode and VerifyCode.
const ( OTAIdle = "idle" OTADownloading = "downloading" OTAInstalling = "installing" OTAFailed = "failed" )
OTA states.
const DefaultSpecURL = "https://miot-spec.org/miot-spec-v2"
DefaultSpecURL is miot-spec.org's specification service.
const MDNSService = "_miio._udp"
MDNSService is the miIO mDNS service type.
const Port = 54321
Port is miIO's UDP port.
const SpecMirrorURL = "https://spec.miot-spec.com/miot-spec-v2"
SpecMirrorURL is a second public host of the same service, for HTTPSpecs.Fallbacks.
Variables ¶
var ( // ErrCloudAuth: the account refused the user name or password. ErrCloudAuth = errors.New("the Mi account refused the user name or password") // ErrCloudVerify: Xiaomi asks for a captcha or an e-mail or SMS code. // The error is a *VerifyError; Captcha, CaptchaCode, SendCode and // VerifyCode complete the sign-in with a person's help. ErrCloudVerify = errors.New("the Mi account asks for a verification (a captcha or a code sent by e-mail or SMS)") )
Errors of the sign-in.
var ( // ErrUnknownName: the specification has no such property or action, or // the short name is shared by several. ErrUnknownName = errors.New("no such property or action in the MIoT specification") // ErrValue: a value does not fit the property's format, range or list. ErrValue = errors.New("the value does not fit the property") // ErrAccess: the property cannot be read or written. ErrAccess = errors.New("the property does not allow this access") )
Errors of the specification mapping.
var ErrNoSpec = errors.New("no MIoT specification of the model")
ErrNoSpec means no specification of the model could be found.
var ErrNotMirrored = errors.New("not in the MIoT specification mirror")
ErrNotMirrored means the mirror has no copy and no upstream to fetch it from (or the upstream failed).
var ErrOTAFailed = errors.New("the device reports the firmware update as failed")
ErrOTAFailed means the device reported the update as failed.
var ErrToken = errors.New("the device's answer does not open with the token")
ErrToken means the device's answer could not be opened with the token.
var ErrUnsupported = errors.New("the device model has no such function")
ErrUnsupported means the device model has no such function.
var Regions = []string{"cn", "de", "us", "ru", "tw", "sg", "in", "i2"}
Regions are the Mi account's server regions (cn has no prefix; i2 is India's).
Functions ¶
func CheckAction ¶
func CheckAction(raw json.RawMessage) error
CheckAction reads an action answer and returns a *PropError when its code is not 0.
func ConfigureWiFi ¶ added in v0.3.0
func ConfigureWiFi(ctx context.Context, c *Client, ssid, password string, uid int64, extra map[string]any) error
ConfigureWiFi tells a device to join a Wi-Fi network (miIO.config_router with ssid, passwd and uid; extra adds further parameters some models take). It is sent to a device in setup mode, on its own access point (usually 192.168.13.1:54321); the device leaves that network at once, so a missing answer is not proof of failure.
func DefaultAPIBase ¶
DefaultAPIBase is the Mi account's API address of a region.
func EncSignature ¶
EncSignature is the SHA-1 signature over the method, the path, the parameters in order and the signed nonce.
func GetProp ¶ added in v0.3.0
GetProp reads legacy properties with get_prop, at most max at a time (devices that cannot take a long list need a few at a time; max < 1 asks for all at once). The values come in the order of keys.
func Keys ¶
Keys derives the AES key and IV from a 16-byte token.
Example ¶
package main
import (
"encoding/hex"
"fmt"
"github.com/cB-Sigma/miio"
)
func main() {
tok, _ := hex.DecodeString("00112233445566778899aabbccddeeff")
key, iv := miio.Keys(tok)
fmt.Println(len(key), len(iv))
}
Output: 16 16
func ParseMDNSInstance ¶ added in v0.3.0
ParseMDNSInstance reads the model and device ID from a miIO instance name ("yeelink-light-color1_miio12345678", optionally followed by "._miio._udp.local."). ok is false for a name without "_miio"; did is 0 when no number follows it.
func RC4Decrypt ¶
RC4Decrypt reverses RC4Encrypt.
func RC4Encrypt ¶
RC4Encrypt encrypts a value with a signed nonce (base64 in and out).
func SignedNonce ¶
SignedNonce is the per-call key: SHA-256(ssecurity ‖ nonce), base64.
func SubDeviceModel ¶ added in v0.2.0
SubDeviceModel names the zigbee model of a type number ("" when not known).
func SupportsMIoT ¶ added in v0.3.0
SupportsMIoT tells whether the device answers MIoT get_properties (it asks for one property, service 1 property 1). A device that refuses the method speaks only the legacy methods; err is set only when the device could not be asked.
func TextKey ¶ added in v0.3.0
TextKey is the translation key of a service (piid, aiid and value all below 0), of one of its properties (piid ≥ 0), of a value of that property's value list (value ≥ 0: its position in the list, from 0), or of an action (aiid ≥ 0).
func TokenEnc ¶ added in v0.2.0
TokenEnc is how a scene target carries the target's token: the first 16 bytes of the token encrypted with itself, in hex.
func URNName ¶
URNName is the name part of a MIoT type URN ("urn:miot-spec-v2:property:on:00000006:..." gives "on") and whether it is a standard (miot-spec-v2) one.
func Update ¶ added in v0.2.0
Update asks the device to download the image at url, check it against md5Hex (32 hex digits) and install it.
func UpdateProgress ¶ added in v0.2.0
UpdateProgress reads the download progress in per cent.
func UpdateState ¶ added in v0.2.0
UpdateState reads the update state (OTAIdle, OTADownloading, OTAInstalling, OTAFailed, or another word a device uses).
func WaitUpdate ¶ added in v0.2.0
func WaitUpdate(ctx context.Context, c *Client, interval time.Duration, progress func(state string, pct int)) error
WaitUpdate polls the state every interval until the device is idle again after an update (nil), reports failure (ErrOTAFailed) or ctx ends. A device that restarts to install stops answering for a while; such silence is waited out. progress, when not nil, receives each reading.
Types ¶
type Action ¶
type Action struct {
IID int `json:"iid"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
In []int `json:"in,omitempty"`
Out []int `json:"out,omitempty"`
}
Action is one action of a service.
type BrowseFunc ¶ added in v0.3.0
BrowseFunc makes a function a Browser.
type Browser ¶ added in v0.3.0
Browser browses mDNS for a service type ("_miio._udp"), returning the instances found before ctx ends or its own wait is over.
type CarpetMode ¶ added in v0.3.0
CarpetMode is the vacuum's carpet detection: when on, it raises suction on carpet, detected by the brush motor's current crossing the thresholds (the units are the firmware's own).
type CleanRecord ¶ added in v0.3.0
type CleanRecord struct {
Start, End time.Time
Duration time.Duration
Area float64 // m²
Error int // 0: none
Complete bool
}
CleanRecord is one cleaning run.
type CleanSummary ¶ added in v0.3.0
type CleanSummary struct {
Duration time.Duration
Area float64 // m²
Count int
// Records are the IDs of the stored runs (start times in Unix
// seconds), newest first, for CleanRecord.
Records []int64
}
CleanSummary is the vacuum's cleaning history in total.
type Client ¶
type Client struct {
Addr string // host:port
Token []byte
Timeout time.Duration
// contains filtered or unexported fields
}
Client talks to one device.
func (*Client) Call ¶
Call sends a JSON-RPC request and returns its result, or the whole answer when it has neither "result" nor "error". Request IDs start at a random value (devices ignore an ID they answered recently, so a restarted client must not begin at 1 again); when a request is not answered, the IDs move on by 100 and it is asked once more.
type Cloud ¶
type Cloud struct {
Username, Password string
// AccountBase is https://account.xiaomi.com (tests change it).
AccountBase string
// APIBase gives a region's API address
// (https://<region>.api.io.mi.com/app).
APIBase func(region string) string
HTTP *http.Client
// CaptchaCode is the text of the captcha image (Captcha) a person
// read; the next Login sends it.
CaptchaCode string
// contains filtered or unexported fields
}
Cloud signs in to a Mi account and lists its devices.
func (*Cloud) Captcha ¶ added in v0.2.0
Captcha fetches the captcha image the last Login was asked for.
func (*Cloud) CloudCall ¶ added in v0.2.0
func (c *Cloud) CloudCall(ctx context.Context, region, did, method string, params any) (json.RawMessage, error)
CloudCall relays a legacy miIO method to a device through the account and returns the device's result.
func (*Cloud) CloudDoAction ¶ added in v0.2.0
func (c *Cloud) CloudDoAction(ctx context.Context, region, did string, siid, aiid int, in []any) error
CloudDoAction runs a MIoT action through the account.
func (*Cloud) CloudGetProperties ¶ added in v0.2.0
func (c *Cloud) CloudGetProperties(ctx context.Context, region string, refs []PropRef) ([]PropResult, error)
CloudGetProperties reads MIoT properties through the account.
func (*Cloud) CloudSetProperties ¶ added in v0.2.0
func (c *Cloud) CloudSetProperties(ctx context.Context, region string, refs []PropRef) ([]PropResult, error)
CloudSetProperties writes MIoT properties through the account and returns a *PropError for the first one refused.
func (*Cloud) Devices ¶
Devices signs in when needed and lists the account's devices in the regions (every region when empty), with the homes shared with it.
type CloudDevice ¶
type CloudDevice struct {
DID string `json:"did"`
Token string `json:"token"`
Name string `json:"name"`
Model string `json:"model"`
LocalIP string `json:"localip"`
MAC string `json:"mac"`
Online bool `json:"isOnline"`
Region string `json:"region,omitempty"`
// ParentID and ParentModel name the gateway of a sub-device.
ParentID string `json:"parent_id,omitempty"`
ParentModel string `json:"parent_model,omitempty"`
}
CloudDevice is one device of the account.
func GatewaySubDevices ¶ added in v0.2.0
func GatewaySubDevices(devs []CloudDevice, gatewayDID string) []CloudDevice
GatewaySubDevices picks from an account's device list the sub-devices whose parent is the gateway (for gateways that do not list them locally).
type Consumable ¶ added in v0.3.0
type Consumable string
Consumable names a part whose use the vacuum counts.
const ( MainBrush Consumable = "main_brush_work_time" SideBrush Consumable = "side_brush_work_time" Filter Consumable = "filter_work_time" Sensors Consumable = "sensor_dirty_time" CleaningBrush Consumable = "cleaning_brush_work_times" // a counter of uses, on docks that wash Strainer Consumable = "strainer_work_times" // a counter of uses, on docks that wash )
The parts reset_consumable takes; each is also the key of its counter in get_consumable's answer.
type Consumables ¶ added in v0.3.0
type Consumables struct {
MainBrush, SideBrush, Filter, Sensors time.Duration
// Raw is the whole answer, with counters of models that have more
// parts.
Raw map[string]any
}
Consumables are how long each part has been used since its last reset.
type DeviceError ¶ added in v0.3.0
DeviceError is an error answer of the device to a request (such as -32601 for a method it does not know).
func (*DeviceError) Error ¶ added in v0.3.0
func (e *DeviceError) Error() string
type EventInfo ¶ added in v0.2.0
type EventInfo struct {
// Action is the name the pushes arrive under (our choice).
Action string
// Extra identifies the trigger, such as "[1,6,1,0,[0,1],2,0]".
Extra string
// Event is the event name in the trigger; Action when empty.
Event string
// CommandExtra is passed back with each push.
CommandExtra string
// TriggerValue is a threshold, for triggers that have one.
TriggerValue any
// TriggerToken is needed by protected triggers (a gateway's alarm).
TriggerToken string
// SourceDID and SourceModel name the source; the watched device when
// empty. Gateway sub-devices are named by their sid and zigbee model.
SourceDID, SourceModel string
}
EventInfo describes one event to subscribe to.
type Family ¶ added in v0.2.0
type Family struct {
Client *Client
DID string
Model *Model // nil: legacy methods
LegacyModel string // such as "yeelink.light.color1"; used when Model is nil
}
Family is what the helpers share: the client, the device ID used in MIoT requests, and either a Model or, for legacy devices, the model name.
type Gateway ¶ added in v0.2.0
type Gateway struct {
Client *Client
// Model is the gateway's model; "lumi.gateway.mgl03" lists with
// get_device_list, the others with the device_list property.
Model string
}
Gateway reaches a gateway's sub-devices.
func (*Gateway) RemoveSubDevice ¶ added in v0.2.0
RemoveSubDevice unpairs a sub-device from the gateway.
func (*Gateway) SetSubProp ¶ added in v0.2.0
SetSubProp writes a property of a sub-device.
func (*Gateway) SubBattery ¶ added in v0.2.0
SubBattery reads a battery-powered sub-device's battery level, per cent (older gateways; the multi-mode gateway reports "voltage" instead).
func (*Gateway) SubDevices ¶ added in v0.2.0
SubDevices lists the gateway's sub-devices, without the gateway itself.
type HTTPSpecs ¶
type HTTPSpecs struct {
Base string
HTTP *http.Client
// Fallbacks are further bases tried in order when Base cannot be
// reached or answers a server error (such as SpecMirrorURL).
Fallbacks []string
// Status is the index asked for: "released" when empty, or "all" for
// every version (a released version is then still preferred).
Status string
// contains filtered or unexported fields
}
HTTPSpecs fetches specifications from a specification service.
func (*HTTPSpecs) Index ¶ added in v0.3.0
func (s *HTTPSpecs) Index(ctx context.Context) ([]SpecInstance, error)
Index returns the service's index.
func (*HTTPSpecs) RawIndex ¶ added in v0.3.0
RawIndex returns the service's index as it answered it.
func (*HTTPSpecs) RawInstance ¶ added in v0.3.0
RawInstance returns the specification with this URN as the service answered it.
func (*HTTPSpecs) RawTranslations ¶ added in v0.3.0
RawTranslations returns the texts of the specification with this URN in other languages, as the service answered them (/instance/v2/multiLanguage, beside /miot-spec-v2 on the same host).
func (*HTTPSpecs) Translations ¶ added in v0.3.0
Translations returns the texts of the specification with this URN in other languages.
type Header ¶
Header is a parsed packet header.
type Light ¶ added in v0.2.0
type Light struct{ Family }
Light is a lamp or bulb.
func (*Light) SetBrightness ¶ added in v0.2.0
SetBrightness sets the brightness in per cent.
func (*Light) SetColorTemperature ¶ added in v0.2.0
SetColorTemperature sets the colour temperature in kelvin (MIoT and Yeelight). Philips legacy lights take a 1-100 scale instead: use SetColorTemperatureScale.
func (*Light) SetColorTemperatureScale ¶ added in v0.2.0
SetColorTemperatureScale sets a Philips legacy light's colour temperature on its 1-100 scale.
type LightStatus ¶ added in v0.2.0
type LightStatus struct {
On bool
Brightness int // per cent
ColorTemperature int // kelvin (MIoT and Yeelight) or the Philips 1-100 scale
Color int // 0xRRGGBB
}
LightStatus is a light's state; fields the model lacks stay 0.
type MDNSDevice ¶ added in v0.3.0
type MDNSDevice struct {
Model string // such as "zhimi.airpurifier.m1"
DID uint32 // 0 when the name does not carry it
Addr string // host:port for Client.Addr
Instance string
}
MDNSDevice is a device found by mDNS.
func DiscoverMDNS ¶ added in v0.3.0
func DiscoverMDNS(ctx context.Context, b Browser) ([]MDNSDevice, error)
DiscoverMDNS browses for "_miio._udp" with the application's browser and returns the miIO devices among the answers, one per instance, with an IPv4 address preferred. A device found this way still needs its token; Client's first call does the hello.
type MDNSEntry ¶ added in v0.3.0
type MDNSEntry struct {
Instance string // the instance name, with or without the service and domain after it
IPs []net.IP
Port int // 0: the miIO port, 54321
}
MDNSEntry is one service instance a browser found.
type MappedAction ¶ added in v0.2.0
MappedAction is one action of a Model with its full name.
type MappedProperty ¶ added in v0.2.0
MappedProperty is one property of a Model with its full name.
type Model ¶ added in v0.2.0
type Model struct {
Spec *Spec
// contains filtered or unexported fields
}
Model maps a specification's names to IDs. Build it with NewModel; it is safe for concurrent use once built.
func NewModel ¶ added in v0.2.0
NewModel builds the mapping of a specification.
Example ¶
Map a specification to names and check values before sending them.
package main
import (
"fmt"
"github.com/cB-Sigma/miio"
)
func main() {
m, _ := miio.NewModel(&miio.Spec{Type: "urn:miot-spec-v2:device:light:0000A001:demo-lamp:1", Services: []miio.Service{
{IID: 2, Type: "urn:miot-spec-v2:service:light:00007802:demo-lamp:1", Properties: []miio.Property{
{IID: 2, Type: "urn:miot-spec-v2:property:brightness:0000000D:demo-lamp:1", Format: "uint8",
Access: []string{"read", "write"}, ValueRange: []float64{1, 100, 1}}}}}})
p, _ := m.Property("light.brightness")
_, err := p.Check(150)
fmt.Println(p.SIID, p.IID, err != nil)
}
Output: 2 2 true
func (*Model) Action ¶ added in v0.2.0
func (m *Model) Action(name string) (MappedAction, error)
Action finds an action by full name, unique short name or "<siid>.<aiid>".
func (*Model) Actions ¶ added in v0.2.0
func (m *Model) Actions() []MappedAction
Actions lists the actions in specification order.
func (*Model) Do ¶ added in v0.2.0
Do runs an action by name with its inputs, checking their number and, where the inputs are properties of the same service, their values.
func (*Model) Get ¶ added in v0.2.0
func (m *Model) Get(ctx context.Context, c *Client, did string, names ...string) (map[string]any, error)
Get reads properties by name and returns their values by the names given. Values of enumerated properties stay numbers; Describe names them. A property the device refused is left out and reported as a *PropError (the first one) next to the values it did give.
func (*Model) Properties ¶ added in v0.2.0
func (m *Model) Properties() []MappedProperty
Properties lists the properties in specification order.
func (*Model) Property ¶ added in v0.2.0
func (m *Model) Property(name string) (MappedProperty, error)
Property finds a property by full name, unique short name or "<siid>.<piid>".
type Plug ¶ added in v0.2.0
type Plug struct{ Family }
Plug is a smart plug or outlet.
type PlugStatus ¶ added in v0.2.0
PlugStatus is a plug's state.
type PropRef ¶
type PropRef struct {
DID string `json:"did"`
SIID int `json:"siid"`
PIID int `json:"piid"`
Value any `json:"value,omitempty"`
Code int `json:"code,omitempty"`
}
PropRef names one property in a MIoT request.
type PropResult ¶
type PropResult struct {
DID string `json:"did"`
SIID int `json:"siid"`
PIID int `json:"piid"`
Code int `json:"code"`
Value any `json:"value"`
}
PropResult is one property of a get_properties or set_properties answer, or the answer to an action. Code 0 is success; devices answer -4001 to -4005 and others for a property they lack, cannot write or cannot take the value of.
func CheckSet ¶
func CheckSet(raw json.RawMessage) ([]PropResult, error)
CheckSet reads a set_properties answer and returns a *PropError for the first property answered with a non-zero code.
func GetProperties ¶
GetProperties reads properties, in requests of at most 15, and returns one result per property in order. A property the device lacks has a non-zero Code.
Example ¶
Read a MIoT device's properties by service and property ID. It needs a device, so it is not run.
package main
import (
"context"
"encoding/hex"
"fmt"
"time"
"github.com/cB-Sigma/miio"
)
func main() {
tok, _ := hex.DecodeString("0f1e2d3c4b5a69788796a5b4c3d2e1f0")
c := &miio.Client{Addr: "192.168.1.70:54321", Token: tok, Timeout: 3 * time.Second}
res, err := miio.GetProperties(context.Background(), c, []miio.PropRef{
{DID: "purifier", SIID: 2, PIID: 2}, // power
{DID: "purifier", SIID: 3, PIID: 6}, // PM2.5
})
if err != nil {
fmt.Println(err)
return
}
for _, r := range res {
fmt.Println(r.SIID, r.PIID, r.Code, r.Value)
}
}
Output:
func SetProperties ¶
SetProperties writes properties (each PropRef with its Value) in one request. It returns the results, and a *PropError for the first property answered with a non-zero code.
type Property ¶
type Property struct {
IID int `json:"iid"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
Format string `json:"format,omitempty"`
Access []string `json:"access,omitempty"`
Unit string `json:"unit,omitempty"`
ValueRange []float64 `json:"value-range,omitempty"`
ValueList []ValueItem `json:"value-list,omitempty"`
}
Property is one property of a service.
func (Property) Can ¶
Can reports whether the property allows an access: "read", "write" or "notify".
func (Property) Check ¶ added in v0.2.0
Check tests a value against the property's format, value range (min, max, step) and value list, and returns it in the form to send: bool, int64 for integer formats, float64 for float, string for string. It takes numbers of any Go kind, json.Number, "on"/"off" and "true"/"false" for bool, and a value-list description for an enumerated property.
type Purifier ¶ added in v0.2.0
type Purifier struct{ Family }
Purifier is an air purifier.
func (*Purifier) SetFanLevel ¶ added in v0.2.0
SetFanLevel sets the fan level (MIoT only).
type PurifierStatus ¶ added in v0.2.0
type PurifierStatus struct {
On bool
Mode string // the mode's description (MIoT) or name (legacy)
FanLevel int
PM25 float64 // µg/m³ (the legacy "aqi" reading)
Humidity float64 // per cent
Temperature float64 // °C
}
PurifierStatus is a purifier's state; fields the model lacks stay 0.
type Push ¶ added in v0.2.0
type Push struct {
Device string // the sender's IP address
Source string // the source's ID (a device ID or a sub-device sid)
Action string // EventInfo.Action
Params json.RawMessage // what the device sent with it
}
Push is one event a device sent.
type PushServer ¶ added in v0.2.0
type PushServer struct {
// Addr is where it listens; ":54321" when empty. Devices always send to
// port 54321 of ServerIP.
Addr string
// DeviceID and Model are what the listener poses as; 100000001 and
// chuangmi.plug.v3 (a model devices accept as a scene target) when
// zero.
DeviceID uint32
Model string
// ServerIP is the address devices send to; when empty, the local
// address that routes to each device.
ServerIP string
// contains filtered or unexported fields
}
PushServer receives device pushes.
func (*PushServer) Close ¶ added in v0.2.0
func (s *PushServer) Close() error
Close stops listening. Scenes stay on the devices: Unsubscribe them first.
func (*PushServer) LocalAddr ¶ added in v0.2.0
func (s *PushServer) LocalAddr() net.Addr
LocalAddr is the listening address.
func (*PushServer) Register ¶ added in v0.2.0
func (s *PushServer) Register(c *Client, handler func(Push)) error
Register accepts pushes from the client's device and hands them to handler (on the server's goroutine: return quickly).
func (*PushServer) Subscribe ¶ added in v0.2.0
Subscribe installs a scene on the client's device that pushes the event to this server, and returns the scene's ID. The device must be Registered.
func (*PushServer) Subscriptions ¶ added in v0.2.0
func (s *PushServer) Subscriptions(c *Client) []string
Subscriptions lists the scene IDs installed through this server on a device.
func (*PushServer) Unsubscribe ¶ added in v0.2.0
Unsubscribe removes a scene from the client's device.
type Service ¶
type Service struct {
IID int `json:"iid"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
Properties []Property `json:"properties,omitempty"`
Actions []Action `json:"actions,omitempty"`
}
Service is one service of a specification.
type Spec ¶
type Spec struct {
Type string `json:"type"`
Description string `json:"description,omitempty"`
Services []Service `json:"services"`
}
Spec is a model's MIoT specification, as miot-spec.org serves it.
type SpecInstance ¶ added in v0.3.0
type SpecInstance struct {
Model string `json:"model"`
Version int `json:"version"`
Type string `json:"type"` // the specification's URN
Status string `json:"status,omitempty"` // "released" and others; only in the full index
TS int64 `json:"ts,omitempty"`
}
SpecInstance is one entry of the service's index: a version of a model's specification.
type SpecMirror ¶ added in v0.3.0
type SpecMirror struct {
Dir string
// Upstream fills the mirror: the index when there is none (or it is
// older than MaxAge), and each specification or translation on first
// request. nil: offline, only what the directory holds.
Upstream *HTTPSpecs
// MaxAge is how old the index may grow before Upstream is asked for
// a new one; 0: the index is kept until Fill is called. An unknown
// model also asks Upstream for a new index, at most once an hour.
MaxAge time.Duration
// contains filtered or unexported fields
}
SpecMirror keeps MIoT specifications in a local directory, for sites without internet or with unreliable internet. Filled from the specification service once (Fill, or on first use when Upstream is set), it serves from the directory from then on, also when the service cannot be reached. It is a SpecSource, and Handler serves the directory in the service's own URL and JSON shape, so HTTPSpecs (and other clients of miot-spec.org) can be pointed at it.
The directory holds instances.json (the service's index as it answered it), instance/<URN>.json and multiLanguage/<URN>.json (one specification and its translations each, as the service answered them; the URN query-escaped). Files are written whole through a temporary file and a rename, so a reader never sees half a file.
func (*SpecMirror) Add ¶ added in v0.3.0
func (m *SpecMirror) Add(model string, version int, raw []byte) error
Add stores a specification under a model and version (its URN is the specification's "type") and lists it in the index: for specifications carried in by hand, or a site's own. A model's newest version is the one used.
func (*SpecMirror) AddTranslations ¶ added in v0.3.0
func (m *SpecMirror) AddTranslations(urn string, raw []byte) error
AddTranslations stores the translations of the specification with this URN, in the service's answer shape.
func (*SpecMirror) Fill ¶ added in v0.3.0
func (m *SpecMirror) Fill(ctx context.Context, models ...string) error
Fill fetches a new index from Upstream and the newest specification of each model named (already stored ones are kept); with no models, only the index.
func (*SpecMirror) FillAll ¶ added in v0.3.0
func (m *SpecMirror) FillAll(ctx context.Context, workers int) error
FillAll fetches the newest specification of every model in the index that is not stored yet, with up to workers requests at a time (1 when below 1). It goes on past a failed model and returns the first error with the number of failures. The full index has many thousand models: expect a long run and a large directory.
func (*SpecMirror) FillTranslations ¶ added in v0.3.0
func (m *SpecMirror) FillTranslations(ctx context.Context, models ...string) error
FillTranslations fetches the translations of each model's newest specification (already stored ones are kept).
func (*SpecMirror) Handler ¶ added in v0.3.0
func (m *SpecMirror) Handler() http.Handler
Handler serves the mirror in the specification service's shape: a path ending in /instances answers the index (filtered by ?status= when its entries carry a status), /instance?type=<URN> a specification, and /multiLanguage?urn=<URN> its translations. Mounted at the root of a server, HTTPSpecs{Base: "http://<server>/miot-spec-v2"} reads it. With Upstream set, what is missing is fetched through and kept.
func (*SpecMirror) Models ¶ added in v0.3.0
func (m *SpecMirror) Models() []string
Models lists the models in the mirror's index, sorted.
func (*SpecMirror) RawInstance ¶ added in v0.3.0
RawInstance returns the stored specification with this URN, fetching it once when Upstream is set.
func (*SpecMirror) RawTranslations ¶ added in v0.3.0
RawTranslations returns the stored translations of the specification with this URN, fetching them once when Upstream is set.
func (*SpecMirror) Stored ¶ added in v0.3.0
func (m *SpecMirror) Stored(model string) bool
Stored tells whether the model's newest specification is in the directory.
func (*SpecMirror) Translations ¶ added in v0.3.0
func (m *SpecMirror) Translations(ctx context.Context, urn string) (Translations, error)
Translations returns the translations of the specification with this URN.
type SpecSource ¶
SpecSource gives a model's MIoT specification.
type SubDevice ¶ added in v0.2.0
type SubDevice struct {
SID string // "lumi.158d..."
TypeID int // the gateway's type number; -1 when listed by model
Model string // zigbee model ("lumi.sensor_ht.v1"), from the list or from TypeID
Firmware int // -1 when not listed
}
SubDevice is a sub-device of a gateway.
type Translations ¶ added in v0.3.0
Translations are a specification's texts in other languages: language (such as "zh_cn" or "en") → text key → text. The keys name a service, a property, a property's value-list entry or an action by their IIDs: TextKey builds them.
func ParseTranslations ¶ added in v0.3.0
func ParseTranslations(b []byte) (Translations, error)
ParseTranslations reads the service's answer to a translations request ({"type": ..., "data": {language: {key: text}}}).
func (Translations) Text ¶ added in v0.3.0
func (t Translations) Text(lang, key string) string
Text returns the text of key in lang, or "" when there is none.
type Vacuum ¶ added in v0.2.0
type Vacuum struct{ Family }
Vacuum is a robot vacuum.
func (*Vacuum) AddTimer ¶ added in v0.3.0
AddTimer schedules a cleaning by a cron schedule in the vacuum's time zone (legacy) and returns its ID; id "" takes the current time in Unix milliseconds, as the vendor app does. The vacuum adds it enabled on most firmware.
func (*Vacuum) CarpetMode ¶ added in v0.3.0
func (v *Vacuum) CarpetMode(ctx context.Context) (CarpetMode, error)
CarpetMode reads the carpet detection settings (legacy).
func (*Vacuum) CleanRecord ¶ added in v0.3.0
CleanRecord reads one run by its ID from CleanSummary.Records (legacy). Older firmware answers a list (start, end, duration, area, error, complete), newer an object; both are read.
func (*Vacuum) CleanSummary ¶ added in v0.3.0
func (v *Vacuum) CleanSummary(ctx context.Context) (CleanSummary, error)
CleanSummary reads the cleaning history (legacy). Older firmware answers a list (time, area, count, record IDs), newer an object with the same named fields; both are read.
func (*Vacuum) Consumables ¶ added in v0.3.0
func (v *Vacuum) Consumables(ctx context.Context) (Consumables, error)
Consumables reads the use of the brushes, filter and sensors (legacy).
func (*Vacuum) DeleteTimer ¶ added in v0.3.0
DeleteTimer removes a scheduled cleaning (legacy).
func (*Vacuum) DisableDND ¶ added in v0.3.0
DisableDND turns the do-not-disturb period off (legacy).
func (*Vacuum) EnableTimer ¶ added in v0.3.0
EnableTimer turns a scheduled cleaning on or off (legacy).
func (*Vacuum) FanSpeed ¶ added in v0.3.0
FanSpeed reads the suction setting: the legacy custom mode (a per cent on early models, a preset number on later ones), or the MIoT fan level's value.
func (*Vacuum) FanSpeedPresets ¶ added in v0.3.0
FanSpeedPresets names the suction settings of a MIoT vacuum, from its specification's value list (description → value). Legacy models take numbers that differ by model and firmware; this module bundles no table of them, so it answers ErrUnsupported there: read the current one with FanSpeed.
func (*Vacuum) Find ¶ added in v0.3.0
Find makes the vacuum say where it is: the legacy find_me, or the MIoT identify action.
func (*Vacuum) ResetConsumable ¶ added in v0.3.0
func (v *Vacuum) ResetConsumable(ctx context.Context, part Consumable) error
ResetConsumable sets a part's counter back to zero after it was replaced or cleaned (legacy).
func (*Vacuum) SetCarpetMode ¶ added in v0.3.0
SetCarpetMode turns carpet detection on or off, keeping the vacuum's thresholds (it reads them first) (legacy).
func (*Vacuum) SetCarpetModeSettings ¶ added in v0.3.0
func (v *Vacuum) SetCarpetModeSettings(ctx context.Context, c CarpetMode) error
SetCarpetModeSettings writes all carpet detection settings (legacy).
func (*Vacuum) SetFanSpeed ¶ added in v0.3.0
SetFanSpeed sets the suction setting: a number FanSpeed reads or FanSpeedPresets lists.
func (*Vacuum) Status ¶ added in v0.2.0
func (v *Vacuum) Status(ctx context.Context) (VacuumStatus, error)
Status reads the state and battery.
func (*Vacuum) TestVolume ¶ added in v0.3.0
TestVolume plays a sound at the current volume (legacy).
func (*Vacuum) Timers ¶ added in v0.3.0
func (v *Vacuum) Timers(ctx context.Context) ([]VacuumTimer, error)
Timers lists the scheduled cleanings (legacy).
type VacuumStatus ¶ added in v0.2.0
type VacuumStatus struct {
// Code is the state number: MIoT's vacuum status value, or the legacy
// Roborock state code.
Code int
// State names it: the specification's description (MIoT) or our own
// name for the common Roborock codes; "" when unknown.
State string
Battery int // per cent, -1 when not reported
}
VacuumStatus is a vacuum's state.
type VacuumTimer ¶ added in v0.3.0
type VacuumTimer struct {
ID string // the creation time in Unix milliseconds, as text
Enabled bool
// Cron is the schedule, "minute hour day-of-month month day-of-week"
// in the vacuum's time zone (VacuumTimezone).
Cron string
// Action is what runs, as the vacuum reports it (such as
// "start_clean"), with its parameters.
Action string
Params any
}
VacuumTimer is a scheduled cleaning.
type VerifyError ¶ added in v0.2.0
type VerifyError struct {
// CaptchaURL is set when a captcha must be read.
CaptchaURL string
// WrongCaptcha: the CaptchaCode sent was refused.
WrongCaptcha bool
// NotificationURL is set when a code must be sent and entered.
NotificationURL string
}
VerifyError is ErrCloudVerify with what the account asked for.
func (*VerifyError) Error ¶ added in v0.2.0
func (e *VerifyError) Error() string
func (*VerifyError) Unwrap ¶ added in v0.2.0
func (e *VerifyError) Unwrap() error
Unwrap makes errors.Is(err, ErrCloudVerify) true.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
miiospec
command
Command miiospec keeps a local mirror of MIoT specifications and serves it in the shape of miot-spec.org, for sites without internet:
|
Command miiospec keeps a local mirror of MIoT specifications and serves it in the shape of miot-spec.org, for sites without internet: |