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