From: rtrimana Date: Fri, 2 Mar 2018 18:40:07 +0000 (-0800) Subject: Adjusting back into the original lengthy version of IrrigationController; for testing... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=02f34d5ef81b2605f3ee42fe62f0f62a7e292aaf;p=iot2.git Adjusting back into the original lengthy version of IrrigationController; for testing purposes we can still use the files in testing_version folder --- diff --git a/benchmarks/Java/IrrigationController/IrrigationController.java b/benchmarks/Java/IrrigationController/IrrigationController.java index a30bffd..a646ff1 100644 --- a/benchmarks/Java/IrrigationController/IrrigationController.java +++ b/benchmarks/Java/IrrigationController/IrrigationController.java @@ -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 weatherData = weatherGrabber.getWeatherData(); - // TODO: Replace this with the WeatherGrabber.getWeatherData() above -// List weatherData = new ArrayList(); // 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; } diff --git a/benchmarks/Java/IrrigationController/LawnState.java b/benchmarks/Java/IrrigationController/LawnState.java index 10ac4f0..3558354 100644 --- a/benchmarks/Java/IrrigationController/LawnState.java +++ b/benchmarks/Java/IrrigationController/LawnState.java @@ -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 index 0000000..909e24c --- /dev/null +++ b/benchmarks/Java/IrrigationController/test_version/IrrigationController.java @@ -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 lawns = new ArrayList(); + 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 inchesPerMinute; + + private static int sensorId = 0; + + /******************************************************************************************************************************************* + ** + ** IoT Sets and Relations + ** + *******************************************************************************************************************************************/ + @config private IoTSet weatherDataAddresses; + @config private IoTSet weatherDataAddressMain; + @config private IoTSet gwSet; + @config private IoTSet lawnSet; + @config private IoTSet moistureSensorsSet; + @config private IoTSet cameraSet; + @config private IoTRelation lawnCameraRelation; + @config private IoTRelation lawnSprinklerRelation; + @config private IoTRelation 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(); + + // 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 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 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 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 weatherData = weatherGrabber.getWeatherData(); + // TODO: Replace this with the WeatherGrabber.getWeatherData() above +// List weatherData = new ArrayList(); + + // 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 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 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] latest weather data + * + * @return [void] None. + */ + private void waterLawn(LawnState _ls, Date _currentDate, List _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 index 0000000..10ac4f0 --- /dev/null +++ b/benchmarks/Java/IrrigationController/test_version/LawnState.java @@ -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 + * @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 daysRained = new ArrayList(); + 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 moistureSensorReadings = + new ConcurrentHashMap(); + private Map moistureSensorUpdateTimes = + new ConcurrentHashMap(); + + + // 0th bit = Monday, 1th bit = Tuesday ext + public LawnState(LawnSmart _l, int _daysToWaterOn, MotionDetection _mo, + double _inchesPerMinute, double _inchesPerWeek, SprinklerSmart _sprinkler, + int _zone, Set _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; + } +} + + + + + + + + + + + diff --git a/benchmarks/drivers/Java/BlossomSprinkler/BlossomSprinkler.java b/benchmarks/drivers/Java/BlossomSprinkler/BlossomSprinkler.java index dc05c0d..209b2fe 100644 --- a/benchmarks/drivers/Java/BlossomSprinkler/BlossomSprinkler.java +++ b/benchmarks/drivers/Java/BlossomSprinkler/BlossomSprinkler.java @@ -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) {