Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
fancl committed Mar 21, 2024
0 parents commit edc3edb
Show file tree
Hide file tree
Showing 17 changed files with 2,411 additions and 0 deletions.
60 changes: 60 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
bin/

.svn/
.godeps
./build
.cover/
dist
_site
_posts
*.dat
.vscode
vendor

# Go.gitignore

# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test
storage
.idea

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.local
.DS_Store

profile

# vim stuff
*.sw[op]


logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

.vscode/*
!.vscode/extensions.json

node_modules
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Getting started

Xiaomi IoT devices protocol

# Usage

### MiIO protocol

#### Example

```go

device := miio.NewDevice("address","token")
if err := device.Dial(context.Background());err != nil{
return
}
defer device.Close()

if info,err := device.Info(context.Background());err == nil{
fmt.Println(info)
}

```

#### Method

* **Info** Get device info
* **GetAttributes** Get device props
* **GetProperties** Get device properties
* **SetProperties** Set device properties
* **Action** Execute device action
* **Execute** Execute command


### Mi Cloud

#### Example

```go
client := cloud.New("country","username","password")

if err = client.Login(context.Background());err != nil {
return
}
client.GetHomes(context.Background())
```

#### Method

* **Login** Login Mi cloud
* **GetHomes** Get mi homes
* **GetHomeDevices** Get home devices
* **GetDevices** Get all devices
* **GetLastMessage** Get last messages
* **GetSensorHistory** Get sensor histories
* **GetDeviceProps** Get device properties, like `miio` `GetProperties`
* **SetDeviceProps** Set device properties, like `miio` `SetProperties`
* **ExecuteDeviceAction** Execute device action, like `miio` `Action`
* **Request** do http request


### Command

build command

```shell
go build -o bin/miio cmd/main.go
```

`miio` command help

```shell
$ miio --help

miio an analog terminal that implements miio, capable of obtaining properties and sending instructions

Usage:
miio [command]

Available Commands:
action Do device action
completion Generate the autocompletion script for the specified shell
execute Execute device command
get_properties Get device properties
help Help about any command
info Show device info
parse_pcap Parse pcap filename
set_properties Set device properties

Flags:
-h, --help help for miio
--ip string device address
--token string device token

Use "miio [command] --help" for more information about a command.
```

## Protocl

Check full protocol specs [here](https://github.com/OpenMiHome/mihome-binary-protocol).
86 changes: 86 additions & 0 deletions cipher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package miio

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"errors"
)

var (
ErrUnPadding = errors.New("UnPadding error")
)

type (
tokenCipher struct {
Token []byte
key []byte
iv []byte
}
)

func (c *tokenCipher) md5Sum(bs ...[]byte) []byte {
hash := md5.New()
for _, b := range bs {
hash.Write(b)
}
return hash.Sum(nil)
}

func (c *tokenCipher) PKCS7Padding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
buf := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, buf...)
}

func (c *tokenCipher) PKCS7UnPadding(src []byte) ([]byte, error) {
length := len(src)
if length == 0 {
return src, ErrUnPadding
}
buf := int(src[length-1])
if length < buf {
return src, ErrUnPadding
}
return src[:(length - buf)], nil
}

func (c *tokenCipher) Encrypt(in []byte) (out []byte, err error) {
var (
mode cipher.BlockMode
block cipher.Block
)
if block, err = aes.NewCipher(c.key); err != nil {
return
}
mode = cipher.NewCBCEncrypter(block, c.iv)
in = c.PKCS7Padding(in, mode.BlockSize())
out = make([]byte, len(in))
mode.CryptBlocks(out, in)
return
}

func (c *tokenCipher) Decrypt(in []byte) (out []byte, err error) {
var (
mode cipher.BlockMode
block cipher.Block
)
if block, err = aes.NewCipher(c.key); err != nil {
return
}
out = make([]byte, len(in))
mode = cipher.NewCBCDecrypter(block, c.iv)
mode.CryptBlocks(out, in)
return c.PKCS7UnPadding(out)
}

func newTokenCipher(token []byte) *tokenCipher {
c := &tokenCipher{
Token: make([]byte, len(token)),
}
copy(c.Token[:], token[:])
c.key = c.md5Sum(c.Token)
c.iv = c.md5Sum(c.key, c.Token)
return c
}
Loading

0 comments on commit edc3edb

Please sign in to comment.