package SmartLightsController; // IoT Runtime packages import iotruntime.slave.IoTSet; import iotruntime.slave.IoTRelation; // IoT driver packages import iotcode.interfaces.*; import iotcode.annotation.*; // Standard Java packages import java.util.HashMap; import java.util.Map; import java.util.Date; // TODO: Get rid of all depreciated stuff for date, switch to Calender import java.util.concurrent.Semaphore; // RMI packages import java.rmi.RemoteException; // Checker annotations //import iotchecker.qual.*; /** Class Smart Lights Controller for the smart home application benchmark * * @author Ali Younis * @version 1.0 * @since 2016-01-27 */ public class SmartLightsController { /* * Constants */ public static final int MOTION_TIME_THRESHOLD = 60; // in seconds public static final int CHECK_TIME_WAIT = 1; // in seconds public static final int COLOR_TEMP_MIN_KELVIN = 2500; // In Kelvin public static final int COLOR_TEMP_MAX_KELVIN = 9000; // In Kelvin public static final int CAMERA_FPS = 15; // In frames per second /* * IoT Sets of Devices */ @config private IoTSet mainRoomLightBulbs; @config private IoTSet cameras; /* * IoT Sets of Things that are not devices such as rooms */ @config private IoTSet rooms; /* * IoT Relations */ @config private IoTRelation roomCameraRel; @config private IoTRelation roomMainBulbRel; /* * The state that the room main lights are supposed to be in */ Map roomLightOnOffStatus = new HashMap(); Map roomLightColorTemperature = new HashMap(); /* * Motion detectors that are bound to specific cameras */ private Map camMotionDetect = new HashMap(); /******************************************************************************************************************************************* ** ** Variables ** *******************************************************************************************************************************************/ long lastTimeChecked = 0; boolean print830 = true; boolean print1030 = true; boolean print730 = true; boolean print930 = true; boolean printNite = true; /******************************************************************************************************************************************* ** ** Private Helper Methods ** *******************************************************************************************************************************************/ /** Method to detect if a room has seen motion within the last few seconds (time specified as parameter). * Checks all the motion detectors for the given room * * @param _room [RoomSmart] , RoomSmart of interest. * @param _numberOfSeconds [int] , Number of seconds in the past that we consider recent. * @param _upperThreshold [int] , Number of seconds as an upper bound before we turn off. * * @return [boolean] if motion was detected recently. */ private boolean roomDidHaveMotionRecently(RoomSmart _room, int _numberOfSeconds) { long currentTimeSeconds = (new Date()).getTime() / 1000; // Loop through all the motion sensors in the room for (CameraSmart cam : roomCameraRel.get(_room)) { long lastDetectedMotionSeconds = currentTimeSeconds; Date motionTime = ((MotionDetection)camMotionDetect.get(cam)).getTimestampOfLastMotion(); // Motion was detected at least once if (motionTime != null) { lastDetectedMotionSeconds = motionTime.getTime() / 1000; } else { // motionTime == null means this is the initialization phase // so we return false to initialize the lightbulbs to off return false; } // Did detect motion recently if (Math.abs(currentTimeSeconds - lastDetectedMotionSeconds) < _numberOfSeconds) { return true; } } return false; } /** Set the temperature of the room based on the time of day. * Do this to make sure people are able to get a good nights sleep. * based on this: https://justgetflux.com/research.html * * @return [void] None; */ private void setRoomColorTemperatureForSleep() throws RemoteException { long currentTimeSeconds = (new Date()).getTime() / 1000; Date today = new Date(); Date beginningOfToday = new Date(today.getYear(), today.getMonth(), today.getDate()); long secondsSinceStartOfDay = currentTimeSeconds - (beginningOfToday.getTime() / 1000); for (RoomSmart room : rooms.values()) { // before 8:30 am if (secondsSinceStartOfDay <= 30600) { ColorTemperature colTemp = roomLightColorTemperature.get(room); colTemp.temperature = COLOR_TEMP_MIN_KELVIN; roomLightColorTemperature.put(room, colTemp); if (print830) { System.out.println("Before 8:30am!"); System.out.println("Color temperature: " + colTemp.temperature); print830 = false; print1030 = true; print730 = true; print930 = true; printNite = true; } } else if ((secondsSinceStartOfDay > 30600) && (secondsSinceStartOfDay < 37800)) { // 8:30am - 10:30 am // Slowly turn lights from warm to work white double newKelvinValue = (double) (secondsSinceStartOfDay - 30600) / (37800 - 30600); newKelvinValue = (newKelvinValue * (COLOR_TEMP_MAX_KELVIN - COLOR_TEMP_MIN_KELVIN)) + COLOR_TEMP_MIN_KELVIN; ColorTemperature colTemp = roomLightColorTemperature.get(room); colTemp.temperature = (int)newKelvinValue; roomLightColorTemperature.put(room, colTemp); if (print1030) { System.out.println("8:30am - 10:30am!"); print830 = true; print1030 = false; print730 = true; print930 = true; printNite = true; } } else if ((secondsSinceStartOfDay > 37800 ) && (secondsSinceStartOfDay < 70200)) { // Between 10:30am and 7:30pm // Keep white Work Light ColorTemperature colTemp = roomLightColorTemperature.get(room); colTemp.temperature = COLOR_TEMP_MAX_KELVIN; roomLightColorTemperature.put(room, colTemp); if (print730) { System.out.println("10:30am - 7:30pm!"); System.out.println("Color temperature: " + colTemp.temperature); print830 = true; print1030 = true; print730 = false; print930 = true; printNite = true; } } else if ((secondsSinceStartOfDay > 70200) && (secondsSinceStartOfDay < 77400)) { // Between 7:30pm and 9:30pm // Slowly turn lights from work to warm double newKelvinValue = (double) (secondsSinceStartOfDay - 30600) / (37800 - 30600); newKelvinValue = (newKelvinValue * (COLOR_TEMP_MAX_KELVIN - COLOR_TEMP_MIN_KELVIN)) + COLOR_TEMP_MIN_KELVIN; ColorTemperature colTemp = roomLightColorTemperature.get(room); colTemp.temperature = (int)newKelvinValue; roomLightColorTemperature.put(room, colTemp); if (print930) { System.out.println("7:30pm - 9:30pm!"); print830 = true; print1030 = true; print730 = true; print930 = false; printNite = true; } } else if (secondsSinceStartOfDay > 77400) { // past 9:30pm // Keep warm Light ColorTemperature colTemp = roomLightColorTemperature.get(room); colTemp.temperature = COLOR_TEMP_MIN_KELVIN; roomLightColorTemperature.put(room, colTemp); if (printNite) { System.out.println("After 9:30pm!"); System.out.println("Color temperature: " + colTemp.temperature); print830 = true; print1030 = true; print730 = true; print930 = true; printNite = false; } } } } /** Sets bulbs to the proper state. Sets the On/Off state as well as the color. * The method changes the state of the bulb. It does not calculate what the state * of the bulb should be, this is done elsewhere. * * When setting the color of the bulb, a best attempt effort is made. If the needed * temperature and color of the bulb is outside the bulb range then the system gets * as close as it can * * @return [void] None; */ private void setMainBulbs() throws RemoteException { for (RoomSmart room : rooms.values()) { // Lights in room should be turned off if (!roomLightOnOffStatus.get(room)) { // turn the bulbs off if they are on for (LightBulbSmart bulb : roomMainBulbRel.get(room)) { if (bulb.getState()) { bulb.turnOff(); System.out.println("SmartLightsController: Send off signal!!!"); } } } else { // Lights in room should be turned on // set the color of the bulbs ColorTemperature colTemp = roomLightColorTemperature.get(room); for (LightBulbSmart bulb : roomMainBulbRel.get(room)) { // Turn on the bulb if they are off if (!bulb.getState()) { bulb.turnOn(); System.out.println("SmartLightsController: Send on signal!!!"); } // Get the requested color of the room double hue = colTemp.hue; double saturation = colTemp.saturation; double brightness = colTemp.brightness; int temperature = colTemp.temperature; // Make sure hue is in range that light bulb supports if (hue < bulb.getHueRangeLowerBound()) { hue = bulb.getHueRangeLowerBound(); } else if (hue > bulb.getHueRangeUpperBound()) { hue = bulb.getHueRangeUpperBound(); } // Make sure saturation is in range that light bulb supports if (saturation < bulb.getSaturationRangeLowerBound()) { saturation = bulb.getSaturationRangeLowerBound(); } else if (saturation > bulb.getSaturationRangeUpperBound()) { saturation = bulb.getSaturationRangeUpperBound(); } // Make sure brightness is in range that light bulb supports if (brightness < bulb.getBrightnessRangeLowerBound()) { brightness = bulb.getBrightnessRangeLowerBound(); } else if (brightness > bulb.getBrightnessRangeUpperBound()) { brightness = bulb.getBrightnessRangeUpperBound(); } // Make sure temperature is in range that light bulb supports if (temperature < bulb.getTemperatureRangeLowerBound()) { temperature = bulb.getTemperatureRangeLowerBound(); } else if (temperature > bulb.getTemperatureRangeUpperBound()) { temperature = bulb.getTemperatureRangeUpperBound(); } // Actually set the bulb to that color and temp bulb.setColor(hue, saturation, brightness); bulb.setTemperature(temperature); } } } } /******************************************************************************************************** ** Public methods, called by the runtime *********************************************************************************************************/ /** Initialization method, called by the runtime (effectively the main of the controller) * This method runs a continuous loop and is blocking * * @return [void] None; */ public void init() throws RemoteException, InterruptedException { System.out.println("Initialized init()!"); // Initialize the rooms for (RoomSmart room : rooms.values()) { // All rooms start with the lights turned off roomLightOnOffStatus.put(room, false); // All rooms have a default color and temperature roomLightColorTemperature.put(room, new ColorTemperature(0, 0, 100, 2500)); } System.out.println("Initialized rooms!"); // Setup the cameras, start them all and assign each one a motion detector for (CameraSmart cam : cameras.values()) { // Each camera will have a motion detector unique to it since the motion detection has state MotionDetection mo = new MotionDetection(12, 0.5f, 10, 10); System.out.println("Motion detection initialized!"); // initialize the camera, might need to setup some stuff internally cam.init(); System.out.println("Initialized cam!"); // set the camera parameters. cam.setFPS(CAMERA_FPS); System.out.println("Set FPS!"); cam.setResolution(Resolution.RES_VGA); System.out.println("Set RES_VGA!"); // camera will call the motion detector directly with data not this controller cam.registerCallback(mo); System.out.println("Register callback!"); // Start the camera (example is start the HTTP stream if it is a network camera) cam.start(); System.out.println("Cam start!"); // Remember which motion detector is for what camera camMotionDetect.put(cam, mo); } System.out.println("Initialized cameras!"); //Initialize the light-bulbs, will turn off the bulb for (LightBulbSmart bulb : mainRoomLightBulbs.values()) { System.out.println("Trying to init bulb?"); bulb.init(); System.out.println("Done init!"); Thread.sleep(1000); } System.out.println("Initialized bulbs!"); // Run the main loop that will keep check the bulbs and rooms periodically while (true) { // Run this code every long currentTimeSeconds = (new Date()).getTime() / 1000; if ((currentTimeSeconds - lastTimeChecked) > CHECK_TIME_WAIT) { lastTimeChecked = currentTimeSeconds; // Check for motion in rooms and if there is motion then turn on the lights for (RoomSmart room : rooms.values()) { if (roomDidHaveMotionRecently(room, MOTION_TIME_THRESHOLD)) { // Motion was detected roomLightOnOffStatus.put(room, true); } else { // No motion was detected roomLightOnOffStatus.put(room, false); } } // Check what the temperature of the light in the room should be setRoomColorTemperatureForSleep(); // Set the bulbs to the new values setMainBulbs(); } else { try { Thread.sleep(CHECK_TIME_WAIT * 100); // sleep for a tenth of the time } catch (Exception e) { } } } } }