-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathstream.go
150 lines (121 loc) · 3.18 KB
/
stream.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package nanoleaf
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"net"
"net/http"
)
// NanoStream udp connection to nanoleaf
type NanoStream struct {
nano *Nanoleaf
con net.Conn
connected bool
address string
port int
}
// FrameEffect describes a frame for a panel
type FrameEffect struct {
Red int `json:"red"`
Green int `json:"green"`
Blue int `json:"blue"`
Transition int `json:"transition"`
}
// PanelEffect describes effect for a specific panel
type PanelEffect struct {
ID int `json:"id"`
Frames []FrameEffect `json:"frames"`
}
// StreamEffect will write panel effects
type StreamEffect struct {
Panels []PanelEffect `json:"panels"`
}
// newNanoStream returns a new instance of NanoStream
func newNanoStream(nano *Nanoleaf) *NanoStream {
return &NanoStream{
nano: nano,
connected: false,
}
}
// WriteEffect writes effect to nanoleaf
func (s *NanoStream) WriteEffect(effect StreamEffect) error {
if len(effect.Panels) == 0 {
return nil
}
buf := new(bytes.Buffer)
binary.Write(buf, binary.LittleEndian, uint8(len(effect.Panels)))
for _, panel := range effect.Panels {
nFrames := uint8(len(panel.Frames))
binary.Write(buf, binary.LittleEndian, uint8(panel.ID))
binary.Write(buf, binary.LittleEndian, nFrames)
for _, frame := range panel.Frames {
binary.Write(buf, binary.LittleEndian, uint8(frame.Red))
binary.Write(buf, binary.LittleEndian, uint8(frame.Green))
binary.Write(buf, binary.LittleEndian, uint8(frame.Blue))
binary.Write(buf, binary.LittleEndian, uint8(0))
binary.Write(buf, binary.LittleEndian, uint8(frame.Transition))
}
}
if _, err := s.con.Write(buf.Bytes()); err != nil {
return err
}
return nil
}
// Activate activates extControl to allow creating a udp connection
func (s *NanoStream) Activate(version string) error {
if version != "v1" {
return ErrInvalidVersion
}
body := jsonPayload{
"write": jsonPayload{
"command": "display",
"animType": "extControl",
"extControlVersion": version,
},
}
url := fmt.Sprintf("%s/%s/effects", s.nano.url, s.nano.token)
resp, err := s.nano.client.R().SetHeader("Content-Type", "application/json").SetBody(body).Put(url)
if err != nil {
return err
}
if resp.StatusCode() == http.StatusUnauthorized {
return ErrUnauthorized
}
if resp.StatusCode() != http.StatusOK {
return ErrUnexpectedResponse
}
var jsonResponse struct {
Address string `json:"streamControlIpAddr"`
Port int `json:"streamControlPort"`
}
if err := json.Unmarshal(resp.Body(), &jsonResponse); err != nil {
return ErrParsingJSON
}
s.address = jsonResponse.Address
s.port = jsonResponse.Port
return nil
}
// Connect connects to nanoleaf via udp
func (s *NanoStream) Connect() error {
con, err := net.Dial("udp", fmt.Sprintf("%s:%d", s.address, s.port))
if err != nil {
return err
}
s.con = con
s.connected = true
return nil
}
// Disconnect closes udp connection
func (s *NanoStream) Disconnect() error {
err := s.con.Close()
if err != nil {
return err
}
s.connected = false
return nil
}
// IsConnected checks if there is a connection
func (s *NanoStream) IsConnected() bool {
return s.connected
}