f073df8f24a7b17ce5118ac5c1f97d8bc861446d
[iot2.git] / benchmarks / SmartLightsController / SmartLightsController.java
1 package SmartLightsController;
2
3 // IoT Runtime packages
4 import iotruntime.slave.IoTSet;
5 import iotruntime.slave.IoTRelation;
6
7 // IoT driver packages
8 import iotcode.interfaces.*;
9 import iotcode.annotation.*;
10
11
12 // Standard Java packages
13 import java.util.HashMap;
14 import java.util.Map;
15 import java.util.Date;  // TODO: Get rid of all depreciated stuff for date, switch to Calender
16 import java.util.concurrent.Semaphore;
17
18 // RMI packages
19 import java.rmi.RemoteException;
20
21 // Checker annotations
22 //import iotchecker.qual.*;
23
24 /** Class Smart Lights Controller for the smart home application benchmark
25  *
26  * @author      Ali Younis <ayounis @ uci.edu>
27  * @version     1.0
28  * @since       2016-01-27
29  */
30 public class SmartLightsController {
31
32         /*
33          *  Constants
34          */
35         public static final int MOTION_TIME_THRESHOLD = 60;     // in seconds
36         public static final int CHECK_TIME_WAIT = 1;                    // in seconds
37         public static final int COLOR_TEMP_MIN_KELVIN = 2500;   // In Kelvin
38         public static final int COLOR_TEMP_MAX_KELVIN = 9000;   // In Kelvin
39         public static final int CAMERA_FPS = 15;                                // In frames per second
40
41         /*
42          *  IoT Sets of Devices
43          */
44         @config private IoTSet<LightBulbSmart> mainRoomLightBulbs;
45         @config private IoTSet<CameraSmart> cameras;
46
47
48         /*
49          *  IoT Sets of Things that are not devices such as rooms
50          */
51         @config private IoTSet<Room> rooms;
52
53         /*
54          *  IoT Relations
55          */
56         @config private IoTRelation<Room,CameraSmart> roomCameraRel;
57         @config private IoTRelation<Room,LightBulbSmart> roomMainBulbRel;
58
59
60         /*
61          *  The state that the room main lights are supposed to be in
62          */
63         Map<Room, Boolean> roomLightOnOffStatus =
64                 new HashMap<Room, Boolean>();
65         Map<Room, ColorTemperature> roomLightColorTemperature =
66                 new HashMap<Room, ColorTemperature>();
67
68         /*
69          *  Motion detectors that are bound to specific cameras
70          */
71         private Map<CameraSmart, MotionDetection>
72         camMotionDetect = new HashMap<CameraSmart, MotionDetection>();
73
74
75         /*******************************************************************************************************************************************
76         **
77         **  Variables
78         **
79         *******************************************************************************************************************************************/
80         long lastTimeChecked = 0;
81
82         boolean print830 = true;
83         boolean print1030 = true;
84         boolean print730 = true;
85         boolean print930 = true;
86         boolean printNite = true;
87
88         /*******************************************************************************************************************************************
89         **
90         ** Private Helper Methods
91         **
92         *******************************************************************************************************************************************/
93
94         /** Method to detect if a room has seen motion within the last few seconds (time specified as parameter).
95          *   Checks all the motion detectors for the given room
96          *
97          *   @param _room            [Room] , Room of interest.
98          *   @param _numberOfSeconds [int]  , Number of seconds in the past that we consider recent.
99          *   @param _upperThreshold  [int]  , Number of seconds as an upper bound before we turn off.
100          *
101          *   @return [boolean] if motion was detected recently.
102          */
103         private boolean roomDidHaveMotionRecently(Room _room, int _numberOfSeconds) {
104                 long currentTimeSeconds = (new Date()).getTime() / 1000;
105
106                 // Loop through all the motion sensors in the room
107                 for (CameraSmart cam : roomCameraRel.get(_room)) {
108                         long lastDetectedMotionSeconds = currentTimeSeconds;
109
110                         Date motionTime = ((MotionDetection)camMotionDetect.get(cam)).getTimestampOfLastMotion();
111
112                         // Motion was detected at least once
113                         if (motionTime != null) {
114                                 lastDetectedMotionSeconds = motionTime.getTime() / 1000;
115                         } else {
116                                 // motionTime == null means this is the initialization phase
117                                 // so we return false to initialize the lightbulbs to off
118                                 return false;
119                         }
120
121                         // Did detect motion recently
122                         if (Math.abs(currentTimeSeconds - lastDetectedMotionSeconds) < _numberOfSeconds) {
123                                 return true;
124                         }
125                 }
126
127                 return false;
128         }
129
130
131
132         /**  Set the temperature of the room based on the time of day.
133          *  Do this to make sure people are able to get a good nights sleep.
134          *  based on this: https://justgetflux.com/research.html
135          *
136          *   @return [void] None;
137          */
138         private void setRoomColorTemperatureForSleep() throws RemoteException {
139
140                 long currentTimeSeconds = (new Date()).getTime() / 1000;
141                 Date today = new Date();
142                 Date beginningOfToday = new Date(today.getYear(),
143                         today.getMonth(), today.getDate());
144
145                 long secondsSinceStartOfDay = currentTimeSeconds - (beginningOfToday.getTime() / 1000);
146
147                 for (Room room : rooms.values()) {
148
149                         // before 8:30 am
150                         if (secondsSinceStartOfDay <= 30600) {
151                                 ColorTemperature colTemp = roomLightColorTemperature.get(room);
152                                 colTemp.temperature = COLOR_TEMP_MIN_KELVIN;
153                                 roomLightColorTemperature.put(room, colTemp);
154
155                                 if (print830) {
156                                         System.out.println("Before 8:30am!");
157                                         System.out.println("Color temperature: " + colTemp.temperature);
158                                         print830 = false;
159                                         print1030 = true;
160                                         print730 = true;
161                                         print930 = true;
162                                         printNite = true;
163                                 }
164
165                         } else if ((secondsSinceStartOfDay > 30600) && (secondsSinceStartOfDay < 37800)) {
166                                 // 8:30am - 10:30 am
167                                 // Slowly turn lights from warm to work white
168                                 double newKelvinValue = (double) (secondsSinceStartOfDay - 30600) / (37800 - 30600);
169                                 newKelvinValue = (newKelvinValue * (COLOR_TEMP_MAX_KELVIN - COLOR_TEMP_MIN_KELVIN)) + COLOR_TEMP_MIN_KELVIN;
170                                 ColorTemperature colTemp = roomLightColorTemperature.get(room);
171                                 colTemp.temperature = (int)newKelvinValue;
172                                 roomLightColorTemperature.put(room, colTemp);
173
174                                 if (print1030) {
175                                         System.out.println("8:30am - 10:30am!");
176                                         print830 = true;
177                                         print1030 = false;
178                                         print730 = true;
179                                         print930 = true;
180                                         printNite = true;
181                                 }
182
183                         } else if ((secondsSinceStartOfDay > 37800 ) && (secondsSinceStartOfDay < 70200)) {
184                                 // Between 10:30am and 7:30pm
185                                 // Keep white Work Light
186                                 ColorTemperature colTemp = roomLightColorTemperature.get(room);
187                                 colTemp.temperature = COLOR_TEMP_MAX_KELVIN;
188                                 roomLightColorTemperature.put(room, colTemp);
189
190                                 if (print730) {
191                                         System.out.println("10:30am - 7:30pm!");
192                                         System.out.println("Color temperature: " + colTemp.temperature);
193                                         print830 = true;
194                                         print1030 = true;
195                                         print730 = false;
196                                         print930 = true;
197                                         printNite = true;
198                                 }
199
200                         } else if ((secondsSinceStartOfDay > 70200) && (secondsSinceStartOfDay < 77400)) {
201                                 // Between 7:30pm and 9:30pm
202                                 // Slowly turn lights from work to warm
203                                 double newKelvinValue = (double) (secondsSinceStartOfDay - 30600) / (37800 - 30600);
204                                 newKelvinValue = (newKelvinValue * (COLOR_TEMP_MAX_KELVIN - COLOR_TEMP_MIN_KELVIN)) + COLOR_TEMP_MIN_KELVIN;
205                                 ColorTemperature colTemp = roomLightColorTemperature.get(room);
206                                 colTemp.temperature = (int)newKelvinValue;
207                                 roomLightColorTemperature.put(room, colTemp);
208
209                                 if (print930) {
210                                         System.out.println("7:30pm - 9:30pm!");
211                                         print830 = true;
212                                         print1030 = true;
213                                         print730 = true;
214                                         print930 = false;
215                                         printNite = true;
216                                 }
217
218                         } else if (secondsSinceStartOfDay > 77400) {
219                                 // past 9:30pm
220                                 // Keep warm Light
221                                 ColorTemperature colTemp = roomLightColorTemperature.get(room);
222                                 colTemp.temperature = COLOR_TEMP_MIN_KELVIN;
223                                 roomLightColorTemperature.put(room, colTemp);
224
225                                 if (printNite) {
226                                         System.out.println("After 9:30pm!");
227                                         System.out.println("Color temperature: " + colTemp.temperature);
228                                         print830 = true;
229                                         print1030 = true;
230                                         print730 = true;
231                                         print930 = true;
232                                         printNite = false;
233                                 }
234                         }
235                 }
236         }
237
238
239
240         /** Sets bulbs to the proper state.  Sets the On/Off state as well as the color.
241          * The method changes the state of the bulb.  It does not calculate what the state
242          * of the bulb should be, this is done elsewhere.
243          *
244          * When setting the color of the bulb, a best attempt effort is made.  If the needed
245          * temperature and color of the bulb is outside the bulb range then the system gets
246          * as close as it can
247          *
248          *   @return [void] None;
249          */
250         private void setMainBulbs() throws RemoteException {
251
252                 for (Room room : rooms.values()) {
253
254                         // Lights in room should be turned off
255                         if (!roomLightOnOffStatus.get(room)) {
256
257                                 // turn the bulbs off if they are on
258                                 for (LightBulbSmart bulb : roomMainBulbRel.get(room)) {
259                                         if (bulb.getState()) {
260                                                 bulb.turnOff();
261                                                 System.out.println("SmartLightsController: Send off signal!!!");
262                                         }
263                                 }
264
265                         } else {
266
267                                 // Lights in room should be turned on
268                                 // set the color of the bulbs
269                                 ColorTemperature colTemp = roomLightColorTemperature.get(room);
270                                 for (LightBulbSmart bulb : roomMainBulbRel.get(room)) {
271                                         // Turn on the bulb if they are off
272                                         if (!bulb.getState()) {
273                                                 bulb.turnOn();
274                                                 System.out.println("SmartLightsController: Send on signal!!!");
275                                         }
276
277                                         // Get the requested color of the room
278                                         double hue = colTemp.hue;
279                                         double saturation = colTemp.saturation;
280                                         double brightness = colTemp.brightness;
281                                         int temperature = colTemp.temperature;
282
283                                         // Make sure hue is in range that light bulb supports
284                                         if (hue < bulb.getHueRangeLowerBound()) {
285                                                 hue = bulb.getHueRangeLowerBound();
286                                         } else if (hue > bulb.getHueRangeUpperBound()) {
287                                                 hue = bulb.getHueRangeUpperBound();
288                                         }
289
290                                         // Make sure saturation is in range that light bulb supports
291                                         if (saturation < bulb.getSaturationRangeLowerBound()) {
292                                                 saturation = bulb.getSaturationRangeLowerBound();
293                                         } else if (saturation > bulb.getSaturationRangeUpperBound()) {
294                                                 saturation = bulb.getSaturationRangeUpperBound();
295                                         }
296
297                                         // Make sure brightness is in range that light bulb supports
298                                         if (brightness < bulb.getBrightnessRangeLowerBound()) {
299                                                 brightness = bulb.getBrightnessRangeLowerBound();
300                                         } else if (brightness > bulb.getBrightnessRangeUpperBound()) {
301                                                 brightness = bulb.getBrightnessRangeUpperBound();
302                                         }
303
304                                         // Make sure temperature is in range that light bulb supports
305                                         if (temperature < bulb.getTemperatureRangeLowerBound()) {
306                                                 temperature = bulb.getTemperatureRangeLowerBound();
307                                         } else if (temperature > bulb.getTemperatureRangeUpperBound()) {
308                                                 temperature = bulb.getTemperatureRangeUpperBound();
309                                         }
310
311                                         // Actually set the bulb to that color and temp
312                                         bulb.setColor(hue, saturation, brightness);
313                                         bulb.setTemperature(temperature);
314                                 }
315                         }
316                 }
317         }
318
319
320         /********************************************************************************************************
321         ** Public methods, called by the runtime
322         *********************************************************************************************************/
323
324         /** Initialization method, called by the runtime (effectively the main of the controller)
325          *   This method runs a continuous loop and is blocking
326          *
327          *   @return [void] None;
328          */
329         public void init() throws RemoteException, InterruptedException {
330
331
332                 // Initialize the rooms
333                 for (Room room : rooms.values()) {
334
335                         // All rooms start with the lights turned off
336                         roomLightOnOffStatus.put(room, false);
337
338                         // All rooms have a default color and temperature
339                         roomLightColorTemperature.put(room, new ColorTemperature(0, 0, 100, 2500));
340                 }
341
342
343                 // Setup the cameras, start them all and assign each one a motion detector
344                 for (CameraSmart cam : cameras.values()) {
345
346                         // Each camera will have a motion detector unique to it since the motion detection has state
347                         MotionDetection mo = new MotionDetection(12, 0.5f, 10, 10);
348
349                         // initialize the camera, might need to setup some stuff internally
350                         cam.init();
351
352                         // set the camera parameters.
353                         cam.setFPS(CAMERA_FPS);
354                         cam.setResolution(Resolution.RES_VGA);
355
356                         // camera will call the motion detector directly with data not this controller
357                         cam.registerCallback(mo);
358
359                         // Start the camera (example is start the HTTP stream if it is a network camera)
360                         cam.start();
361
362                         // Remember which motion detector is for what camera
363                         camMotionDetect.put(cam, mo);
364                 }
365
366
367                 //Initialize the light-bulbs, will turn off the bulb
368                 for (LightBulbSmart bulb : mainRoomLightBulbs.values()) {
369                         bulb.init();
370                         Thread.sleep(1000);
371                 }
372
373                 // Run the main loop that will keep check the bulbs and rooms periodically
374                 while (true) {
375
376                         // Run this code every <specified time>
377                         long currentTimeSeconds = (new Date()).getTime() / 1000;
378                         if ((currentTimeSeconds - lastTimeChecked) > CHECK_TIME_WAIT) {
379                                 lastTimeChecked = currentTimeSeconds;
380
381                                 // Check for motion in rooms and if there is motion then turn on the lights
382                                 for (Room room : rooms.values()) {
383
384                                         if (roomDidHaveMotionRecently(room, MOTION_TIME_THRESHOLD)) {
385
386                                                 // Motion was detected
387                                                 roomLightOnOffStatus.put(room, true);
388
389                                         } else {
390
391                                                 // No motion was detected
392                                                 roomLightOnOffStatus.put(room, false);
393
394                                         }
395                                 }
396
397                                 // Check what the temperature of the light in the room should be
398                                 setRoomColorTemperatureForSleep();
399
400                                 // Set the bulbs to the new values
401                                 setMainBulbs();
402
403                         } else {
404                                 try {
405                                         Thread.sleep(CHECK_TIME_WAIT * 100); // sleep for a tenth of the time
406                                 } catch (Exception e) {
407
408                                 }
409                         }
410
411                 }
412         }
413 }
414
415
416
417