1
1
package sladdlos
2
2
3
3
import (
4
+ "fmt"
4
5
"github.com/hemtjanst/hemtjanst/device"
5
6
"github.com/hemtjanst/hemtjanst/messaging"
6
7
"github.com/hemtjanst/sladdlos/tradfri"
8
+ "github.com/lucasb-eyer/go-colorful"
7
9
"log"
8
10
"strconv"
9
11
"strings"
10
12
"sync"
11
13
)
12
14
15
+ const (
16
+ lTypeNone = iota
17
+ lTypeTemp
18
+ lTypeRgb
19
+ )
20
+
13
21
type HemtjanstDevice struct {
14
22
sync.RWMutex
15
- client * HemtjanstClient
16
- mqClient messaging.PublishSubscriber
17
- Topic string
18
- isRunning bool
19
- isGroup bool
20
- accessory * tradfri.Accessory
21
- members []* HemtjanstDevice
22
- group * tradfri.Group
23
- device * device.Device
24
- features map [string ]* device.Feature
23
+ client * HemtjanstClient
24
+ mqClient messaging.PublishSubscriber
25
+ Topic string
26
+ isRunning bool
27
+ isGroup bool
28
+ accessory * tradfri.Accessory
29
+ members []* HemtjanstDevice
30
+ group * tradfri.Group
31
+ device * device.Device
32
+ features map [string ]* device.Feature
33
+ lastHue * int
34
+ lastSaturation * int
25
35
}
26
36
27
37
func NewHemtjanstAccessory (client * HemtjanstClient , topic string , accessory * tradfri.Accessory , group * HemtjanstDevice ) * HemtjanstDevice {
@@ -87,7 +97,8 @@ func (h *HemtjanstDevice) init() {
87
97
return
88
98
}
89
99
var dev * device.Device
90
- hasColorTemp := false
100
+
101
+ lType := lTypeNone
91
102
if h .isGroup {
92
103
if h .group == nil {
93
104
return
@@ -109,10 +120,13 @@ func (h *HemtjanstDevice) init() {
109
120
if d .accessory != nil {
110
121
if l := d .accessory .Light (); l != nil {
111
122
if l .HasColorTemperature () {
112
- hasColorTemp = true
113
- break
123
+ lType = lTypeTemp
114
124
}
115
125
}
126
+ if d .accessory .DeviceInfo .IsRGBModel () {
127
+ lType = lTypeRgb
128
+ break
129
+ }
116
130
}
117
131
}
118
132
} else {
@@ -137,13 +151,24 @@ func (h *HemtjanstDevice) init() {
137
151
dev .LastWillID = h .client .Id
138
152
139
153
dev .AddFeature ("reachable" , & device.Feature {})
140
- hasColorTemp = h .accessory .Light ().HasColorTemperature ()
154
+
155
+ if h .accessory .Light ().HasColorTemperature () {
156
+ lType = lTypeTemp
157
+ }
158
+ if h .accessory .DeviceInfo .IsRGBModel () {
159
+ lType = lTypeRgb
160
+ }
141
161
}
142
162
143
163
dev .AddFeature ("on" , & device.Feature {})
144
164
dev .AddFeature ("brightness" , & device.Feature {})
145
- if hasColorTemp {
165
+
166
+ switch lType {
167
+ case lTypeTemp :
146
168
dev .AddFeature ("colorTemperature" , & device.Feature {})
169
+ case lTypeRgb :
170
+ dev .AddFeature ("hue" , & device.Feature {})
171
+ dev .AddFeature ("saturation" , & device.Feature {})
147
172
}
148
173
if dev != nil {
149
174
h .isRunning = true
@@ -177,6 +202,7 @@ func (h *HemtjanstDevice) handleFeature(name string, ft *device.Feature) {
177
202
ft .OnSet (func (msg messaging.Message ) {
178
203
h .onDeviceSet (ftName , string (msg .Payload ()))
179
204
})
205
+ h .publish (ftName )
180
206
}
181
207
}
182
208
@@ -210,17 +236,50 @@ func (h *HemtjanstDevice) onDeviceSet(feature string, newValue string) {
210
236
for _ , m := range h .members {
211
237
if m .accessory != nil && m .accessory .Light () != nil {
212
238
if m .accessory .Light ().HasColorTemperature () {
213
- m .accessory .SetColor (newTemp )
239
+ m .accessory .SetColorTemp (newTemp )
214
240
}
215
241
}
216
242
}
217
243
} else if h .accessory != nil {
218
- h .accessory .SetColor (newTemp )
244
+ h .accessory .SetColorTemp (newTemp )
219
245
}
220
246
}
247
+ case "hue" :
248
+ if hue , err := strconv .Atoi (newValue ); err == nil {
249
+ h .lastHue = & hue
250
+ h .updateColor ()
251
+ }
252
+ case "saturation" :
253
+ if saturation , err := strconv .Atoi (newValue ); err == nil {
254
+ h .lastSaturation = & saturation
255
+ h .updateColor ()
256
+ }
221
257
}
222
258
}
223
259
260
+ func (h * HemtjanstDevice ) updateColor () {
261
+ if h .lastHue == nil || h .lastSaturation == nil {
262
+ return
263
+ }
264
+ hue := * h .lastHue
265
+ sat := * h .lastSaturation
266
+
267
+ newColor := colorful .Hsv (float64 (hue ), float64 (sat )/ 100 , float64 (1 ))
268
+
269
+ if h .isGroup && h .group != nil {
270
+ for _ , m := range h .members {
271
+ if m .accessory != nil && m .accessory .Light () != nil {
272
+ if m .accessory .DeviceInfo .IsRGBModel () {
273
+ m .accessory .SetColor (newColor )
274
+ }
275
+ }
276
+ }
277
+ } else if h .accessory != nil {
278
+ h .accessory .SetColor (newColor )
279
+ }
280
+
281
+ }
282
+
224
283
func (h * HemtjanstDevice ) dimmable () * tradfri.Dimmable {
225
284
if h .isGroup {
226
285
if h .group != nil {
@@ -252,59 +311,83 @@ func (h *HemtjanstDevice) lightSetting() *tradfri.LightSetting {
252
311
return & l .LightSetting
253
312
}
254
313
314
+ func (h * HemtjanstDevice ) publish (feature string ) error {
315
+ switch feature {
316
+ case "on" :
317
+ dim := h .dimmable ()
318
+ if dim == nil {
319
+ return fmt .Errorf ("Device doesn't support %s" , feature )
320
+ }
321
+ val := "0"
322
+ if dim .IsOn () {
323
+ val = "1"
324
+ }
325
+ if ft , err := h .device .GetFeature ("on" ); err == nil && ft != nil {
326
+ return ft .Update (val )
327
+ }
328
+ return fmt .Errorf ("Feature %s not found" , feature )
329
+ case "brightness" :
330
+ dim := h .dimmable ()
331
+ if dim == nil {
332
+ return fmt .Errorf ("Device doesn't support %s" , feature )
333
+ }
334
+ newDim := dim .DimInt ()
335
+ if ft , err := h .device .GetFeature ("brightness" ); err == nil && ft != nil {
336
+ return ft .Update (strconv .Itoa (newDim ))
337
+ }
338
+ return fmt .Errorf ("Feature %s not found" , feature )
339
+ case "colorTemperature" :
340
+ ls := h .lightSetting ()
341
+ if ls == nil || ! ls .HasColorTemperature () {
342
+ return fmt .Errorf ("Device doesn't support %s" , feature )
343
+ }
344
+ newVal := ""
345
+ switch ls .GetColorName () {
346
+ case "cold" :
347
+ newVal = "111"
348
+ case "normal" :
349
+ newVal = "222"
350
+ case "warm" :
351
+ newVal = "400"
352
+ }
353
+ if ft , err := h .device .GetFeature ("colorTemperature" ); err == nil && ft != nil {
354
+ return ft .Update (newVal )
355
+ }
356
+ return fmt .Errorf ("Feature %s not found" , feature )
357
+ case "reachable" :
358
+ if h .isGroup || h .accessory == nil {
359
+ return fmt .Errorf ("Device doesn't support %s" , feature )
360
+ }
361
+ val := "0"
362
+ if h .accessory .IsAlive () {
363
+ val = "1"
364
+ }
365
+ if ft , err := h .device .GetFeature ("reachable" ); err == nil && ft != nil {
366
+ return ft .Update (val )
367
+ }
368
+ return fmt .Errorf ("Feature %s not found" , feature )
369
+ }
370
+ return fmt .Errorf ("Device doesn't support %s" , feature )
371
+ }
372
+
255
373
func (h * HemtjanstDevice ) onTradfriChange (change []* tradfri.ObservedChange ) {
374
+ colorUpdated := false
256
375
for _ , ch := range change {
257
376
log .Printf ("[%s] %s changed from %v to %v" , h .Topic , ch .Field , ch .OldValue , ch .NewValue )
258
377
switch ch .Field {
259
378
case "Dim" :
260
- dim := h .dimmable ()
261
- if dim == nil {
262
- continue
263
- }
264
- newDim := dim .DimInt ()
265
- if ft , err := h .device .GetFeature ("brightness" ); err == nil && ft != nil {
266
- ft .Update (strconv .Itoa (newDim ))
267
- }
379
+ h .publish ("brightness" )
268
380
case "On" :
269
- dim := h .dimmable ()
270
- if dim == nil {
271
- continue
272
- }
273
- val := "0"
274
- if dim .IsOn () {
275
- val = "1"
276
- }
277
- if ft , err := h .device .GetFeature ("on" ); err == nil && ft != nil {
278
- ft .Update (val )
279
- }
280
- case "Color" :
281
- ls := h .lightSetting ()
282
- if ls == nil {
283
- continue
284
- }
285
- newVal := ""
286
- switch ls .GetColorName () {
287
- case "cold" :
288
- newVal = "111"
289
- case "normal" :
290
- newVal = "222"
291
- case "warm" :
292
- newVal = "400"
293
- }
294
- if ft , err := h .device .GetFeature ("colorTemperature" ); err == nil && ft != nil {
295
- ft .Update (newVal )
381
+ h .publish ("on" )
382
+ case "Color" , "ColorX" , "ColorY" :
383
+ if ! colorUpdated {
384
+ colorUpdated = true
385
+ h .publish ("colorTemperature" )
386
+ h .publish ("hue" )
387
+ h .publish ("saturation" )
296
388
}
297
389
case "Alive" :
298
- if h .isGroup || h .accessory == nil {
299
- continue
300
- }
301
- val := "0"
302
- if h .accessory .IsAlive () {
303
- val = "1"
304
- }
305
- if ft , err := h .device .GetFeature ("reachable" ); err == nil && ft != nil {
306
- ft .Update (val )
307
- }
390
+ h .publish ("reachable" )
308
391
}
309
392
310
393
}
0 commit comments