Adjusting back into the original lengthy version of IrrigationController; for testing...
authorrtrimana <rtrimana@uci.edu>
Fri, 2 Mar 2018 18:40:07 +0000 (10:40 -0800)
committerrtrimana <rtrimana@uci.edu>
Fri, 2 Mar 2018 18:40:07 +0000 (10:40 -0800)
benchmarks/Java/IrrigationController/IrrigationController.java
benchmarks/Java/IrrigationController/LawnState.java
benchmarks/Java/IrrigationController/test_version/IrrigationController.java [new file with mode: 0644]
benchmarks/Java/IrrigationController/test_version/LawnState.java [new file with mode: 0644]
benchmarks/drivers/Java/BlossomSprinkler/BlossomSprinkler.java

index a30bffd..a646ff1 100644 (file)
@@ -31,15 +31,10 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
        **
        *******************************************************************************************************************************************/
        // private static final int NUMBER_OF_TIMES_PER_WEEK_TO_WATER = 2;
-       //TODO: Change these back to normal - this is just for testing to make it awake all the time
-//     private static final int TIME_HOURS_TO_WATER_GRASS = 7;         // 7 am
-       private static final int TIME_HOURS_TO_WATER_GRASS = 3;
-//     private static final int TIME_MINUTES_TO_WATER_GRASS = 30;      // 30 minutes
-       private static final int TIME_MINUTES_TO_WATER_GRASS = 30;
-//     private static final int TIME_TO_RECOVER_GRASS_FOR = 8 * 24 * 60 * 60;  // 8 days
-       private static final int TIME_TO_RECOVER_GRASS_FOR = 10;
-//     private static final int TIME_TO_HIBERNATE_GRASS_FOR = 30 * 24 * 60 * 60;               // 30 days
-       private static final int TIME_TO_HIBERNATE_GRASS_FOR = 10;
+       private static final int TIME_HOURS_TO_WATER_GRASS = 7;         // 7 am
+       private static final int TIME_MINUTES_TO_WATER_GRASS = 30;      // 30 minutes
+       private static final int TIME_TO_RECOVER_GRASS_FOR = 8 * 24 * 60 * 60;  // 8 days
+       private static final int TIME_TO_HIBERNATE_GRASS_FOR = 30 * 24 * 60 * 60;               // 30 days
        public static final int CAMERA_FPS = 15;                                                                                                        // In frames per second
 
 
@@ -147,12 +142,12 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                        // Seconds since the start of the day to start the watering
                        long secondsForWateringStart = (TIME_HOURS_TO_WATER_GRASS * 3600) + (TIME_MINUTES_TO_WATER_GRASS * 60);
 
-//                     System.out.println("beginingOfToday " + beginingOfToday);
-//                     System.out.println("secondsSinceStartOfDay " + secondsSinceStartOfDay);
-//                     System.out.println("secondsForWateringStart " + secondsForWateringStart);
+                       System.out.println("beginingOfToday " + beginingOfToday);
+                       System.out.println("secondsSinceStartOfDay " + secondsSinceStartOfDay);
+                       System.out.println("secondsForWateringStart " + secondsForWateringStart);
 
                        // check if the current time is within the start watering interval
-                       /*if ((secondsSinceStartOfDay < secondsForWateringStart) || (secondsSinceStartOfDay > (secondsForWateringStart + (60 * 60)))) {
+                       if ((secondsSinceStartOfDay < secondsForWateringStart) || (secondsSinceStartOfDay > (secondsForWateringStart + (60 * 60)))) {
                                System.out.println("Sleep for 10 minutes.. ");
                                try {
                                        //Thread.sleep(10 * 60 * 1000);                                         // sleep for 10 minutes
@@ -162,11 +157,11 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                                }
 
                                continue;
-                       }*/
+                       }
 
                        // check if we already checked if we should water today
                        // we only need to do this once per day
-                       /*if ((dayOfLastCheck == currentDate.getDate()) && (monthOfLastCheck == currentDate.getMonth())) {
+                       if ((dayOfLastCheck == currentDate.getDate()) && (monthOfLastCheck == currentDate.getMonth())) {
                                System.out.println("Sleep for 1 hour...");
                                try {
                                        Thread.sleep(60 * 60 * 1000);                                           // sleep for an hour
@@ -175,7 +170,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                                }
 
                                continue;
-                       }*/
+                       }
 
                        // we decided to check if we should water today so save the fact that we chose to water on this day
                        dayOfLastCheck = currentDate.getDate();
@@ -187,11 +182,11 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                        }
                        // check if we are in hibernation mode and do the correct loop action
                        if (isHibernationMode) {
-//                             System.out.println("Hibernation mode!");
+                               System.out.println("Hibernation mode!");
                                // If we are in hibernation mode then use the hibernation loop code
                                wateringHibernationLoop(currentDate);
                        } else {
-//                             System.out.println("Normal mode!");
+                               System.out.println("Normal mode!");
                                // Using the normal watering loop code
                                wateringNormalLoop(currentDate);
                        }
@@ -210,15 +205,6 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
        public void informationRetrieved(double _inchesPerWeek, int _weatherZipCode, int _daysToWaterOn, double _inchesPerMinute) {
 
                System.out.println("DEBUG: Information is retrieved from phone!!!");
-               /*try {
-                       // get the parameters that the interface (phone app) reads from the user
-                       inchesPerWeek = _wgw.getInchesPerWeek();
-                       weatherZipCode = _wgw.getWeatherZipCode();
-                       daysToWaterOn = _wgw.getDaysToWaterOn();
-                       inchesPerMinute.add(_wgw.getInchesPerMinute());
-               } catch(RemoteException ex) {
-                       ex.printStackTrace();
-               }*/
 
                inchesPerWeek = _inchesPerWeek;
                weatherZipCode = _weatherZipCode;
@@ -264,11 +250,6 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                                e.printStackTrace();
                        }
                }
-               // TODO: Use a phone input interface later
-               /*inchesPerWeek = 20.00;
-               weatherZipCode = 92612;
-               daysToWaterOn = 255;
-               inchesPerMinute.add(1.50);*/
 
                System.out.println("DEBUG: inchesPerWeek: " + inchesPerWeek);
                System.out.println("DEBUG: weatherZipCode: " + weatherZipCode);
