This repository has been archived on 2023-08-29. You can view files and clone it, but cannot push or open issues or pull requests.
automation/integration/kasa/kasa.go
2022-11-19 04:48:05 +01:00

93 lines
1.4 KiB
Go

package kasa
import (
"automation/device"
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"net"
)
// This implementation is based on:
// https://www.softscheck.com/en/blog/tp-link-reverse-engineering/
type Device interface {
device.Basic
IsKasaDevice()
GetIP() string
}
func encrypt(data []byte) []byte {
var key byte = 171
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, uint32(len(data)))
for _, c := range []byte(data) {
a := key ^ c
key = a
buf.WriteByte(a)
}
return buf.Bytes()
}
func decrypt(data []byte) ([]byte, error) {
var key byte = 171
if len(data) < 4 {
return nil, fmt.Errorf("Array has a minumun size of 4")
}
size := binary.BigEndian.Uint32(data[0:4])
buf := make([]byte, size)
for i := 0; i < int(size); i++ {
a := key ^ data[i+4]
key = data[i+4]
buf[i] = a
}
return buf, nil
}
func sendCmd(kasa Device, cmd cmd) (reply, error) {
con, err := net.Dial("tcp", fmt.Sprintf("%s:9999", kasa.GetIP()))
if err != nil {
return reply{}, err
}
defer con.Close()
b, err := json.Marshal(cmd)
if err != nil {
return reply{}, err
}
_, err = con.Write(encrypt(b))
if err != nil {
return reply{}, err
}
resp := make([]byte, 2048)
_, err = con.Read(resp)
if err != nil {
return reply{}, err
}
d, err := decrypt(resp)
if err != nil {
return reply{}, err
}
var reply reply
err = json.Unmarshal(d, &reply)
if err != nil {
return reply, err
}
return reply, err
}