1 package SmartLightsController;
3 // IoT Runtime packages
4 import iotruntime.slave.IoTSet;
5 import iotruntime.slave.IoTRelation;
8 import iotcode.interfaces.*;
9 import iotcode.annotation.*;
12 // Standard Java packages
13 import java.util.HashMap;
15 import java.util.Date; // TODO: Get rid of all depreciated stuff for date, switch to Calender
16 import java.util.concurrent.Semaphore;
19 import java.rmi.RemoteException;
21 // Checker annotations
22 //import iotchecker.qual.*;
24 /** Class Smart Lights Controller for the smart home application benchmark
26 * @author Ali Younis <ayounis @ uci.edu>
30 public class SmartLightsController {
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
44 @config private IoTSet<LightBulbSmart> mainRoomLightBulbs;
45 @config private IoTSet<CameraSmart> cameras;
49 * IoT Sets of Things that are not devices such as rooms
51 @config private IoTSet<Room> rooms;
56 @config private IoTRelation<Room,CameraSmart> roomCameraRel;
57 @config private IoTRelation<Room,LightBulbSmart> roomMainBulbRel;
61 * The state that the room main lights are supposed to be in
63 Map<Room, Boolean> roomLightOnOffStatus =
64 new HashMap<Room, Boolean>();
65 Map<Room, ColorTemperature> roomLightColorTemperature =
66 new HashMap<Room, ColorTemperature>();
69 * Motion detectors that are bound to specific cameras
71 private Map<CameraSmart, MotionDetection>
72 camMotionDetect = new HashMap<CameraSmart, MotionDetection>();
75 /*******************************************************************************************************************************************
79 *******************************************************************************************************************************************/
80 long lastTimeChecked = 0;
82 boolean print830 = true;
83 boolean print1030 = true;
84 boolean print730 = true;
85 boolean print930 = true;
86 boolean printNite = true;
88 /*******************************************************************************************************************************************
90 ** Private Helper Methods
92 *******************************************************************************************************************************************/
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
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.
101 * @return [boolean] if motion was detected recently.
103 private boolean roomDidHaveMotionRecently(Room _room, int _numberOfSeconds) {
104 long currentTimeSeconds = (new Date()).getTime() / 1000;
106 // Loop through all the motion sensors in the room
107 for (CameraSmart cam : roomCameraRel.get(_room)) {
108 long lastDetectedMotionSeconds = currentTimeSeconds;
110 Date motionTime = ((MotionDetection)camMotionDetect.get(cam)).getTimestampOfLastMotion();
112 // Motion was detected at least once
113 if (motionTime != null) {
114 lastDetectedMotionSeconds = motionTime.getTime() / 1000;
116 // motionTime == null means this is the initialization phase
117 // so we return false to initialize the lightbulbs to off
121 // Did detect motion recently
122 if (Math.abs(currentTimeSeconds - lastDetectedMotionSeconds) < _numberOfSeconds) {
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
136 * @return [void] None;
138 private void setRoomColorTemperatureForSleep() throws RemoteException {
140 long currentTimeSeconds = (new Date()).getTime() / 1000;
141 Date today = new Date();
142 Date beginningOfToday = new Date(today.getYear(),
143 today.getMonth(), today.getDate());
145 long secondsSinceStartOfDay = currentTimeSeconds - (beginningOfToday.getTime() / 1000);
147 for (Room room : rooms.values()) {
150 if (secondsSinceStartOfDay <= 30600) {
151 ColorTemperature colTemp = roomLightColorTemperature.get(room);
152 colTemp.temperature = COLOR_TEMP_MIN_KELVIN;
153 roomLightColorTemperature.put(room, colTemp);
156 System.out.println("Before 8:30am!");
157 System.out.println("Color temperature: " + colTemp.temperature);
165 } else if ((secondsSinceStartOfDay > 30600) && (secondsSinceStartOfDay < 37800)) {
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);
175 System.out.println("8:30am - 10:30am!");
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);
191 System.out.println("10:30am - 7:30pm!");
192 System.out.println("Color temperature: " + colTemp.temperature);
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);
210 System.out.println("7:30pm - 9:30pm!");
218 } else if (secondsSinceStartOfDay > 77400) {
221 ColorTemperature colTemp = roomLightColorTemperature.get(room);
222 colTemp.temperature = COLOR_TEMP_MIN_KELVIN;
223 roomLightColorTemperature.put(room, colTemp);
226 System.out.println("After 9:30pm!");
227 System.out.println("Color temperature: " + colTemp.temperature);
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.
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
248 * @return [void] None;
250 private void setMainBulbs() throws RemoteException {
252 for (Room room : rooms.values()) {
254 // Lights in room should be turned off
255 if (!roomLightOnOffStatus.get(room)) {
257 // turn the bulbs off if they are on
258 for (LightBulbSmart bulb : roomMainBulbRel.get(room)) {
259 if (bulb.getState()) {
261 System.out.println("SmartLightsController: Send off signal!!!");
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()) {
274 System.out.println("SmartLightsController: Send on signal!!!");
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;
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();
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();
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();
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();
311 // Actually set the bulb to that color and temp
312 bulb.setColor(hue, saturation, brightness);
313 bulb.setTemperature(temperature);
320 /********************************************************************************************************
321 ** Public methods, called by the runtime
322 *********************************************************************************************************/
324 /** Initialization method, called by the runtime (effectively the main of the controller)
325 * This method runs a continuous loop and is blocking
327 * @return [void] None;
329 public void init() throws RemoteException, InterruptedException {
332 // Initialize the rooms
333 for (Room room : rooms.values()) {
335 // All rooms start with the lights turned off
336 roomLightOnOffStatus.put(room, false);
338 // All rooms have a default color and temperature
339 roomLightColorTemperature.put(room, new ColorTemperature(0, 0, 100, 2500));
343 // Setup the cameras, start them all and assign each one a motion detector
344 for (CameraSmart cam : cameras.values()) {
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);
349 // initialize the camera, might need to setup some stuff internally
352 // set the camera parameters.
353 cam.setFPS(CAMERA_FPS);
354 cam.setResolution(Resolution.RES_VGA);
356 // camera will call the motion detector directly with data not this controller
357 cam.registerCallback(mo);
359 // Start the camera (example is start the HTTP stream if it is a network camera)
362 // Remember which motion detector is for what camera
363 camMotionDetect.put(cam, mo);
367 //Initialize the light-bulbs, will turn off the bulb
368 for (LightBulbSmart bulb : mainRoomLightBulbs.values()) {
373 // Run the main loop that will keep check the bulbs and rooms periodically
376 // Run this code every <specified time>
377 long currentTimeSeconds = (new Date()).getTime() / 1000;
378 if ((currentTimeSeconds - lastTimeChecked) > CHECK_TIME_WAIT) {
379 lastTimeChecked = currentTimeSeconds;
381 // Check for motion in rooms and if there is motion then turn on the lights
382 for (Room room : rooms.values()) {
384 if (roomDidHaveMotionRecently(room, MOTION_TIME_THRESHOLD)) {
386 // Motion was detected
387 roomLightOnOffStatus.put(room, true);
391 // No motion was detected
392 roomLightOnOffStatus.put(room, false);
397 // Check what the temperature of the light in the room should be
398 setRoomColorTemperatureForSleep();
400 // Set the bulbs to the new values
405 Thread.sleep(CHECK_TIME_WAIT * 100); // sleep for a tenth of the time
406 } catch (Exception e) {