@@ -282,21 +263,17 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
 
                // Setup the cameras, start them all and assign each one a motion detector
                for (CameraSmart cam : cameraSet.values()) {
-                       //try {
-                               // 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);
+                       // initialize the camera, might need to setup some stuff internally
+                       cam.init();
 
-                               // Start the camera (example is start the HTTP stream if it is a network camera)
-                               cam.start();
-                               System.out.println("DEBUG: Init camera! " + cam.toString());
-                       //} catch (RemoteException e) {
-                       //      e.printStackTrace();
-                       //}
+                       // set the camera parameters.
+                       cam.setFPS(CAMERA_FPS);
+                       cam.setResolution(Resolution.RES_VGA);
 
+                       // Start the camera (example is start the HTTP stream if it is a network camera)
+                       cam.start();
+                       System.out.println("DEBUG: Init camera! " + cam.toString());
                }
 
                // counter so that we can match the lawn inches per min data with the specific lawn
@@ -314,12 +291,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                                Iterator camIt = cameras.iterator();
                                CameraSmart cam = (CameraSmart)camIt.next();
                                System.out.println("DEBUG: Registering callback to camera: " + cam.toString());
-                               //try {
-                                       // setup the callback
-                                       cam.registerCallback(mo);
-                               //} catch (RemoteException e) {
-                               //      e.printStackTrace();
-                               //}
+                               cam.registerCallback(mo);
                        }
 
                        // we also only need 1 sprinkler controller per lawn so grab the first one
@@ -370,8 +342,6 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
 
                // get the weather data for the next little bit
                List<DayWeather> weatherData = weatherGrabber.getWeatherData();
-               // TODO: Replace this with the WeatherGrabber.getWeatherData() above
-//             List<DayWeather> weatherData = new ArrayList<DayWeather>();
 
                // Go through each lawn and check if we should water it and if we should, water it
                for (LawnState ls : lawns) {
@@ -392,7 +362,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                // if we are in recovery mode then run the recovery action
                // we are still in hibernation mode but we need to recover the grass
                if (isInHibernationRecoveryMode) {
-//                     System.out.println("DEBUG: Recovery mode!");
+                       System.out.println("DEBUG: Recovery mode!");
                        hibernationRecoveryLoop(_currentDate);
                        return;
                }
@@ -404,7 +374,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                        // start recovery mode
                        isInHibernationRecoveryMode = true;
                        hibernationRecoveryModeStartDate = null;
-//                     System.out.println("DEBUG: We enter recovery mode for the first time!");
+                       System.out.println("DEBUG: We enter recovery mode for the first time!");
                        // first cycle of recovery
                        hibernationRecoveryLoop(_currentDate);
                        return;
@@ -422,7 +392,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                        if (!lawnHasMotion) {
                                continue;
                        }
-//                     System.out.println("DEBUG: We water the lawn! (wateringHibernationLoop)");
+                       System.out.println("DEBUG: We water the lawn! (wateringHibernationLoop)");
                        // water specific lawn since it has motion
                        waterLawn(ls, _currentDate, weatherData);
                }
