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;
48 * IoT Sets of Things that are not devices such as rooms
50 @config private IoTSet<RoomSmart> rooms;
55 @config private IoTRelation<RoomSmart,CameraSmart> roomCameraRel;
56 @config private IoTRelation<RoomSmart,LightBulbSmart> roomMainBulbRel;
60 * The state that the room main lights are supposed to be in
62 Map<RoomSmart, Boolean> roomLightOnOffStatus =
63 new HashMap<RoomSmart, Boolean>();
64 Map<RoomSmart, ColorTemperature> roomLightColorTemperature =
65 new HashMap<RoomSmart, ColorTemperature>();
68 * Motion detectors that are bound to specific cameras
70 private Map<CameraSmart, MotionDetection>
71 camMotionDetect = new HashMap<CameraSmart, MotionDetection>();
74 /*******************************************************************************************************************************************
78 *******************************************************************************************************************************************/
79 long lastTimeChecked = 0;
81 boolean print830 = true;
82 boolean print1030 = true;
83 boolean print730 = true;
84 boolean print930 = true;
85 boolean printNite = true;
87 /*******************************************************************************************************************************************
89 ** Private Helper Methods
91 *******************************************************************************************************************************************/
93 /** Method to detect if a room has seen motion within the last few seconds (time specified as parameter).
94 * Checks all the motion detectors for the given room
96 * @param _room [RoomSmart] , RoomSmart of interest.
97 * @param _numberOfSeconds [int] , Number of seconds in the past that we consider recent.
98 * @param _upperThreshold [int] , Number of seconds as an upper bound before we turn off.
100 * @return [boolean] if motion was detected recently.
102 private boolean roomDidHaveMotionRecently(RoomSmart _room, int _numberOfSeconds) {
103 long currentTimeSeconds = (new Date()).getTime() / 1000;
105 // Loop through all the motion sensors in the room
106 for (CameraSmart cam : roomCameraRel.get(_room)) {
107 long lastDetectedMotionSeconds = currentTimeSeconds;
109 Date motionTime = ((MotionDetection)camMotionDetect.get(cam)).getTimestampOfLastMotion();
111 // Motion was detected at least once
112 if (motionTime != null) {
113 lastDetectedMotionSeconds = motionTime.getTime() / 1000;
115 // motionTime == null means this is the initialization phase
116 // so we return false to initialize the lightbulbs to off
120 // Did detect motion recently
121 if (Math.abs(currentTimeSeconds - lastDetectedMotionSeconds) < _numberOfSeconds) {
131 /** Set the temperature of the room based on the time of day.
132 * Do this to make sure people are able to get a good nights sleep.
133 * based on this: https://justgetflux.com/research.html
135 * @return [void] None;
137 private void setRoomColorTemperatureForSleep() throws RemoteException {
139 long currentTimeSeconds = (new Date()).getTime() / 1000;
140 Date today = new Date();
141 Date beginningOfToday = new Date(today.getYear(),
142 today.getMonth(), today.getDate());
144 long secondsSinceStartOfDay = currentTimeSeconds - (beginningOfToday.getTime() / 1000);
146 for (RoomSmart room : rooms.values()) {
149 if (secondsSinceStartOfDay <= 30600) {
150 ColorTemperature colTemp = roomLightColorTemperature.get(room);
151 colTemp.temperature = COLOR_TEMP_MIN_KELVIN;
152 roomLightColorTemperature.put(room, colTemp);
155 System.out.println("Before 8:30am!");
156 System.out.println("Color temperature: " + colTemp.temperature);
164 } else if ((secondsSinceStartOfDay > 30600) && (secondsSinceStartOfDay < 37800)) {
166 // Slowly turn lights from warm to work white
167 double newKelvinValue = (double) (secondsSinceStartOfDay - 30600) / (37800 - 30600);
168 newKelvinValue = (newKelvinValue * (COLOR_TEMP_MAX_KELVIN - COLOR_TEMP_MIN_KELVIN)) + COLOR_TEMP_MIN_KELVIN;
169 ColorTemperature colTemp = roomLightColorTemperature.get(room);
170 colTemp.temperature = (int)newKelvinValue;
171 roomLightColorTemperature.put(room, colTemp);
174 System.out.println("8:30am - 10:30am!");
182 } else if ((secondsSinceStartOfDay > 37800 ) && (secondsSinceStartOfDay < 70200)) {
183 // Between 10:30am and 7:30pm
184 // Keep white Work Light
185 ColorTemperature colTemp = roomLightColorTemperature.get(room);
186 colTemp.temperature = COLOR_TEMP_MAX_KELVIN;
187 roomLightColorTemperature.put(room, colTemp);
190 System.out.println("10:30am - 7:30pm!");
191 System.out.println("Color temperature: " + colTemp.temperature);
199 } else if ((secondsSinceStartOfDay > 70200) && (secondsSinceStartOfDay < 77400)) {
200 // Between 7:30pm and 9:30pm
201 // Slowly turn lights from work to warm
202 double newKelvinValue = (double) (secondsSinceStartOfDay - 30600) / (37800 - 30600);
203 newKelvinValue = (newKelvinValue * (COLOR_TEMP_MAX_KELVIN - COLOR_TEMP_MIN_KELVIN)) + COLOR_TEMP_MIN_KELVIN;
204 ColorTemperature colTemp = roomLightColorTemperature.get(room);
205 colTemp.temperature = (int)newKelvinValue;
206 roomLightColorTemperature.put(room, colTemp);
209 System.out.println("7:30pm - 9:30pm!");
217 } else if (secondsSinceStartOfDay > 77400) {
220 ColorTemperature colTemp = roomLightColorTemperature.get(room);
221 colTemp.temperature = COLOR_TEMP_MIN_KELVIN;
222 roomLightColorTemperature.put(room, colTemp);
225 System.out.println("After 9:30pm!");
226 System.out.println("Color temperature: " + colTemp.temperature);
239 /** Sets bulbs to the proper state. Sets the On/Off state as well as the color.
240 * The method changes the state of the bulb. It does not calculate what the state
241 * of the bulb should be, this is done elsewhere.
243 * When setting the color of the bulb, a best attempt effort is made. If the needed
244 * temperature and color of the bulb is outside the bulb range then the system gets
247 * @return [void] None;
249 private void setMainBulbs() throws RemoteException {
251 for (RoomSmart room : rooms.values()) {
253 // Lights in room should be turned off
254 if (!roomLightOnOffStatus.get(room)) {
256 // turn the bulbs off if they are on
257 for (LightBulbSmart bulb : roomMainBulbRel.get(room)) {
258 if (bulb.getState()) {
260 System.out.println("SmartLightsController: Send off signal!!!");
266 // Lights in room should be turned on
267 // set the color of the bulbs
268 ColorTemperature colTemp = roomLightColorTemperature.get(room);
269 for (LightBulbSmart bulb : roomMainBulbRel.get(room)) {
270 // Turn on the bulb if they are off
271 if (!bulb.getState()) {
273 System.out.println("SmartLightsController: Send on signal!!!");
276 // Get the requested color of the room
277 double hue = colTemp.hue;
278 double saturation = colTemp.saturation;
279 double brightness = colTemp.brightness;
280 int temperature = colTemp.temperature;
282 // Make sure hue is in range that light bulb supports
283 if (hue < bulb.getHueRangeLowerBound()) {
284 hue = bulb.getHueRangeLowerBound();
285 } else if (hue > bulb.getHueRangeUpperBound()) {
286 hue = bulb.getHueRangeUpperBound();
289 // Make sure saturation is in range that light bulb supports
290 if (saturation < bulb.getSaturationRangeLowerBound()) {
291 saturation = bulb.getSaturationRangeLowerBound();
292 } else if (saturation > bulb.getSaturationRangeUpperBound()) {
293 saturation = bulb.getSaturationRangeUpperBound();
296 // Make sure brightness is in range that light bulb supports
297 if (brightness < bulb.getBrightnessRangeLowerBound()) {
298 brightness = bulb.getBrightnessRangeLowerBound();
299 } else if (brightness > bulb.getBrightnessRangeUpperBound()) {
300 brightness = bulb.getBrightnessRangeUpperBound();
303 // Make sure temperature is in range that light bulb supports
304 if (temperature < bulb.getTemperatureRangeLowerBound()) {
305 temperature = bulb.getTemperatureRangeLowerBound();
306 } else if (temperature > bulb.getTemperatureRangeUpperBound()) {
307 temperature = bulb.getTemperatureRangeUpperBound();
310 // Actually set the bulb to that color and temp
311 bulb.setColor(hue, saturation, brightness);
312 bulb.setTemperature(temperature);
319 /********************************************************************************************************
320 ** Public methods, called by the runtime
321 *********************************************************************************************************/
323 /** Initialization method, called by the runtime (effectively the main of the controller)
324 * This method runs a continuous loop and is blocking
326 * @return [void] None;
328 public void init() throws RemoteException, InterruptedException {
330 System.out.println("Initialized init()!");
331 // Initialize the rooms
332 for (RoomSmart room : rooms.values()) {
334 // All rooms start with the lights turned off
335 roomLightOnOffStatus.put(room, false);
337 // All rooms have a default color and temperature
338 roomLightColorTemperature.put(room, new ColorTemperature(0, 0, 100, 2500));
340 System.out.println("Initialized rooms!");
342 // Setup the cameras, start them all and assign each one a motion detector
343 for (CameraSmart cam : cameras.values()) {
345 // Each camera will have a motion detector unique to it since the motion detection has state
346 MotionDetection mo = new MotionDetection(12, 0.5f, 10, 10);
348 // initialize the camera, might need to setup some stuff internally
351 // set the camera parameters.
352 cam.setFPS(CAMERA_FPS);
353 cam.setResolution(Resolution.RES_VGA);
355 // camera will call the motion detector directly with data not this controller
356 cam.registerCallback(mo);
358 // Start the camera (example is start the HTTP stream if it is a network camera)
361 // Remember which motion detector is for what camera
362 camMotionDetect.put(cam, mo);
364 System.out.println("Initialized cameras!");
366 //Initialize the light-bulbs, will turn off the bulb
367 for (LightBulbSmart bulb : mainRoomLightBulbs.values()) {
368 System.out.println("Trying to init bulb?");
370 System.out.println("Done init!");
373 System.out.println("Initialized bulbs!");
375 // Run the main loop that will keep check the bulbs and rooms periodically
378 // Run this code every <specified time>
379 long currentTimeSeconds = (new Date()).getTime() / 1000;
380 if ((currentTimeSeconds - lastTimeChecked) > CHECK_TIME_WAIT) {
381 lastTimeChecked = currentTimeSeconds;
383 // Check for motion in rooms and if there is motion then turn on the lights
384 for (RoomSmart room : rooms.values()) {
386 if (roomDidHaveMotionRecently(room, MOTION_TIME_THRESHOLD)) {
388 // Motion was detected
389 roomLightOnOffStatus.put(room, true);
393 // No motion was detected
394 roomLightOnOffStatus.put(room, false);
399 // Check what the temperature of the light in the room should be
400 setRoomColorTemperatureForSleep();
402 // Set the bulbs to the new values
407 Thread.sleep(CHECK_TIME_WAIT * 100); // sleep for a tenth of the time
408 } catch (Exception e) {