-
Notifications
You must be signed in to change notification settings - Fork 1
/
co2mini.go
121 lines (106 loc) · 2.52 KB
/
co2mini.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package co2mini
import (
"fmt"
"time"
"github.com/zserge/hid"
"errors"
)
var (
key = []byte{0x86, 0x41, 0xc9, 0xa8, 0x7f, 0x41, 0x3c, 0xac}
)
type Co2mini struct {
Co2Ch chan int
TempCh chan float64
device hid.Device
}
func (c *Co2mini) Connect() error {
const vendorId = "04d9:a052:0100:00"
hid.UsbWalk(func(device hid.Device) {
info := device.Info()
id := fmt.Sprintf("%04x:%04x:%04x:%02x", info.Vendor, info.Product, info.Revision, info.Interface)
if id != vendorId {
return
}
c.device = device
})
if c.device == nil {
return errors.New("Device not found.")
}
c.Co2Ch = make(chan int)
c.TempCh = make(chan float64)
return nil
}
func (c *Co2mini) Start() error {
const co2op = 0x50
const tempop = 0x42
if err := c.device.Open(); err != nil {
return err
}
defer c.device.Close()
if err := c.device.SetReport(0, key); err != nil {
return err
}
for {
if buf, err := c.device.Read(-1, 1*time.Second); err == nil {
dec := decrypt(buf, key)
if len(dec) == 0 {
continue
}
val := int(dec[1])<<8 | int(dec[2])
if dec[0] == co2op {
c.Co2Ch <- val
}
if dec[0] == tempop {
c.TempCh <- float64(val)/16.0 - 273.15
}
}
}
}
func decrypt(b, key []byte) []byte {
if len(b) != 8 {
return b
}
phase1 := shuffle(b)
phase2 := xor(phase1, key)
phase3 := shift(phase2)
ctmp := offset()
result := calc(phase3, ctmp)
return result
}
func calc(b, ctmp []byte) []byte {
res := make([]byte, 8)
for i := range b {
res[i] = (0xFF + b[i] - ctmp[i] + 0x01) & 0xFF
}
return res
}
func offset() []byte {
offset := []byte{0x48, 0x74, 0x65, 0x6D, 0x70, 0x39, 0x39, 0x65} //"Htemp99e"
res := make([]byte, 8)
for i := range offset {
res[i] = (offset[i]>>4 | offset[i]<<4) & 0xFF
}
return res
}
func shift(b []byte) []byte {
res := make([]byte, 8)
for i := range b {
res[i] = (b[i]>>3 | b[(i-1+8)%8]<<5) & 0xFF
}
return res
}
func xor(b, key []byte) []byte {
res := make([]byte, 8)
for i := range b {
res[i] = b[i] ^ key[i]
}
return res
}
func shuffle(b []byte) []byte {
assignNum := []int{2, 4, 0, 7, 1, 6, 5, 3}
res := make([]byte, 8)
for i, v := range assignNum {
res[i] = b[v]
}
return res
}