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