Integrating capability-based RMI on Sentinel for Java side
[iot2.git] / benchmarks / drivers / LifxLightBulb / LifxLightBulb.java
1 package iotcode.LifxLightBulb;
2
3 // Standard Java Packages
4 import java.io.*;
5 import java.net.*;
6 import java.util.concurrent.Semaphore;
7 import java.security.InvalidParameterException;
8 import java.util.Date;
9 import java.util.Iterator;
10 import java.util.concurrent.atomic.AtomicBoolean;
11
12 // IoT Packages
13 import iotcode.annotation.*;
14 import iotcode.interfaces.LightBulb;
15 import iotruntime.IoTUDP;
16 import iotruntime.slave.IoTDeviceAddress;
17 import iotruntime.slave.IoTSet;
18
19 // String to byte conversion
20 import javax.xml.bind.DatatypeConverter;
21
22 public class LifxLightBulb implements LightBulb {
23
24         /*******************************************************************************************************************************************
25         **
26         **  Constants
27         **
28         *******************************************************************************************************************************************/
29         public static final long GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
30
31
32
33         /*******************************************************************************************************************************************
34         **
35         **  Variables
36         **
37         *******************************************************************************************************************************************/
38         private IoTUDP communicationSockect;
39         private byte[] bulbMacAddress = new byte[8];
40         static Semaphore socketMutex = new Semaphore(1);
41         static boolean sendSocketFlag = false;
42         private long lastSentGetBulbVersionRequest = 0;                                                                                                                                                                                                                                                         // time last request sent
43
44         // Current Bulb Values
45         private int currentHue = 0;
46         private int currentSaturation = 0;
47         private int currentBrightness = 65535;
48         private int currentTemperature = 9000;
49         private boolean bulbIsOn = false;
50
51
52
53         private AtomicBoolean didAlreadyInit = new AtomicBoolean(false);
54
55         private AtomicBoolean didGetBulbVersion = new AtomicBoolean(false);
56         static Semaphore settingBulbColorMutex = new Semaphore(1);
57         static Semaphore settingBulbTempuraturerMutex = new Semaphore(1);
58         static Semaphore bulbStateMutex = new Semaphore(1);
59
60         // color and temperature ranges for the bulbs
61         private int hueLowerBound = 0;
62         private int hueUpperBound = 0;
63         private int saturationLowerBound = 0;
64         private int saturationUpperBound = 0;
65         private int brightnessLowerBound = 0;
66         private int brightnessUpperBound = 0;
67         private int temperatureLowerBound = 2500;
68         private int temperatureUpperBound = 9000;
69
70
71
72         // Check if a state change was requested, used to poll the bulb for if the bulb did
73         // preform the requested state change
74         private boolean stateDidChange = false;
75
76         /*******************************************************************************************************************************************
77         **
78         **  Threads
79         **
80         *******************************************************************************************************************************************/
81
82         // Main worker thread will do the receive loop
83         Thread workerThread = null;
84
85         /*******************************************************************************************************************************************
86         **
87         **  IoT Sets and Relations
88         **
89         *******************************************************************************************************************************************/
90
91         // IoTSet of Device Addresses.
92         // Will be filled with only 1 address.
93         @config private IoTSet<IoTDeviceAddress> lb_addresses;
94
95         /**
96          * Used for testing only
97          */
98         public LifxLightBulb(IoTUDP udp, byte[] macAddress) {
99                 communicationSockect = udp;
100                 bulbMacAddress = macAddress;
101         }
102
103         public LifxLightBulb(String macAddress) {
104                 communicationSockect = null;
105
106                 // Set the Mac Address to a default value
107                 // Probably not needed for anything
108                 /*bulbMacAdd[0] = (byte)0x00;
109                    bulbMacAdd[1] = (byte)0x00;
110                    bulbMacAdd[2] = (byte)0x00;
111                    bulbMacAdd[3] = (byte)0x00;
112                    bulbMacAdd[4] = (byte)0x00;
113                    bulbMacAdd[5] = (byte)0x00;
114                    bulbMacAdd[6] = (byte)0x00;
115                    bulbMacAdd[7] = (byte)0x00;*/
116
117                 bulbMacAddress = DatatypeConverter.parseHexBinary(macAddress);
118         }
119
120
121
122         /*******************************************************************************************************************************************
123         **  Sending
124         **  Device Messages
125         **
126         *******************************************************************************************************************************************/
127         private void sendGetServicePacket() {
128                 LifxHeader header = new LifxHeader();
129                 header.setSize(36);
130                 header.setTagged(true);
131                 header.setMacAddress(bulbMacAddress);
132                 header.setSource(0);                                                                                                                                                                                                                                                                                                                                                                                                                            // randomly picked
133                 header.setAck_required(false);
134                 header.setRes_required(false);
135                 header.setSequence(0);
136                 header.setType(2);
137
138                 byte[] dataBytes = header.getHeaderBytes();
139                 sendPacket(dataBytes);
140         }
141
142         private void sendGetHostInfoPacket() {
143                 LifxHeader header = new LifxHeader();
144                 header.setSize(36);
145                 header.setTagged(false);
146                 header.setMacAddress(bulbMacAddress);
147                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
148                 header.setAck_required(false);
149                 header.setRes_required(false);
150                 header.setSequence(0);
151                 header.setType(12);
152
153                 byte[] dataBytes = header.getHeaderBytes();
154                 sendPacket(dataBytes);
155         }
156
157         private void sendGetHostFirmwarePacket() {
158                 LifxHeader header = new LifxHeader();
159                 header.setSize(36);
160                 header.setTagged(false);
161                 header.setMacAddress(bulbMacAddress);
162                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
163                 header.setAck_required(false);
164                 header.setRes_required(false);
165                 header.setSequence(0);
166                 header.setType(14);
167
168                 byte[] dataBytes = header.getHeaderBytes();
169                 sendPacket(dataBytes);
170         }
171
172         private void sendGetWifiInfoPacket() {
173                 LifxHeader header = new LifxHeader();
174                 header.setSize(36);
175                 header.setTagged(false);
176                 header.setMacAddress(bulbMacAddress);
177                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
178                 header.setAck_required(false);
179                 header.setRes_required(false);
180                 header.setSequence(0);
181                 header.setType(16);
182
183                 byte[] dataBytes = header.getHeaderBytes();
184                 sendPacket(dataBytes);
185         }
186
187         private void sendGetWifiFirmwarePacket() {
188                 LifxHeader header = new LifxHeader();
189                 header.setSize(36);
190                 header.setTagged(false);
191                 header.setMacAddress(bulbMacAddress);
192                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
193                 header.setAck_required(false);
194                 header.setRes_required(false);
195                 header.setSequence(0);
196                 header.setType(18);
197
198                 byte[] dataBytes = header.getHeaderBytes();
199                 sendPacket(dataBytes);
200         }
201
202         private void sendGetPowerPacket() {
203                 LifxHeader header = new LifxHeader();
204                 header.setSize(36);
205                 header.setTagged(false);
206                 header.setMacAddress(bulbMacAddress);
207                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
208                 header.setAck_required(false);
209                 header.setRes_required(false);
210                 header.setSequence(0);
211                 header.setType(20);
212
213                 byte[] dataBytes = header.getHeaderBytes();
214                 sendPacket(dataBytes);
215         }
216
217         private void sendSetPowerPacket(int level) {
218                 // Currently only 0 and 65535 are supported
219                 // This is a fix for now
220                 if ((level != 65535) && (level != 0)) {
221                         throw new InvalidParameterException("Invalid parameter values");
222                 }
223
224                 if ((level > 65535) || (level < 0)) {
225                         throw new InvalidParameterException("Invalid parameter values");
226                 }
227
228                 byte[] packetBytes = new byte[38];
229
230                 LifxHeader header = new LifxHeader();
231                 header.setSize(38);
232                 header.setTagged(false);
233                 header.setMacAddress(bulbMacAddress);
234                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
235                 header.setAck_required(false);
236                 header.setRes_required(false);
237                 header.setSequence(0);
238                 header.setType(21);
239                 byte[] headerBytes = header.getHeaderBytes();
240
241                 for (int i = 0; i < 36; i++) {
242                         packetBytes[i] = headerBytes[i];
243                 }
244
245                 packetBytes[36] = (byte)(level & 0xFF);
246                 packetBytes[37] = (byte)((level >> 8) & 0xFF);
247
248                 sendPacket(packetBytes);
249         }
250
251         private void sendGetLabelPacket() {
252                 LifxHeader header = new LifxHeader();
253                 header.setSize(36);
254                 header.setTagged(false);
255                 header.setMacAddress(bulbMacAddress);
256                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
257                 header.setAck_required(false);
258                 header.setRes_required(false);
259                 header.setSequence(0);
260                 header.setType(23);
261
262                 byte[] dataBytes = header.getHeaderBytes();
263                 sendPacket(dataBytes);
264         }
265
266         private void sendSetLabelPacket(String label) {
267                 // Currently only 0 and 65535 are supported
268                 // This is a fix for now
269                 if (label.length() != 32) {
270                         throw new InvalidParameterException("Invalid parameter values, label must be 32 bytes long");
271                 }
272
273                 byte[] packetBytes = new byte[68];
274
275                 LifxHeader header = new LifxHeader();
276                 header.setSize(68);
277                 header.setTagged(false);
278                 header.setMacAddress(bulbMacAddress);
279                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
280                 header.setAck_required(false);
281                 header.setRes_required(false);
282                 header.setSequence(0);
283                 header.setType(24);
284                 byte[] headerBytes = header.getHeaderBytes();
285
286                 for (int i = 0; i < 36; i++) {
287                         packetBytes[i] = headerBytes[i];
288                 }
289
290                 for (int i = 0; i < 32; i++) {
291                         packetBytes[i + 36] = label.getBytes()[i];
292                 }
293
294                 sendPacket(packetBytes);
295         }
296
297         private void sendGetVersionPacket() {
298                 LifxHeader header = new LifxHeader();
299                 header.setSize(36);
300                 header.setTagged(false);
301                 header.setMacAddress(bulbMacAddress);
302                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
303                 header.setAck_required(false);
304                 header.setRes_required(false);
305                 header.setSequence(0);
306                 header.setType(32);
307
308                 byte[] dataBytes = header.getHeaderBytes();
309                 sendPacket(dataBytes);
310         }
311
312         private void sendGetInfoPacket() {
313                 LifxHeader header = new LifxHeader();
314                 header.setSize(36);
315                 header.setTagged(false);
316                 header.setMacAddress(bulbMacAddress);
317                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
318                 header.setAck_required(false);
319                 header.setRes_required(false);
320                 header.setSequence(0);
321                 header.setType(34);
322
323                 byte[] dataBytes = header.getHeaderBytes();
324                 sendPacket(dataBytes);
325         }
326
327         private void sendGetLocationPacket() {
328                 LifxHeader header = new LifxHeader();
329                 header.setSize(36);
330                 header.setTagged(false);
331                 header.setMacAddress(bulbMacAddress);
332                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
333                 header.setAck_required(false);
334                 header.setRes_required(false);
335                 header.setSequence(0);
336                 header.setType(34);
337
338                 byte[] dataBytes = header.getHeaderBytes();
339                 sendPacket(dataBytes);
340         }
341
342         private void sendGetGroupPacket() {
343                 LifxHeader header = new LifxHeader();
344                 header.setSize(36);
345                 header.setTagged(false);
346                 header.setMacAddress(bulbMacAddress);
347                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
348                 header.setAck_required(false);
349                 header.setRes_required(false);
350                 header.setSequence(0);
351                 header.setType(51);
352
353                 byte[] dataBytes = header.getHeaderBytes();
354                 sendPacket(dataBytes);
355         }
356
357
358         /*******************************************************************************************************************************************
359         **  Sending
360         **  Light Messages
361         **
362         *******************************************************************************************************************************************/
363         private void sendGetLightStatePacket() {
364                 LifxHeader header = new LifxHeader();
365                 header.setSize(36);
366                 header.setTagged(false);
367                 header.setMacAddress(bulbMacAddress);
368                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
369                 header.setAck_required(false);
370                 header.setRes_required(false);
371                 header.setSequence(0);
372                 header.setType(101);
373
374                 byte[] dataBytes = header.getHeaderBytes();
375                 sendPacket(dataBytes);
376         }
377
378         private void sendSetLightColorPacket(BulbColor bulbColor, long duration) {
379
380                 if ((duration > 4294967295l) || (duration < 0)) {
381                         throw new InvalidParameterException("Invalid parameter value, duration out of range (0 - 4294967295)");
382                 }
383
384                 byte[] packetBytes = new byte[49];
385
386                 LifxHeader header = new LifxHeader();
387                 header.setSize(49);
388                 header.setTagged(false);
389                 header.setMacAddress(bulbMacAddress);
390                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
391                 header.setAck_required(false);
392                 header.setRes_required(false);
393                 header.setSequence(0);
394                 header.setType(102);
395                 byte[] headerBytes = header.getHeaderBytes();
396
397                 for (int i = 0; i < 36; i++) {
398                         packetBytes[i] = headerBytes[i];
399                 }
400
401                 // 1 reserved packet
402                 packetBytes[37] = (byte)(bulbColor.getHue() & 0xFF);
403                 packetBytes[38] = (byte)((bulbColor.getHue() >> 8) & 0xFF);
404
405                 packetBytes[39] = (byte)(bulbColor.getSaturation() & 0xFF);
406                 packetBytes[40] = (byte)((bulbColor.getSaturation() >> 8) & 0xFF);
407
408                 packetBytes[41] = (byte)(bulbColor.getBrightness() & 0xFF);
409                 packetBytes[42] = (byte)((bulbColor.getBrightness() >> 8) & 0xFF);
410
411                 packetBytes[43] = (byte)(bulbColor.getKelvin() & 0xFF);
412                 packetBytes[44] = (byte)((bulbColor.getKelvin() >> 8) & 0xFF);
413
414                 packetBytes[45] = (byte)((duration >> 0) & 0xFF);
415                 packetBytes[46] = (byte)((duration >> 8) & 0xFF);
416                 packetBytes[47] = (byte)((duration >> 16) & 0xFF);
417                 packetBytes[48] = (byte)((duration >> 24) & 0xFF);
418
419                 sendPacket(packetBytes);
420         }
421
422         private void sendGetLightPowerPacket() {
423                 LifxHeader header = new LifxHeader();
424                 header.setSize(36);
425                 header.setTagged(false);
426                 header.setMacAddress(bulbMacAddress);
427                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
428                 header.setAck_required(false);
429                 header.setRes_required(false);
430                 header.setSequence(0);
431                 header.setType(116);
432
433                 byte[] dataBytes = header.getHeaderBytes();
434                 sendPacket(dataBytes);
435         }
436
437         private void sendSetLightPowerPacket(int level, long duration) {
438
439                 if ((level > 65535) || (duration > 4294967295l)
440                         || (level < 0) || (duration < 0)) {
441                         throw new InvalidParameterException("Invalid parameter values");
442                 }
443
444                 byte[] packetBytes = new byte[42];
445
446
447                 LifxHeader header = new LifxHeader();
448                 header.setSize(42);
449                 header.setTagged(false);
450                 header.setMacAddress(bulbMacAddress);
451                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
452                 header.setAck_required(false);
453                 header.setRes_required(false);
454                 header.setSequence(0);
455                 header.setType(117);
456                 byte[] headerBytes = header.getHeaderBytes();
457
458                 for (int i = 0; i < 36; i++) {
459                         packetBytes[i] = headerBytes[i];
460                 }
461
462                 packetBytes[36] = (byte)(level & 0xFF);
463                 packetBytes[37] = (byte)((level >> 8) & 0xFF);
464
465                 packetBytes[38] = (byte)((duration >> 0) & 0xFF);
466                 packetBytes[39] = (byte)((duration >> 8) & 0xFF);
467                 packetBytes[40] = (byte)((duration >> 16) & 0xFF);
468                 packetBytes[41] = (byte)((duration >> 24) & 0xFF);
469
470                 sendPacket(packetBytes);
471         }
472
473         private void sendEchoRequestPacket(byte[] data) {
474                 // Currently only 0 and 65535 are supported
475                 // This is a fix for now
476                 if (data.length != 64) {
477                         throw new InvalidParameterException("Invalid parameter values, must have 64 bytes");
478                 }
479
480                 byte[] packetBytes = new byte[100];
481
482                 LifxHeader header = new LifxHeader();
483                 header.setSize(100);
484                 header.setTagged(false);
485                 header.setMacAddress(bulbMacAddress);
486                 header.setSource(10);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           // randomly picked
487                 header.setAck_required(false);
488                 header.setRes_required(false);
489                 header.setSequence(0);
490                 header.setType(58);
491                 byte[] headerBytes = header.getHeaderBytes();
492
493                 for (int i = 0; i < 36; i++) {
494                         packetBytes[i] = headerBytes[i];
495                 }
496
497                 for (int i = 0; i < 64; i++) {
498                         packetBytes[i + 36] = data[i];
499                 }
500
501                 sendPacket(packetBytes);
502         }
503
504
505         /*******************************************************************************************************************************************
506         **  Receiving
507         **  Device Messages
508         **
509         *******************************************************************************************************************************************/
510         private DeviceStateService parseDeviceStateServiceMessage(LifxHeader header, byte[] payloadData) {
511                 int service = payloadData[0];
512                 long port = ((payloadData[3] & 0xFF) << 24);
513                 port |= ((payloadData[2] & 0xFF) << 16);
514                 port |= ((payloadData[1] & 0xFF) << 8);
515                 port |= (payloadData[0] & 0xFF);
516
517                 return new DeviceStateService(service, port);
518         }
519
520         private DeviceStateHostInfo parseDeviceStateHostInfoMessage(LifxHeader header, byte[] payloadData) {
521                 long signal = ((payloadData[3] & 0xFF) << 24);
522                 signal |= ((payloadData[2] & 0xFF) << 16);
523                 signal |= ((payloadData[1] & 0xFF) << 8);
524                 signal |= (payloadData[0] & 0xFF);
525
526                 long tx = ((payloadData[7] & 0xFF) << 24);
527                 tx |= ((payloadData[6] & 0xFF) << 16);
528                 tx |= ((payloadData[5] & 0xFF) << 8);
529                 tx |= (payloadData[4] & 0xFF);
530
531                 long rx = ((payloadData[11] & 0xFF) << 24);
532                 rx |= ((payloadData[10] & 0xFF) << 16);
533                 rx |= ((payloadData[9] & 0xFF) << 8);
534                 rx |= (payloadData[8] & 0xFF);
535
536                 return new DeviceStateHostInfo(signal, tx, rx);
537         }
538
539         private DeviceStateHostFirmware parseDeviceStateHostFirmwareMessage(LifxHeader header, byte[] payloadData) {
540                 long build = 0;
541                 for (int i = 0; i < 8; i++) {
542                         build += ((long) payloadData[i] & 0xffL) << (8 * i);
543                 }
544
545                 // 8 reserved bytes
546
547                 long version = ((payloadData[19] & 0xFF) << 24);
548                 version |= ((payloadData[18] & 0xFF) << 16);
549                 version |= ((payloadData[17] & 0xFF) << 8);
550                 version |= (payloadData[16] & 0xFF);
551
552                 return new DeviceStateHostFirmware(build, version);
553         }
554
555         private DeviceStateWifiInfo parseDeviceStateWifiInfoMessage(LifxHeader header, byte[] payloadData) {
556                 long signal = ((payloadData[3] & 0xFF) << 24);
557                 signal |= ((payloadData[2] & 0xFF) << 16);
558                 signal |= ((payloadData[1] & 0xFF) << 8);
559                 signal |= (payloadData[0] & 0xFF);
560
561                 long tx = ((payloadData[7] & 0xFF) << 24);
562                 tx |= ((payloadData[6] & 0xFF) << 16);
563                 tx |= ((payloadData[5] & 0xFF) << 8);
564                 tx |= (payloadData[4] & 0xFF);
565
566                 long rx = ((payloadData[11] & 0xFF) << 24);
567                 rx |= ((payloadData[10] & 0xFF) << 16);
568                 rx |= ((payloadData[9] & 0xFF) << 8);
569                 rx |= (payloadData[8] & 0xFF);
570
571                 return new DeviceStateWifiInfo(signal, tx, rx);
572         }
573
574         private DeviceStateWifiFirmware parseDeviceStateWifiFirmwareMessage(LifxHeader header, byte[] payloadData) {
575                 long build = 0;
576                 for (int i = 0; i < 8; i++) {
577                         build += ((long) payloadData[i] & 0xffL) << (8 * i);
578                 }
579
580                 // 8 reserved bytes
581
582                 long version = ((payloadData[19] & 0xFF) << 24);
583                 version |= ((payloadData[18] & 0xFF) << 16);
584                 version |= ((payloadData[17] & 0xFF) << 8);
585                 version |= (payloadData[16] & 0xFF);
586
587                 return new DeviceStateWifiFirmware(build, version);
588         }
589
590         private int parseStatePowerMessage(LifxHeader header, byte[] payloadData) {
591                 int level = ((payloadData[1] & 0xFF) << 8);
592                 level |= (payloadData[0] & 0xFF);
593                 return level;
594         }
595
596         private String parseStateLabelMessage(LifxHeader header, byte[] payloadData) {
597                 return new String(payloadData);
598         }
599
600
601         private DeviceStateVersion parseDeviceStateVersionMessage(LifxHeader header, byte[] payloadData) {
602                 long vender = ((payloadData[3] & 0xFF) << 24);
603                 vender |= ((payloadData[2] & 0xFF) << 16);
604                 vender |= ((payloadData[1] & 0xFF) << 8);
605                 vender |= (payloadData[0] & 0xFF);
606
607                 long product = ((payloadData[7] & 0xFF) << 24);
608                 product |= ((payloadData[6] & 0xFF) << 16);
609                 product |= ((payloadData[5] & 0xFF) << 8);
610                 product |= (payloadData[4] & 0xFF);
611
612                 long version = ((payloadData[11] & 0xFF) << 24);
613                 version |= ((payloadData[10] & 0xFF) << 16);
614                 version |= ((payloadData[9] & 0xFF) << 8);
615                 version |= (payloadData[8] & 0xFF);
616
617                 return new DeviceStateVersion(vender, product, version);
618         }
619
620         private DeviceStateInfo parseDeviceStateInfoMessage(LifxHeader header, byte[] payloadData) {
621                 long time = 0;
622                 long upTime = 0;
623                 long downTime = 0;
624                 for (int i = 0; i < 8; i++) {
625                         time += ((long) payloadData[i] & 0xffL) << (8 * i);
626                         upTime += ((long) payloadData[i + 8] & 0xffL) << (8 * i);
627                         downTime += ((long) payloadData[i + 16] & 0xffL) << (8 * i);
628                 }
629
630                 return new DeviceStateInfo(time, upTime, downTime);
631         }
632
633         private DeviceStateLocation parseDeviceStateLocationMessage(LifxHeader header, byte[] payloadData) {
634                 byte[] location = new byte[16];
635                 for (int i = 0; i < 16; i++) {
636                         location[i] = payloadData[i];
637                 }
638
639                 byte[] labelBytes = new byte[32];
640                 for (int i = 0; i < 32; i++) {
641                         labelBytes[i] = payloadData[i + 16];
642                 }
643
644                 long updatedAt = 0;
645                 for (int i = 0; i < 8; i++) {
646                         updatedAt += ((long) payloadData[48] & 0xffL) << (8 * i);
647                 }
648
649                 return new DeviceStateLocation(location, new String(labelBytes), updatedAt);
650         }
651
652         private DeviceStateGroup parseDeviceStateGroupMessage(LifxHeader header, byte[] payloadData) {
653                 byte[] group = new byte[16];
654                 for (int i = 0; i < 16; i++) {
655                         group[i] = payloadData[i];
656                 }
657
658                 byte[] labelBytes = new byte[32];
659                 for (int i = 0; i < 32; i++) {
660                         labelBytes[i] = payloadData[i + 16];
661                 }
662
663                 long updatedAt = 0;
664                 for (int i = 0; i < 8; i++) {
665                         updatedAt += ((long) payloadData[48] & 0xffL) << (8 * i);
666                 }
667
668                 return new DeviceStateGroup(group, new String(labelBytes), updatedAt);
669         }
670
671         private byte[] parseDeviceEchoResponseMessage(LifxHeader header, byte[] payloadData) {
672                 return payloadData;
673         }
674
675         /*******************************************************************************************************************************************
676         **  Receiving
677         **  Light Messages
678         **
679         *******************************************************************************************************************************************/
680         private LightState parseLightStateMessage(LifxHeader header, byte[] payloadData) {
681
682                 byte[] colorData = new byte[8];
683                 for (int i = 0; i < 8; i++) {
684                         colorData[i] = payloadData[i];
685                 }
686                 BulbColor color = new BulbColor(colorData);
687
688                 int power = ((payloadData[11] & 0xFF) << 8);
689                 power |= (payloadData[10] & 0xFF);
690
691                 String label = new String(payloadData);
692
693                 byte[] labelArray = new byte[32];
694                 for (int i = 0; i < 32; i++) {
695                         labelArray[i] = payloadData[12 + i];
696                 }
697
698                 return new LightState(color, power, label);
699         }
700
701         private int parseLightStatePowerMessage(LifxHeader header, byte[] payloadData) {
702                 int level = ((payloadData[1] & 0xFF) << 8);
703                 level |= (payloadData[0] & 0xFF);
704                 return level;
705         }
706
707
708         /*******************************************************************************************************************************************
709         **
710         **  Private Handlers
711         **
712         *******************************************************************************************************************************************/
713         private void handleStateVersionMessageRecieved(LifxHeader header, byte[] payloadData) {
714
715                 DeviceStateVersion deviceState = parseDeviceStateVersionMessage(header, payloadData);
716                 int productNumber = (int)deviceState.getProduct();
717
718                 boolean isColor = false;
719
720                 if (productNumber == 1) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Original 1000
721                         isColor = true;
722                 } else if (productNumber == 3) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                //Color 650
723                         isColor = true;
724                 } else if (productNumber == 10) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 800 (Low Voltage)
725                         isColor = false;
726                 } else if (productNumber == 11) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 800 (High Voltage)
727                         isColor = false;
728                 } else if (productNumber == 18) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // White 900 BR30 (Low Voltage)
729                         isColor = false;
730                 } else if (productNumber == 20) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Color 1000 BR30
731                         isColor = true;
732                 } else if (productNumber == 22) {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               // Color 1000
733                         isColor = true;
734                 }
735
736                 if (isColor) {
737                         hueLowerBound = 0;
738                         hueUpperBound = 65535;
739                         saturationLowerBound = 0;
740                         saturationUpperBound = 65535;
741                         brightnessLowerBound = 0;
742                         brightnessUpperBound = 65535;
743                         temperatureLowerBound = 2500;
744                         temperatureUpperBound = 9000;
745                 } else {
746                         hueLowerBound = 0;
747                         hueUpperBound = 0;
748                         saturationLowerBound = 0;
749                         saturationUpperBound = 0;
750                         brightnessLowerBound = 0;
751                         brightnessUpperBound = 65535;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   // still can dim bulb
752                         temperatureLowerBound = 2500;
753                         temperatureUpperBound = 9000;
754                 }
755
756                 didGetBulbVersion.set(true);
757
758         }
759
760         private void handleLightStateMessageRecieved(LifxHeader header, byte[] payloadData) {
761                 LightState lightState = parseLightStateMessage(header, payloadData);
762
763                 BulbColor color = lightState.getColor();
764                 int power = lightState.getPower();
765
766                 boolean bulbWrongColor = false;
767                 bulbWrongColor = bulbWrongColor || (color.getHue() != currentHue);
768                 bulbWrongColor = bulbWrongColor || (color.getSaturation() != currentSaturation);
769                 bulbWrongColor = bulbWrongColor || (color.getBrightness() != currentBrightness);
770                 bulbWrongColor = bulbWrongColor || (color.getKelvin() != currentTemperature);
771
772
773                 // gets set to true if any of the below if statements are taken
774                 stateDidChange = false;
775
776                 if (bulbWrongColor) {
777                         BulbColor newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
778                         sendSetLightColorPacket(newColor, 250);
779                         // System.out.println("Failed Check 1");
780                 }
781
782                 try {
783                         bulbStateMutex.acquire();
784                 } catch (Exception e) {
785                         e.printStackTrace();
786                 }
787                 boolean bulbIsOnTmp = bulbIsOn;
788                 bulbStateMutex.release();
789
790                 if ((!bulbIsOnTmp) && (power != 0)) {
791                         turnOff();
792                         // System.out.println("Failed Check 2:  " + Integer.toString(power));
793
794                 }
795
796                 if (bulbIsOnTmp && (power < 65530)) {
797                         turnOn();
798                         // System.out.println("Failed Check 3:  " + Integer.toString(power));
799
800                 }
801         }
802
803         /*******************************************************************************************************************************************
804         **
805         **  Light Bulb Interface Methods
806         **
807         *******************************************************************************************************************************************/
808         public double getHue() {
809                 double tmp = 0;
810                 try {
811                         settingBulbColorMutex.acquire();
812                         tmp = ((double)currentHue / 65535.0) * 360.0;
813                 } catch (Exception e) {
814                         e.printStackTrace();
815                 }
816                 settingBulbColorMutex.release();
817
818
819                 return tmp;
820         }
821
822         public double getSaturation() {
823                 double tmp = 0;
824                 try {
825                         settingBulbColorMutex.acquire();
826                         tmp = ((double)currentSaturation / 65535.0) * 360.0;
827                 } catch (Exception e) {
828                         e.printStackTrace();
829                 }
830                 settingBulbColorMutex.release();
831
832
833                 return tmp;
834         }
835
836         public double getBrightness() {
837                 double tmp = 0;
838                 try {
839                         settingBulbColorMutex.acquire();
840                         tmp = ((double)currentBrightness / 65535.0) * 360.0;
841                 } catch (Exception e) {
842                         e.printStackTrace();
843                 }
844                 settingBulbColorMutex.release();
845
846                 return tmp;
847         }
848
849         public int getTemperature() {
850
851                 int tmp = 0;
852                 try {
853                         settingBulbTempuraturerMutex.acquire();
854                         tmp = currentTemperature;
855                 } catch (Exception e) {
856                         e.printStackTrace();
857                 }
858                 settingBulbTempuraturerMutex.release();
859
860                 return tmp;
861         }
862
863         public double getHueRangeLowerBound() {
864                 if (!didGetBulbVersion.get()) {
865                         return -1;
866                 }
867                 return ((double)hueLowerBound / 65535.0) * 360.0;
868         }
869
870         public double getHueRangeUpperBound() {
871                 if (!didGetBulbVersion.get()) {
872                         return -1;
873                 }
874                 return ((double)hueUpperBound / 65535.0) * 360.0;
875         }
876
877         public double getSaturationRangeLowerBound() {
878                 if (!didGetBulbVersion.get()) {
879                         return -1;
880                 }
881                 return ((double)saturationLowerBound / 65535.0) * 100.0;
882         }
883
884         public double getSaturationRangeUpperBound() {
885                 if (!didGetBulbVersion.get()) {
886                         return -1;
887                 }
888                 return ((double)saturationUpperBound / 65535.0) * 100.0;
889         }
890
891         public double getBrightnessRangeLowerBound() {
892                 if (!didGetBulbVersion.get()) {
893                         return -1;
894                 }
895                 return ((double)brightnessLowerBound / 65535.0) * 100.0;
896         }
897
898         public double getBrightnessRangeUpperBound() {
899                 if (!didGetBulbVersion.get()) {
900                         return -1;
901                 }
902                 return ((double)brightnessUpperBound / 65535.0) * 100.0;
903         }
904
905         public int getTemperatureRangeLowerBound() {
906                 if (!didGetBulbVersion.get()) {
907                         return -1;
908                 }
909                 return temperatureLowerBound;
910         }
911
912         public int getTemperatureRangeUpperBound() {
913                 if (!didGetBulbVersion.get()) {
914                         return -1;
915                 }
916                 return temperatureUpperBound;
917         }
918
919         public void setTemperature(int _temperature) {
920
921                 try {
922                         settingBulbTempuraturerMutex.acquire();
923                 } catch (Exception e) {
924                         e.printStackTrace();
925                 }
926
927                 BulbColor newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
928                 sendSetLightColorPacket(newColor, 250);
929
930                 currentTemperature = _temperature;
931                 stateDidChange = true;
932
933                 settingBulbTempuraturerMutex.release();
934         }
935
936         public void setColor(double _hue, double _saturation, double _brightness) {
937
938                 try {
939                         settingBulbColorMutex.acquire();
940                 } catch (Exception e) {
941                         e.printStackTrace();
942                 }
943
944
945                 _hue /= 360.0;
946                 _saturation /= 100.0;
947                 _brightness /= 100.0;
948
949
950                 int newHue = (int)(_hue * 65535.0);
951                 int newSaturation = (int)(_saturation * 65535.0);
952                 int newBrightness = (int)(_brightness * 65535.0);
953
954                 BulbColor newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
955                 sendSetLightColorPacket(newColor, 250);
956
957                 currentHue = newHue;
958                 currentSaturation = newSaturation;
959                 currentBrightness = newBrightness;
960                 stateDidChange = true;
961
962                 settingBulbColorMutex.release();
963         }
964
965
966         public void turnOff() {
967
968                 try {
969                         bulbStateMutex.acquire();
970                         bulbIsOn = false;
971                         sendSetLightPowerPacket(0, 0);
972                         stateDidChange = true;
973                 } catch (Exception e) {
974                         e.printStackTrace();
975                 }
976
977                 bulbStateMutex.release();
978         }
979
980         public void turnOn() {
981                 try {
982                         bulbStateMutex.acquire();
983                         bulbIsOn = true;
984                         sendSetLightPowerPacket(65535, 0);
985                         stateDidChange = true;
986
987                 } catch (Exception e) {
988                         e.printStackTrace();
989                 }
990
991
992                 bulbStateMutex.release();
993         }
994
995         public boolean getState() {
996
997                 boolean tmp = false;
998                 try {
999                         bulbStateMutex.acquire();
1000                         tmp = bulbIsOn;
1001                 } catch (Exception e) {
1002                         e.printStackTrace();
1003                 }
1004
1005                 bulbStateMutex.release();
1006
1007                 return tmp;
1008         }
1009
1010
1011         /*******************************************************************************************************************************************
1012         **
1013         **  Communication Helpers
1014         **
1015         *******************************************************************************************************************************************/
1016         private void recievedPacket(byte[] packetData) {
1017
1018                 byte[] headerBytes = new byte[36];
1019                 for (int i = 0; i < 36; i++) {
1020                         headerBytes[i] = packetData[i];
1021                 }
1022
1023                 LifxHeader recHeader = new LifxHeader();
1024                 recHeader.setFromBytes(headerBytes);
1025
1026                 // load the payload bytes (strip away the header)
1027                 byte[] payloadBytes = new byte[recHeader.getSize()];
1028                 for (int i = 36; i < recHeader.getSize(); i++) {
1029                         payloadBytes[i - 36] = packetData[i];
1030                 }
1031
1032                 System.out.println("Received: " + Integer.toString(recHeader.getType()));
1033
1034                 switch (recHeader.getType()) {
1035                 case 3:
1036                         DeviceStateService dat = parseDeviceStateServiceMessage(recHeader, payloadBytes);
1037                         // System.out.println("Service: " + Integer.toString(dat.getService()));
1038                         // System.out.println("Port   : " + Long.toString(dat.getPort()));
1039                         break;
1040
1041
1042                 case 33:
1043                         handleStateVersionMessageRecieved(recHeader, payloadBytes);
1044                         break;
1045
1046                 case 35:
1047                         parseDeviceStateInfoMessage(recHeader, payloadBytes);
1048                         break;
1049
1050
1051                 case 107:
1052                         handleLightStateMessageRecieved(recHeader, payloadBytes);
1053                         break;
1054
1055                 default:
1056                         // System.out.println("unknown packet Type");
1057                 }
1058
1059         }
1060
1061         private void sendPacket(byte[] packetData) {
1062                 // System.out.println("About to send");
1063                 sendSocketFlag = true;
1064
1065                 try {
1066                         socketMutex.acquire();
1067                 } catch (InterruptedException e) {
1068                         System.out.println("mutex Error");
1069                 }
1070
1071                 try {
1072                         communicationSockect.sendData(packetData);
1073
1074                 } catch (IOException e) {
1075                         System.out.println("Socket Send Error");
1076                 }
1077
1078                 sendSocketFlag = false;
1079                 socketMutex.release();
1080         }
1081
1082
1083         /**
1084          *   Worker function which runs the while loop for receiving data from the bulb.
1085          *   Is blocking
1086          */
1087         private void workerFunction() {
1088                 LifxHeader h = new LifxHeader();
1089
1090                 try {
1091                         // Need timeout on receives since we are not sure if a packet will be available
1092                         // for processing so don't block waiting
1093                         communicationSockect.setSoTimeout(50);
1094                 } catch (IOException e) {
1095                 }
1096
1097                 // Start the bulb in the off state
1098                 turnOff();
1099
1100
1101                 while (true) {
1102
1103                         // Check if we got the bulb version yet
1104                         // could have requested it but message could have gotten lost (UDP)
1105                         if (!didGetBulbVersion.get()) {
1106                                 long currentTime = (new Date().getTime()) / 1000;
1107                                 if ((currentTime - lastSentGetBulbVersionRequest) > GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
1108                                         // Get the bulb version so we know what type of bulb this is.
1109                                         sendGetVersionPacket();
1110                                         lastSentGetBulbVersionRequest = currentTime;
1111                                 }
1112                         }
1113
1114                         // Communication resource is busy so try again later
1115                         if (sendSocketFlag) {
1116                                 continue;
1117                         }
1118
1119                         try {
1120                                 socketMutex.acquire();
1121                         } catch (InterruptedException e) {
1122                         }
1123
1124                         byte[] dat = null;
1125                         try {
1126                                 dat = communicationSockect.recieveData(1024);
1127                         } catch (java.net.SocketTimeoutException e) {
1128                                 // Timeout occurred
1129
1130                         } catch (IOException e) {
1131                                 // Problem but might be able to recover??
1132                                 e.printStackTrace();
1133
1134                         }
1135
1136                         // Never forget to release!
1137                         socketMutex.release();
1138
1139                         // A packed arrived
1140                         if (dat != null) {
1141                                 recievedPacket(dat);
1142                         }
1143
1144                         // If a state change occurred then request the bulb state to ensure that the
1145                         // bulb did indeed change its state to the correct state
1146                         if (stateDidChange) {
1147                                 sendGetLightStatePacket();
1148                         }
1149
1150                         // Wait a bit as to not tie up system resources
1151                         try {
1152                                 Thread.sleep(100);
1153                         } catch (Exception e) {
1154
1155                         }
1156
1157
1158                 }
1159         }
1160
1161
1162         public void init() {
1163
1164                 if (didAlreadyInit.compareAndSet(false, true) == false) {
1165                         return; // already init
1166                 }
1167
1168                 try {
1169                         // Get the bulb address from the IoTSet
1170                         Iterator itr = lb_addresses.iterator();
1171                         IoTDeviceAddress deviceAddress = (IoTDeviceAddress)itr.next();
1172
1173                         System.out.println("Address: " + deviceAddress.getCompleteAddress());
1174
1175                         // Create the communication channel
1176                         communicationSockect = new IoTUDP(deviceAddress);
1177
1178                 } catch (IOException e) {
1179                         e.printStackTrace();
1180                 }
1181
1182                 // Launch the worker function in a separate thread.
1183                 workerThread = new Thread(new Runnable() {
1184                         public void run() {
1185                                 workerFunction();
1186                         }
1187                 });
1188                 workerThread.start();
1189
1190         }
1191 }
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211