--- /dev/null
+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 <ayounis @ uci.edu>
+ * @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<LightBulbSmart> mainRoomLightBulbs;
+ @config private IoTSet<CameraSmart> cameras;
+
+ /*
+ * IoT Sets of Things that are not devices such as rooms
+ */
+ @config private IoTSet<RoomSmart> rooms;
+
+ /*
+ * IoT Relations
+ */
+ @config private IoTRelation<RoomSmart,CameraSmart> roomCameraRel;
+ @config private IoTRelation<RoomSmart,LightBulbSmart> roomMainBulbRel;
+
+
+ /*
+ * The state that the room main lights are supposed to be in
+ */
+ Map<RoomSmart, Boolean> roomLightOnOffStatus =
+ new HashMap<RoomSmart, Boolean>();
+ Map<RoomSmart, ColorTemperature> roomLightColorTemperature =
+ new HashMap<RoomSmart, ColorTemperature>();
+
+ /*
+ * Motion detectors that are bound to specific cameras
+ */
+ private Map<CameraSmart, MotionDetection>
+ camMotionDetect = new HashMap<CameraSmart, MotionDetection>();
+
+
+ /*******************************************************************************************************************************************
+ **
+ ** 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);
+
+ // initialize the camera, might need to setup some stuff internally
+ cam.init();
+
+ // set the camera parameters.
+ cam.setFPS(CAMERA_FPS);
+ cam.setResolution(Resolution.RES_VGA);
+
+ // camera will call the motion detector directly with data not this controller
+ cam.registerCallback(mo);
+
+ // Start the camera (example is start the HTTP stream if it is a network camera)
+ 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 <specified time>
+ 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) {
+
+ }
+ }
+
+ }
+ }
+}
+
+
+
+