@@ -448,7 +418,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                // we have been in recovery mode long enough
                if (elapsedTime >= TIME_TO_RECOVER_GRASS_FOR) {
 
-//                     System.out.println("DEBUG: We have been in recovery mode long enough!");
+                       System.out.println("DEBUG: We have been in recovery mode long enough!");
                        // reset the recovery mode
                        isInHibernationRecoveryMode = false;
                        hibernationRecoveryModeStartDate = null;
@@ -470,7 +440,7 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                // Go through each lawn and check if we should water it and if we should, water it
                for (LawnState ls : lawns) {
 
-//                     System.out.println("DEBUG: We water the lawn! (hibernationRecoveryLoop)");
+                       System.out.println("DEBUG: We water the lawn! (hibernationRecoveryLoop)");
                        // water specific lawn since it has motion
                        waterLawn(ls, _currentDate, weatherData);
                }
@@ -491,10 +461,6 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                // check if today or tomorrow is a wet day
                boolean todayIsWetDay = _weatherData.get(0).getIsWetDay();
                boolean tomorrowIsWetDay = _weatherData.get(1).getIsWetDay();
-               // TODO: Remove this later - hack the values for now!!!
-//             boolean todayIsWetDay = false;
-//             boolean tomorrowIsWetDay = false;
-
                // lawn cannot wait anymore for water so water not
                boolean lawnNeedsWaterNow = _ls.needsWateringUrgently(_currentDate);
                if (lawnNeedsWaterNow) {
@@ -502,10 +468,9 @@ public class IrrigationController extends UnicastRemoteObject implements Weather
                        System.out.println("DEBUG: Is wet day? " + todayIsWetDay);
                        System.out.println("DEBUG: Tomorrow is wet day? " + tomorrowIsWetDay);
                        // if it is not going to rain today then water the lawn
-                       // TODO: Put this back to uncommented!!! Only for testing!!!
-//                     if (!todayIsWetDay) {
+                       if (!todayIsWetDay) {
                                _ls.waterLawn(_currentDate);
-//                     }
+                       }
                        return;
                }
 
index 10ac4f0..3558354 100644 (file)
@@ -204,8 +204,7 @@ public class LawnState extends UnicastRemoteObject implements MotionDetectionCal
        public boolean needsWateringUrgently(Date _currentDate) {
 
                // get difference between now and last time watered
-               // TODO: Remove this to uncommented!!! This is only for testing!!!
-/*             long timeElapsed = (_currentDate.getTime() - lastTimeWatered.getTime()) / 1000;
+               long timeElapsed = (_currentDate.getTime() - lastTimeWatered.getTime()) / 1000;
 
                // needs watering now urgently
                if (timeElapsed >= MAX_TIME_BETWEEN_WATERING_SESSIONS) {
@@ -215,7 +214,7 @@ public class LawnState extends UnicastRemoteObject implements MotionDetectionCal
                // calculate the average moisture readings of all the
                // sensors in this lawn
                double averageMoistureValue = getAverageMoistureReading();
-
+               System.out.println("DEBUG: Average moisture value: " + averageMoistureValue);
                // is a valid average
                if (averageMoistureValue != -1) {
                        // moisture is very low so we need to water now!
@@ -228,11 +227,6 @@ public class LawnState extends UnicastRemoteObject implements MotionDetectionCal
                }
 
                return false;
-*/
-               double averageMoistureValue = getAverageMoistureReading();
-//             System.out.println("DEBUG: Average moisture value: " + averageMoistureValue);
-
-               return true;
        }
 
 
@@ -502,12 +496,12 @@ public class LawnState extends UnicastRemoteObject implements MotionDetectionCal
                        System.out.println("DEBUG: Current time stamp: " + currentTime.getTime());
                        System.out.println("Time elapsed: " + (currentTime.getTime() - readingTimestamp.getTime()) / 1000);                     
 
-                       //long timeElapsedSinceLastWatering = (currentTime.getTime() - readingTimestamp.getTime()) / 1000;
+                       long timeElapsedSinceLastWatering = (currentTime.getTime() - readingTimestamp.getTime()) / 1000;
 
                        // if reading is old then dont use it since it is noise
-                       //if (timeElapsedSinceLastWatering > TWO_HOURS) {
-                       //      continue;
-                       //}
+                       if (timeElapsedSinceLastWatering > TWO_HOURS) {
+                               continue;
+                       }
 
                        // Do averaging
                        numberOfReadings++;
diff --git a/benchmarks/Java/IrrigationController/test_version/IrrigationController.java b/benchmarks/Java/IrrigationController/test_version/IrrigationController.java
new file mode 100644 (file)
index 0000000..909e24c
--- /dev/null
@@ -0,0 +1,526 @@
+package IrrigationController;
+// Standard Java Packages
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+// RMI packages
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+// IoT Runtime Packages
+import iotruntime.slave.IoTSet;
+import iotruntime.slave.IoTRelation;
+import iotruntime.slave.IoTAddress;
+import iotcode.annotation.*;
+
+// IoT Driver Packages
+import iotcode.interfaces.*;
+import iotcode.WeatherPhoneGateway.*;
+
+public class IrrigationController extends UnicastRemoteObject implements WeatherGatewayCallback {
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Constants
+       **
+       *******************************************************************************************************************************************/
+       // private static final int NUMBER_OF_TIMES_PER_WEEK_TO_WATER = 2;
+       //TODO: Change these back to normal - this is just for testing to make it awake all the time
+//     private static final int TIME_HOURS_TO_WATER_GRASS = 7;         // 7 am
+       private static final int TIME_HOURS_TO_WATER_GRASS = 3;
+//     private static final int TIME_MINUTES_TO_WATER_GRASS = 30;      // 30 minutes
+       private static final int TIME_MINUTES_TO_WATER_GRASS = 30;
+//     private static final int TIME_TO_RECOVER_GRASS_FOR = 8 * 24 * 60 * 60;  // 8 days
+       private static final int TIME_TO_RECOVER_GRASS_FOR = 10;
+//     private static final int TIME_TO_HIBERNATE_GRASS_FOR = 30 * 24 * 60 * 60;               // 30 days
+       private static final int TIME_TO_HIBERNATE_GRASS_FOR = 10;
+       public static final int CAMERA_FPS = 15;                                                                                                        // In frames per second
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Variables
+       **
+       *******************************************************************************************************************************************/
+       private int dayOfLastCheck = -1;
+       private int monthOfLastCheck = -1;
+       private boolean isInHibernationRecoveryMode = false;
+       private Date hibernationRecoveryModeStartDate = null;
+       private boolean isHibernationMode = false;
+       private Date hibernationModeStartDate = null;
+       private List<LawnState> lawns = new ArrayList<LawnState>();
+       private WeatherGrabber weatherGrabber = null;
+
+       // used to block until gui is done and the settings are ready to be polled
+       private AtomicBoolean waitingForInterface = new AtomicBoolean(true);
+
+       // the settings from the interface, used to setup the system
+       private double inchesPerWeek = 0;
+       private int weatherZipCode = 0;
+       private int daysToWaterOn = 0;
+       private List<Double> inchesPerMinute;
+
+       private static int sensorId = 0;
+
+       /*******************************************************************************************************************************************
+       **
+       **  IoT Sets and Relations
+       **
+       *******************************************************************************************************************************************/
+       @config private IoTSet<IoTAddress> weatherDataAddresses;
+       @config private IoTSet<IoTAddress> weatherDataAddressMain;
+       @config private IoTSet<WeatherGatewaySmart> gwSet;
+       @config private IoTSet<LawnSmart> lawnSet;
+       @config private IoTSet<MoistureSensorSmart> moistureSensorsSet;
+       @config private IoTSet<CameraSmart> cameraSet;
+       @config private IoTRelation<LawnSmart, CameraSmart> lawnCameraRelation;
+       @config private IoTRelation<LawnSmart, SprinklerSmart> lawnSprinklerRelation;
+       @config private IoTRelation<LawnSmart, MoistureSensorSmart> lawnMoistureSensorRelation;
+
+
+       public IrrigationController() throws RemoteException {
+
+       }
+
+       /*******************************************************************************************************************************************
+       **
+       **  Public Methods
+       **
+       *******************************************************************************************************************************************/
+
+
+       /** Method to set whether the controller should maintain the lawns in hibernation mode
+        *   or in normal mode.  Lawns should be put in hibernation mode in drought conditions
+        *
+        *   @param _hibMode [boolean] set the hibernation mode for this lawn controllers (true = hibernation)
+        *
+        *   @return [void] None.
+        */
+       public void setHibernationMode(boolean _hibMode) {
+
+               // change hibernation mode status
+               isHibernationMode = _hibMode;
+
+               // set the start date for when we started this hibernation mode
+               if (_hibMode) {
+
+                       // make sure we dont reset this cycle
+                       if (!isHibernationMode) {
+                               hibernationModeStartDate = new Date();
+                       }
+               } else {
+                       // reset all hibernation stuff
+                       hibernationModeStartDate = null;
+                       isInHibernationRecoveryMode = false;
+                       hibernationRecoveryModeStartDate = null;
+               }
+       }
+
+       /** Method to start the controller and run the main control loop
+        *
+        *   @return [void] None.
+        */
+       public void init() throws RemoteException {
+
+               // initialize the controller
+               initController();
+               System.out.println("Initialized controller!");
+
+               // Main Loop
+               while (true) {
+
+                       // get the current time of day (date and time)
+                       Date currentDate = new Date();
+
+                       // get the epoch time till the beginning of the day
+                       Date beginingOfToday = new Date(currentDate.getYear(), currentDate.getMonth(), currentDate.getDate());
+
+                       // calculate the seconds since the start of the day.
+                       long secondsSinceStartOfDay = (currentDate.getTime() - beginingOfToday.getTime()) / 1000;
+
+                       // Seconds since the start of the day to start the watering
+                       long secondsForWateringStart = (TIME_HOURS_TO_WATER_GRASS * 3600) + (TIME_MINUTES_TO_WATER_GRASS * 60);
+
+//                     System.out.println("beginingOfToday " + beginingOfToday);
+//                     System.out.println("secondsSinceStartOfDay " + secondsSinceStartOfDay);
+//                     System.out.println("secondsForWateringStart " + secondsForWateringStart);
+
+                       // check if the current time is within the start watering interval
+                       /*if ((secondsSinceStartOfDay < secondsForWateringStart) || (secondsSinceStartOfDay > (secondsForWateringStart + (60 * 60)))) {
+                               System.out.println("Sleep for 10 minutes.. ");
+                               try {
+                                       //Thread.sleep(10 * 60 * 1000);                                         // sleep for 10 minutes
+                                       Thread.sleep(10);                                               // sleep for 10 seconds
+                               } catch (Exception e) {
+                                       e.printStackTrace();
+                               }
+
+                               continue;
+                       }*/
+
+                       // check if we already checked if we should water today
+                       // we only need to do this once per day
+                       /*if ((dayOfLastCheck == currentDate.getDate()) && (monthOfLastCheck == currentDate.getMonth())) {
+                               System.out.println("Sleep for 1 hour...");
+                               try {
+                                       Thread.sleep(60 * 60 * 1000);                                           // sleep for an hour
+                               } catch (Exception e) {
+                                       e.printStackTrace();
+                               }
+
+                               continue;
+                       }*/
+
+                       // we decided to check if we should water today so save the fact that we chose to water on this day
+                       dayOfLastCheck = currentDate.getDate();
+                       monthOfLastCheck = currentDate.getMonth();
+
+                       // update the lawn states everyday
+                       for (LawnState ls : lawns) {
+                               ls.updateLawn(currentDate);
+                       }
+                       // check if we are in hibernation mode and do the correct loop action
+                       if (isHibernationMode) {
+//                             System.out.println("Hibernation mode!");
+                               // If we are in hibernation mode then use the hibernation loop code
+                               wateringHibernationLoop(currentDate);
+                       } else {
+//                             System.out.println("Normal mode!");
+                               // Using the normal watering loop code
+                               wateringNormalLoop(currentDate);
+                       }
+               }
+       }
+
+
+       /** Callback method for when the information is retrieved.
+        *
+        * @param _inchesPerWeek [double].
+        * @param _weatherZipCode [int].
+        * @param _daysToWaterOn [int].
+        * @param _inchesPerMinute [double].
+        * @return [void] None.
+        */
+       public void informationRetrieved(double _inchesPerWeek, int _weatherZipCode, int _daysToWaterOn, double _inchesPerMinute) {
+
+               System.out.println("DEBUG: Information is retrieved from phone!!!");
+               /*try {
+                       // get the parameters that the interface (phone app) reads from the user
+                       inchesPerWeek = _wgw.getInchesPerWeek();
+                       weatherZipCode = _wgw.getWeatherZipCode();
+                       daysToWaterOn = _wgw.getDaysToWaterOn();
+                       inchesPerMinute.add(_wgw.getInchesPerMinute());
+               } catch(RemoteException ex) {
+                       ex.printStackTrace();
+               }*/
+
+               inchesPerWeek = _inchesPerWeek;
+               weatherZipCode = _weatherZipCode;
+               daysToWaterOn = _daysToWaterOn;
+               inchesPerMinute.add(_inchesPerMinute);
+
+               // the gui is done so release the spin wait that was waiting for the gui
+               waitingForInterface.set(false);
+       }
+
+       /*******************************************************************************************************************************************
+       **
+       **  Helper Methods
+       **
+       *******************************************************************************************************************************************/
+
+
+       /** Method to initialize the controller variables and all the drivers and such
+        *
+        *   @return [void] None.
+        */
+       private void initController() throws RemoteException {
+
+               // Setup the weather grabber object with the correct address of the weather api
+               Iterator it = weatherDataAddresses.iterator();
+               weatherGrabber = new WeatherGrabber((IoTAddress)it.next());
+
+               // Initialize inchesPerMinute
+               inchesPerMinute = new ArrayList<Double>();
+
+               // We setup a Gateway object to get information from the phone app
+               for (WeatherGatewaySmart gw : gwSet.values()) {
+                       gw.init();
+                       gw.registerCallback(this);
+                       gw.start();
+               }
+
+               System.out.println("DEBUG: Waiting for phone to send weather information");
+               while (waitingForInterface.get()) {
+                       try {
+                               Thread.sleep(1000);
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+               // TODO: Use a phone input interface later
+               /*inchesPerWeek = 20.00;
+               weatherZipCode = 92612;
+               daysToWaterOn = 255;
+               inchesPerMinute.add(1.50);*/
+
+               System.out.println("DEBUG: inchesPerWeek: " + inchesPerWeek);
+               System.out.println("DEBUG: weatherZipCode: " + weatherZipCode);
+               System.out.println("DEBUG: daysToWaterOn: " + daysToWaterOn);
+               System.out.println("DEBUG: inchesPerMinute: " + inchesPerMinute.get(0));
+
+               // set the zip code and the the number of days of the weather grabber
+               // here the number of days is set to the max that the grabber supports
+               weatherGrabber.setZipcode(weatherZipCode);
+               weatherGrabber.setNumberOfDays(16);
+
+               // Setup the cameras, start them all and assign each one a motion detector
+               for (CameraSmart cam : cameraSet.values()) {
+
+                       // 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);
+
+                       // Start the camera (example is start the HTTP stream if it is a network camera)
+                       cam.start();
+                       System.out.println("DEBUG: Init camera! " + cam.toString());
+               }
+
+               // counter so that we can match the lawn inches per min data with the specific lawn
+               int counter = 0;
+               for (LawnSmart l : lawnSet.values()) {
+                       // create a motionDetector for each lawn object
+                       MotionDetection mo = new MotionDetection(12, 0.5f, 10, 10);
+
+                       // for 1 camera, if there are any then register the camera for that lawn
+                       HashSet<CameraSmart> cameras = lawnCameraRelation.get(l);
+                       System.out.println("DEBUG: Camera.size(): " + cameras.size());
+                       if (cameras.size() >= 1) {
+
+                               // we only need 1 camera per lawn so get the first one in the list
+                               Iterator camIt = cameras.iterator();
+                               CameraSmart cam = (CameraSmart)camIt.next();
+                               System.out.println("DEBUG: Registering callback to camera: " + cam.toString());
+                               //try {
+                                       // setup the callback
+                                       cam.registerCallback(mo);
+                               //} catch (RemoteException e) {
+                               //      e.printStackTrace();
+                               //}
+                       }
+
+                       // we also only need 1 sprinkler controller per lawn so grab the first one
+                       HashSet<SprinklerSmart> sprinklers = lawnSprinklerRelation.get(l);
+                       Iterator sprinklersIt = sprinklers.iterator();
+                       SprinklerSmart spr = (SprinklerSmart)sprinklersIt.next();
+
+                       // init the sprinkler controller, do it here since it only needs to be done once per controller
+                       try {
+                               spr.init();
+                               // Wait until sprinkler is active
+                               Thread.sleep(30000);
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+                       System.out.println("DEBUG: Init sprinkler: " + spr.toString());
+
+                       // get and init the moisture sensors for this specific lawn
+                       HashSet<MoistureSensorSmart> sensors = lawnMoistureSensorRelation.get(l);
+                       for (MoistureSensorSmart sen : sensors) {
+                               System.out.println("DEBUG: Init sensors: " + sen.toString());
+                               try {
+                                       sen.init();
+                                       sen.setId(sensorId++);
+                               } catch (Exception e) {
+                                       e.printStackTrace();
+                               }
+                       }
+
+                       // create the lawn objects
+                       System.out.println("DEBUG: Creating a LawnState object");
+                       LawnState ls = 
+                               new LawnState(l, daysToWaterOn, mo, inchesPerMinute.get(counter), inchesPerWeek, spr, counter, sensors);
+                       lawns.add(ls);
+
+                       // dont forget to increment the counter
+                       counter++;
+               }
+       }
+
+       /** Main loop for when the controller is watering the lawns under normal conditions, not in hibernation mode
+        *
+        *   @param _currentDate [Date] current date
+        *
+        *   @return [void] None.
+        */
+       private void wateringNormalLoop(Date _currentDate) {
+
+               // get the weather data for the next little bit
+               List<DayWeather> weatherData = weatherGrabber.getWeatherData();
+               // TODO: Replace this with the WeatherGrabber.getWeatherData() above
+//             List<DayWeather> weatherData = new ArrayList<DayWeather>();
+
+               // Go through each lawn and check if we should water it and if we should, water it
+               for (LawnState ls : lawns) {
+
+                       // water for specific lawn
+                       waterLawn(ls, _currentDate, weatherData);
+               }
+       }
+
+       /** Main loop for when the controller is watering the lawns in hibernation mode
+        *
+        *   @param _currentDate [Date] current date
+        *
+        *   @return [void] None.
+        */
+       private void wateringHibernationLoop(Date _currentDate) {
+
+               // if we are in recovery mode then run the recovery action
+               // we are still in hibernation mode but we need to recover the grass
+               if (isInHibernationRecoveryMode) {
+//                     System.out.println("DEBUG: Recovery mode!");
+                       hibernationRecoveryLoop(_currentDate);
+                       return;
+               }
+
+               // check if we should enter recovery mode
+               long elapsedTime = (_currentDate.getTime() - hibernationModeStartDate.getTime()) / 1000;
+               if (elapsedTime >= TIME_TO_HIBERNATE_GRASS_FOR) {
+
+                       // start recovery mode
+                       isInHibernationRecoveryMode = true;
+                       hibernationRecoveryModeStartDate = null;
+//                     System.out.println("DEBUG: We enter recovery mode for the first time!");
+                       // first cycle of recovery
+                       hibernationRecoveryLoop(_currentDate);
+                       return;
+               }
+
+               // get the weather data for the next little bit
+               List<DayWeather> weatherData = weatherGrabber.getWeatherData();
+
+               // Go through each lawn and check if we should water it and if we should, water it
+               for (LawnState ls : lawns) {
+
+                       boolean lawnHasMotion = ls.lawnHasSufficientMotion();
+
+                       // there is no motion on the lawn so no need to water it
+                       if (!lawnHasMotion) {
+                               continue;
+                       }
+//                     System.out.println("DEBUG: We water the lawn! (wateringHibernationLoop)");
+                       // water specific lawn since it has motion
+                       waterLawn(ls, _currentDate, weatherData);
+               }
+       }
+
+
+       /** Main loop for when the controller is watering the lawns in hibernation mode
+        *
+        *   @param _currentDate [Date] current date
+        *
+        *   @return [void] None.
+        */
+       private void hibernationRecoveryLoop(Date _currentDate) {
+
+               // start recovery mode if it wasnt started yet
+               if (hibernationRecoveryModeStartDate == null) {
+                       hibernationRecoveryModeStartDate = _currentDate;
+               }
+
+               // time since this mode was started
+               long elapsedTime = (_currentDate.getTime() - hibernationRecoveryModeStartDate.getTime()) / 1000;
+
+               // we have been in recovery mode long enough
+               if (elapsedTime >= TIME_TO_RECOVER_GRASS_FOR) {
+
+//                     System.out.println("DEBUG: We have been in recovery mode long enough!");
+                       // reset the recovery mode
+                       isInHibernationRecoveryMode = false;
+                       hibernationRecoveryModeStartDate = null;
+
+                       // revived grass so restart the grass hibernation cycle
+                       hibernationModeStartDate = _currentDate;
+
+                       // do the hibernation loop since we are no longer in recovery mode
+                       wateringHibernationLoop(_currentDate);
+                       return;
+               }
+
+
+               // if we got here then we are trying to recover the grass
+
+               // get the weather data for the next little bit
+               List<DayWeather> weatherData = weatherGrabber.getWeatherData();
+
+               // Go through each lawn and check if we should water it and if we should, water it
+               for (LawnState ls : lawns) {
+
+//                     System.out.println("DEBUG: We water the lawn! (hibernationRecoveryLoop)");
+                       // water specific lawn since it has motion
+                       waterLawn(ls, _currentDate, weatherData);
+               }
+
+       }
+
+
+       /** Method for watering a specific lawn if it needs to be watered
+        *
+        *   @param _ls [LawnState] lawn to water
+        *   @param _currentDate [Date] current date
+        *   @param _weatherData [List<DayWeather>] latest weather data
+        *
+        *   @return [void] None.
+        */
+       private void waterLawn(LawnState _ls, Date _currentDate,  List<DayWeather> _weatherData) {
+
+               // check if today or tomorrow is a wet day
+               boolean todayIsWetDay = _weatherData.get(0).getIsWetDay();
+               boolean tomorrowIsWetDay = _weatherData.get(1).getIsWetDay();
+               // TODO: Remove this later - hack the values for now!!!
+//             boolean todayIsWetDay = false;
+//             boolean tomorrowIsWetDay = false;
+
+               // lawn cannot wait anymore for water so water not
+               boolean lawnNeedsWaterNow = _ls.needsWateringUrgently(_currentDate);
+               if (lawnNeedsWaterNow) {
+                       System.out.println("DEBUG: Need water now!!!");
+                       System.out.println("DEBUG: Is wet day? " + todayIsWetDay);
+                       System.out.println("DEBUG: Tomorrow is wet day? " + tomorrowIsWetDay);
+                       // if it is not going to rain today then water the lawn
+                       // TODO: Put this back to uncommented!!! Only for testing!!!
+//                     if (!todayIsWetDay) {
+                               _ls.waterLawn(_currentDate);
+//                     }
+                       return;
+               }
+
+               // check if this lawn needs watering based on watering algoritm/sensors/ext
+               boolean shouldWaterLawn = _ls.needsWatering(_currentDate);
+
+               // should not water this lawn then just skip to the next lawn
+               if (!shouldWaterLawn) {
+                       return;
+               }
+
+               // it is going to rain soon so wait it out.
+               // Grass is not in critical condition so it can wait a bit.
+               if (todayIsWetDay || tomorrowIsWetDay) {
+                       return;
+               }
+
+               // if we got here then we need to water the lawn
+               _ls.waterLawn(_currentDate);
+       }
+}
+
diff --git a/benchmarks/Java/IrrigationController/test_version/LawnState.java b/benchmarks/Java/IrrigationController/test_version/LawnState.java
new file mode 100644 (file)
index 0000000..10ac4f0
--- /dev/null
@@ -0,0 +1,539 @@
+package IrrigationController;
+
+// Standard Java Packages
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+
+// RMI packages
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+// IoT Driver Packages
+import iotcode.interfaces.*;
+
+// Checker annotations
+//import iotchecker.qual.*;
+
+/** Class LawnState that represents the state of the lawn, also help calculate if the lawn needs to be watered.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-04
+ */
+
+public class LawnState extends UnicastRemoteObject implements MotionDetectionCallback, MoistureSensorCallback {
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Constants
+       **
+       *******************************************************************************************************************************************/
+       private static final long MAX_TIME_BETWEEN_WATERING_SESSIONS = 4 * 24 * 60 * 60;        // 5 days
+       private static final int MAX_DAYS_RAINED_RECORD = 20;
+       private static final int RAINED_RECENTLY_DAYS_INTERVAL = 1;
+       private static final long TWENTY_FIVE_HOURS = 25 * 60 * 60;
+       private static final long TWO_HOURS = 2 * 60 * 60;
+
+       private static final long NEW_MOTION_THRESHOLD = 2 * 60;        // 2 minutes
+       private static final long AMOUNT_OF_MOTION_FOR_ACTIVE = 60 * 60;        // 1 hour
+       private static final long AMOUNT_OF_TIME_FOR_ACTIVE_TO_HOLD = 7 * 24 * 60 * 60;         // 1 week
+
+       private static final double MOISTURE_LEVEL_FOR_NORMAL_WATERING = 25;            // Percentage
+       private static final double MOISTURE_LEVEL_FOR_EMERGENCY_WATERING = 5;  // Percentage
+       private static final double MOISTURE_LEVEL_FOR_NO_WATERING = 80;        // Percentage
+
+       /*******************************************************************************************************************************************
+       **
+       **  Variables
+       **
+       *******************************************************************************************************************************************/
+       private boolean isInHibernationMode = false;
+       private Date lastTimeWatered = null;
+       private boolean didWaterSinceLastSchedualedDate = false;
+       private List<Date> daysRained = new ArrayList<Date>();
+       private int daysToWaterOn = 0;
+       private LawnSmart iotLawnObject;
+       private MotionDetection motionDetector;
+       private double inchesPerMinute = 0;
+       private double inchesPerWeek = 0;
+       private double timePerWatering = 0;
+       private double timePerWeek = 0;
+       private double timeWateredSoFar = 0;
+       private SprinklerSmart sprinkler;
+       private int zone = 0;
+       private Date lastMotionDetectedTime = null;
+       private Date startOfThisMotion = null;
+       private Date lastUpdateDate = null;
+       private Lock mutex = new ReentrantLock();
+       private long totalMotionOnLawn = 0;
+       private long numberOfMotionsOnLawnToday = 0;
+       private boolean lawnIsActive = false;
+       private Date lawnBecameActiceDate = null;
+       private Map<Integer, Double> moistureSensorReadings = 
+               new ConcurrentHashMap<Integer, Double>();
+       private Map<Integer, Date> moistureSensorUpdateTimes = 
+               new ConcurrentHashMap<Integer, Date>();
+
+
+       // 0th bit = Monday, 1th bit = Tuesday ext
+       public LawnState(LawnSmart _l, int _daysToWaterOn, MotionDetection _mo, 
+                                       double _inchesPerMinute, double _inchesPerWeek, SprinklerSmart _sprinkler, 
+                                       int _zone, Set<MoistureSensorSmart> _moistureSensors) throws RemoteException {
+               iotLawnObject = _l;
+               daysToWaterOn = _daysToWaterOn;
+               inchesPerMinute = _inchesPerMinute;
+               inchesPerWeek = _inchesPerWeek;
+               sprinkler = _sprinkler;
+               zone = _zone;
+
+               // register the callback with self
+               motionDetector = _mo;
+               _mo.registerCallback(this);
+
+               // register callback to self
+               for (MoistureSensorSmart sen : _moistureSensors) {
+
+                       try {
+                               sen.registerCallback(this);
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+
+               // parse the days that we are going to water on
+               int numberOfDaysForWatering = 0;
+               for (int i = 0; i < 7; i++) {
+                       if ((daysToWaterOn & (1 << i)) > 0) {
+                               numberOfDaysForWatering++;
+                       }
+               }
+
+               // calculate lawn watering water amounts
+               timePerWeek = _inchesPerWeek / _inchesPerMinute;
+               timePerWatering = timePerWeek / (double)numberOfDaysForWatering;
+       }
+
+       /*******************************************************************************************************************************************
+       **
+       **  Public Methods
+       **
+       *******************************************************************************************************************************************/
+
+
+       /** Method to update the lawn state, updates lawn activity state based on activity timeout
+        *
+        *   @param _currentDate  [Date], the current date and time.
+        *
+        *   @return [void] None.
+        */
+       public void updateLawn(Date _currentDate) {
+               if (lastUpdateDate != null) {
+
+                       // check if we already did an update today
+                       if ((lastUpdateDate.getDate() == _currentDate.getDate())
+                                       && (lastUpdateDate.getMonth() == _currentDate.getMonth())
+                                       && (lastUpdateDate.getYear() == _currentDate.getYear())) {
+                               return;
+                       }
+               }
+
+               lastUpdateDate = _currentDate;
+
+               // lawn was active at some time so check if it can be deemed inactive because
+               // time has passed and it has not been active in that time
+               if (lawnBecameActiceDate != null) {
+                       long timeElapsed = (_currentDate.getTime() - lawnBecameActiceDate.getTime()) / 1000;
+
+                       if (timeElapsed >= AMOUNT_OF_TIME_FOR_ACTIVE_TO_HOLD) {
+                               lawnBecameActiceDate = null;
+                               lawnIsActive = false;
+                       }
+               }
+
+
+               // check activity of lawn
+               boolean isActiveLawn = false;
+               try {
+                       mutex.lock();
+                       if (totalMotionOnLawn >= AMOUNT_OF_MOTION_FOR_ACTIVE) {
+                               isActiveLawn = true;
+                       }
+
+                       // reset motion counters
+                       totalMotionOnLawn = 0;
+                       numberOfMotionsOnLawnToday = 0;
+
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               finally {
+                       mutex.unlock();
+               }
+
+               // update lawn state
+               if (isActiveLawn) {
+                       lawnIsActive = true;
+                       lawnBecameActiceDate = _currentDate;
+               }
+       }
+
+
+       /** Method to test if this lawn is active or not.
+        *
+        *   @return [Boolean] lawn is active.
+        */
+       public boolean lawnHasSufficientMotion() {
+               return lawnIsActive;
+       }
+
+
+       /** Method to test if this lawn should be watered or not right now.
+        *   Lawn urgently needs to be watered right now.
+        *
+        *   @param _currentDate  [Date], the current date and time.
+        *
+        *   @return [Boolean] lawn does need watering.
+        */
+       public boolean needsWateringUrgently(Date _currentDate) {
+
+               // get difference between now and last time watered
+               // TODO: Remove this to uncommented!!! This is only for testing!!!
+/*             long timeElapsed = (_currentDate.getTime() - lastTimeWatered.getTime()) / 1000;
+
+               // needs watering now urgently
+               if (timeElapsed >= MAX_TIME_BETWEEN_WATERING_SESSIONS) {
+                       return true;
+               }
+
+               // calculate the average moisture readings of all the
+               // sensors in this lawn
+               double averageMoistureValue = getAverageMoistureReading();
+
+               // is a valid average
+               if (averageMoistureValue != -1) {
+                       // moisture is very low so we need to water now!
+                       if (averageMoistureValue <= MOISTURE_LEVEL_FOR_EMERGENCY_WATERING) {
+                               return true;
+                       } else if (averageMoistureValue >= MOISTURE_LEVEL_FOR_NO_WATERING) {
+                               // moisture is high so no need to water
+                               return false;
+                       }
+               }
+
+               return false;
+*/
+               double averageMoistureValue = getAverageMoistureReading();
+//             System.out.println("DEBUG: Average moisture value: " + averageMoistureValue);
+
+               return true;
+       }
+
+
+       /** Method to test if this lawn should be watered or not
+        *
+        *   @param _currentDate  [Date], the current date and time.
+        *
+        *   @return [Boolean] lawn does need watering.
+        */
+       public boolean needsWatering(Date _currentDate) {
+
+               // only check if we have watered since the last date
+               if (didWaterSinceLastSchedualedDate) {
+                       // get the day of the week from the date and convert it to be
+                       // 0=Monday, 1=Sunday, ....
+                       int dayOfWeek = _currentDate.getDay();
+                       dayOfWeek = (dayOfWeek - 1) % 7;
+
+                       // Calculate what we should mask out days to water byte to see if it is a 1
+                       int mask = (1 << dayOfWeek);
+
+                       // mask the bye
+                       int shouldWaterToday = daysToWaterOn & mask;
+
+                       // if the post masked data is 0 then we should not water today since that bit was not set to 1
+                       // do not water today
+                       if (shouldWaterToday == 0) {
+                               return false;
+                       }
+
+               }
+
+               // it is a scheduled day so we need to water soon;
+               didWaterSinceLastSchedualedDate = false;
+
+               // check if it rained in the last little bit so there is no need to water this grass right now.
+               if (didRainRecently(_currentDate, RAINED_RECENTLY_DAYS_INTERVAL)) {
+                       return false;
+               }
+
+               // The grass was never watered before so water now
+               if (lastTimeWatered == null) {
+                       return true;
+               }
+
+               // calculate the average moisture readings of all the
+               // sensors in this lawn
+               double averageMoistureValue = getAverageMoistureReading();
+
+               // is a valid average
+               if (averageMoistureValue != -1) {
+                       // moisture is low enough to need to water now
+                       if (averageMoistureValue <= MOISTURE_LEVEL_FOR_NORMAL_WATERING) {
+                               return true;
+                       } else if (averageMoistureValue >= MOISTURE_LEVEL_FOR_NO_WATERING) {
+                               // moisture is high so no need to water
+                               return false;
+                       }
+               }
+
+               // if got here then no condition says we should not water today so we should
+               // water the grass today
+               return true;
+       }
+
+
+       /** Method to get the date of the last time the lawn was watered
+        *
+        *   @return [Date] date of last watering.
+        */
+       public Date getLastTimeWatered() {
+               return lastTimeWatered;
+       }
+
+       /** Method to keep track of the last few times it rained on this lawn
+        *
+        *   @param _dateOfRain  [Date], the date of the rain.
+        *
+        *   @return [void] None.
+        */
+       public void rainedOnDate(Date _dateOfRain) {
+
+               // the grass was technically watered on this day
+               lastTimeWatered = _dateOfRain;
+
+               didWaterSinceLastSchedualedDate = true;
+
+               // it rained on this date
+               daysRained.add(_dateOfRain);
+
+               // only keep the last 20 days that it rained
+               if (daysRained.size() > 20) {
+                       daysRained.remove(0);
+               }
+
+       }
+
+
+       /** Method to water lawn, calculates how much to water and sends water signal to controller
+        *
+        *   @param _currentDate  [Date], the current date and time.
+        *
+        *   @return [void] None.
+        */
+       public void waterLawn(Date _currentDate) {
+               lastTimeWatered = _currentDate;
+               didWaterSinceLastSchedualedDate = true;
+
+               // get the day of the week from the date and convert it to be
+               // 0=Monday, 1=Sunday, ....
+               int dayOfWeek = _currentDate.getDay();
+               dayOfWeek = (dayOfWeek - 1) % 7;
+
+
+               // check if it is the last day to water for this week
+               boolean isLastDay = true;
+               for (int i = 6; i > dayOfWeek; i--) {
+                       int mask = (1 << dayOfWeek);
+
+                       int shouldWaterToday = daysToWaterOn & mask;
+
+                       if (shouldWaterToday != 0) {
+                               isLastDay = false;
+                               break;
+                       }
+               }
+
+
+               int secondsToWater = 0;
+               if (isLastDay) {
+
+                       // last day of week to water so water the remaining amount
+                       double minutesToWater = timePerWeek - timeWateredSoFar;
+                       timeWateredSoFar = 0;
+                       secondsToWater = (int)((double)(minutesToWater * 60));
+
+               } else {
+
+                       // if it is not the last day then just water a normal amount
+                       timeWateredSoFar += timePerWatering;
+                       secondsToWater = (int)((double)(timePerWatering * 60));
+               }
+
+               try {
+                       System.out.println("DEBUG: We water the lawn!!! Zone: " + zone + " Seconds to water: " + secondsToWater);
+                       sprinkler.setZone(zone, true, secondsToWater);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+
+       }
+
+       /** Method callback from the motion detection callback interface, processes the motion
+        *  to see how long the motion was and saves that motion.
+        *
+        *   @param _md  [MotionDetection], motion detector with the motion
+        *
+        *   @return [void] None.
+        */
+       public void motionDetected(long timeStampOfLastMotion) {
+
+               Date currMotTime = new Date(timeStampOfLastMotion);
+
+               if (lastMotionDetectedTime == null) {
+                       lastMotionDetectedTime = currMotTime;
+               }
+
+               if (startOfThisMotion == null) {
+                       startOfThisMotion = currMotTime;
+               }
+
+               long timeElapsed = (currMotTime.getTime() - lastMotionDetectedTime.getTime()) / 1000;
+
+               if (timeElapsed >= NEW_MOTION_THRESHOLD) {
+                       try {
+                               mutex.lock();
+                               long motiontime = (lastMotionDetectedTime.getTime() - startOfThisMotion.getTime()) / 1000;
+                               totalMotionOnLawn += motiontime;
+                               numberOfMotionsOnLawnToday++;
+
+
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+                       finally {
+                               mutex.unlock();
+                       }
+
+                       startOfThisMotion = currMotTime;
+               }
+
+               lastMotionDetectedTime = currMotTime;
+       }
+
+
+       /** Callback method for when a new moisture reading is available.
+        *   Called when a new reading is ready by the sensor and the sensor
+        *   can be checked for the frame data.
+        *
+        *   @param _sensor [MoistureSensor] .
+        *
+        *   @return [void] None.
+        */
+       public void newReadingAvailable(int sensorId, float moisture, long timeStampOfLastReading) {
+
+               moistureSensorReadings.put(sensorId, (double) moisture);
+               moistureSensorUpdateTimes.put(sensorId, new Date(timeStampOfLastReading));
+       }
+
+
+       /*******************************************************************************************************************************************
+       **
+       **  Helper Methods
+       **
+       *******************************************************************************************************************************************/
+
+       /** Method to check if it rained recently in the near past.
+        *
+        *   @param _numberOfDaysInPast  [long], number of days in the past to check if it rained recently.
+        *   @param _currentDate  [Date], the current date and time.
+        *
+        *   @return [boolean] weather it rained recently or not.
+        */
+       private boolean didRainRecently(Date _currentDate, long _numberOfDaysInPast) {
+
+               // it never rained before
+               if (daysRained.size() == 0) {
+                       return false;
+               }
+
+               // convert the days to seconds for calculation
+               long numberOfSecondsInPast = _numberOfDaysInPast * 24 * 60 * 60;
+
+               // go through all the stored days that it rained on
+               for (Date d : daysRained) {
+
+                       // check the difference time and convert to seconds.
+                       long numberOfSecondsDifference = (_currentDate.getTime() - d.getTime()) / 1000;
+
+                       // if it rained in the last specified time then return true
+                       if (numberOfSecondsDifference < numberOfSecondsInPast) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+
+       /** Method calculate the average moisture readings of the most recent moisture reading of each sensor
+        *   if that reading is not stale
+        *
+        *   @return [double] average value of moisture readings.
+        */
+       private double getAverageMoistureReading() {
+
+               Date currentTime = new Date();
+               double total = 0;
+               int numberOfReadings = 0;
+
+               for (Integer sen : moistureSensorReadings.keySet()) {
+
+                       // check the timestamp of the watering of the lawn
+                       Date readingTimestamp = moistureSensorUpdateTimes.get(sen);
+
+                       System.out.println("DEBUG: Sensor reading time stamp: " + readingTimestamp.getTime());
+                       System.out.println("DEBUG: Current time stamp: " + currentTime.getTime());
+                       System.out.println("Time elapsed: " + (currentTime.getTime() - readingTimestamp.getTime()) / 1000);                     
+
+                       //long timeElapsedSinceLastWatering = (currentTime.getTime() - readingTimestamp.getTime()) / 1000;
+
+                       // if reading is old then dont use it since it is noise
+                       //if (timeElapsedSinceLastWatering > TWO_HOURS) {
+                       //      continue;
+                       //}
+
+                       // Do averaging
+                       numberOfReadings++;
+                       total += moistureSensorReadings.get(sen);
+
+                       System.out.println("DEBUG: Sensor reading value: " + moistureSensorReadings.get(sen) + " with total: " + total);
+               }
+
+
+               // if no readings were valid then return -1 so that we can signal that moisture cannot be used for now
+               if (numberOfReadings == 0) {
+                       return -1;
+               }
+
+               // return the calculated average of all the recent moisture readings
+               return total / (double)numberOfReadings;
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
index dc05c0d..209b2fe 100644 (file)
@@ -90,7 +90,6 @@ public class BlossomSprinkler implements Sprinkler {
 
         // create the correct number of zones for this controller
         for (int i = 0; i < NUMBER_OF_ZONES; i++) {
-            //zoneStates.add(new ZoneState(i, false, 0));
                        ZoneState zTmp = new ZoneState();
                        zTmp.zoneNumber = i;
                        zTmp.onOffState = false;
@@ -123,7 +122,6 @@ public class BlossomSprinkler implements Sprinkler {
                 {
                     // We replaced methods with fields
                                //z.zoneNumber, z.onOffState z.duration
-                    //if (z.getZoneNumber() == _zone) {
                     if (z.zoneNumber == _zone) {
 
                         // turn on or off the valve
@@ -206,10 +204,7 @@ public class BlossomSprinkler implements Sprinkler {
             try {
                 zoneStateMutex.acquire();
                 for (ZoneState z : zoneStates) {
-                                       //System.out.println("Iterating on zone: " + z.zoneNumber);
                     if (z.onOffState) {
-                                               //System.out.println("Turning on zone: " + z.zoneNumber);
-                                               //System.out.println("Duration: " + z.duration);
                         // if on and time has expired then turn off
                         if (z.duration == 0) {