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