extensions/net.sf.basedb.labenv/trunk/src/net/sf/basedb/labenv/LabEnvironment.java

Code
Comments
Other
Rev Date Author Line
2303 02 Apr 14 olle 1 package net.sf.basedb.labenv;
2303 02 Apr 14 olle 2
2303 02 Apr 14 olle 3 import java.util.ArrayList;
2303 02 Apr 14 olle 4 import java.util.Date;
2303 02 Apr 14 olle 5 import java.util.HashMap;
2303 02 Apr 14 olle 6 import java.util.List;
3014 05 Dec 14 nicklas 7 import java.util.TimerTask;
2303 02 Apr 14 olle 8
3017 08 Dec 14 nicklas 9 import org.hibernate.Session;
3017 08 Dec 14 nicklas 10 import org.hibernate.SessionFactory;
2328 08 Apr 14 olle 11 import org.slf4j.Logger;
2328 08 Apr 14 olle 12 import org.slf4j.LoggerFactory;
2303 02 Apr 14 olle 13
3014 05 Dec 14 nicklas 14 import net.sf.basedb.core.Application;
3017 08 Dec 14 nicklas 15 import net.sf.basedb.core.DbControl;
3014 05 Dec 14 nicklas 16 import net.sf.basedb.core.ServiceSessionControl;
3014 05 Dec 14 nicklas 17 import net.sf.basedb.core.SessionControl;
3874 25 Apr 16 nicklas 18 import net.sf.basedb.core.ServiceSessionControl.SessionFactoryConfiguration;
2432 16 May 14 olle 19 import net.sf.basedb.labenv.dao.EmailConfig;
2303 02 Apr 14 olle 20 import net.sf.basedb.labenv.dao.LabEnvironmentData;
2303 02 Apr 14 olle 21 import net.sf.basedb.labenv.dao.LabSensorAlarmConfig;
2424 14 May 14 olle 22 import net.sf.basedb.labenv.dao.LabSensorAlarmUserConfig;
2303 02 Apr 14 olle 23 import net.sf.basedb.labenv.dao.LabSensorConfig;
3017 08 Dec 14 nicklas 24 import net.sf.basedb.labenv.entity.SensorData;
2415 09 May 14 olle 25 import net.sf.basedb.labenv.servlet.LabEnvironmentStatisticsServlet;
2303 02 Apr 14 olle 26 import net.sf.basedb.labenv.util.LabEnvironmentStorageUtil;
2303 02 Apr 14 olle 27 import net.sf.basedb.labenv.util.LabSensorUtil;
2432 16 May 14 olle 28 import net.sf.basedb.labenv.util.MailUtil;
2418 12 May 14 olle 29 import net.sf.basedb.util.Values;
2303 02 Apr 14 olle 30 import net.sf.basedb.util.formatter.DateFormatter;
2303 02 Apr 14 olle 31
2303 02 Apr 14 olle 32 public class LabEnvironment
2303 02 Apr 14 olle 33 {
2303 02 Apr 14 olle 34   // Singleton
2303 02 Apr 14 olle 35   private static LabEnvironment instance = null;
2303 02 Apr 14 olle 36   
2328 08 Apr 14 olle 37   private static final Logger log = LoggerFactory.getLogger(LabEnvironment.class);
2303 02 Apr 14 olle 38   
3014 05 Dec 14 nicklas 39   private volatile boolean isRunning;
3014 05 Dec 14 nicklas 40   private TimerTask timer;
3017 08 Dec 14 nicklas 41   private ServiceSessionControl sessionControl;
3017 08 Dec 14 nicklas 42   private SessionFactory sessionFactory;
3014 05 Dec 14 nicklas 43   
2418 12 May 14 olle 44   private final int numberOfDecimals = 2;
2418 12 May 14 olle 45
2303 02 Apr 14 olle 46   // Instance variables connected to measurement cycle per stored value
2303 02 Apr 14 olle 47   private HashMap<Integer, Integer> measurementNumberInCycleHashMap;
2303 02 Apr 14 olle 48   private HashMap<Integer, Long> accMeasurementUnixTimeInSecondsHashMap;
2303 02 Apr 14 olle 49   private HashMap<Integer, List<Double>> sensorTemperatureInCycleHashMap;
2303 02 Apr 14 olle 50   private HashMap<Integer, List<Double>> sensorHumidityInCycleHashMap;
2415 09 May 14 olle 51   
2303 02 Apr 14 olle 52   protected LabEnvironment()
2303 02 Apr 14 olle 53   {
2303 02 Apr 14 olle 54     // Exists only to defeat instantiation
2303 02 Apr 14 olle 55     if (this.labEnvironmentConfiguration == null)
2303 02 Apr 14 olle 56     {
2303 02 Apr 14 olle 57       this.labEnvironmentConfiguration = new LabEnvironmentConfiguration();
2303 02 Apr 14 olle 58     }
2303 02 Apr 14 olle 59     this.measurementNumberInCycleHashMap = new HashMap<Integer, Integer>();
2303 02 Apr 14 olle 60     this.accMeasurementUnixTimeInSecondsHashMap = new HashMap<Integer, Long>();
2303 02 Apr 14 olle 61     this.sensorTemperatureInCycleHashMap = new HashMap<Integer, List<Double>>();
2303 02 Apr 14 olle 62     this.sensorHumidityInCycleHashMap = new HashMap<Integer, List<Double>>();
2303 02 Apr 14 olle 63   }
2303 02 Apr 14 olle 64
2303 02 Apr 14 olle 65   public static LabEnvironment getInstance()
2303 02 Apr 14 olle 66   {
2303 02 Apr 14 olle 67     if (instance == null)
2303 02 Apr 14 olle 68     {
3014 05 Dec 14 nicklas 69       synchronized (LabEnvironment.class) 
3014 05 Dec 14 nicklas 70       {
3014 05 Dec 14 nicklas 71         if (instance == null)
3014 05 Dec 14 nicklas 72         {
3014 05 Dec 14 nicklas 73           LabEnvironment tmp = new LabEnvironment();
3014 05 Dec 14 nicklas 74           instance = tmp;
3014 05 Dec 14 nicklas 75         }
3014 05 Dec 14 nicklas 76       }
2303 02 Apr 14 olle 77     }
2303 02 Apr 14 olle 78     return instance;
2303 02 Apr 14 olle 79   }
2303 02 Apr 14 olle 80
3014 05 Dec 14 nicklas 81   /**
3014 05 Dec 14 nicklas 82     Is the Lab environment running or not?
3014 05 Dec 14 nicklas 83     @since 1.3
3014 05 Dec 14 nicklas 84   */
3014 05 Dec 14 nicklas 85   public boolean isRunning()
3014 05 Dec 14 nicklas 86   {
3014 05 Dec 14 nicklas 87     return isRunning;
3014 05 Dec 14 nicklas 88   }
3014 05 Dec 14 nicklas 89
3014 05 Dec 14 nicklas 90   /**
3014 05 Dec 14 nicklas 91     Start the service if it is not running.
3014 05 Dec 14 nicklas 92     @since 1.3
3014 05 Dec 14 nicklas 93   */
3017 08 Dec 14 nicklas 94   public synchronized void start(SessionControl sc)
3014 05 Dec 14 nicklas 95   {
3014 05 Dec 14 nicklas 96     if (!isRunning)
3014 05 Dec 14 nicklas 97     {
3014 05 Dec 14 nicklas 98       log.debug("Starting Lab environment service");
3017 08 Dec 14 nicklas 99       
3014 05 Dec 14 nicklas 100       // Force reloading configuration file when service is started again
3014 05 Dec 14 nicklas 101       reloadLabEnvironmentConfiguration();
3017 08 Dec 14 nicklas 102
3014 05 Dec 14 nicklas 103       // Get timer interval from configuration
3014 05 Dec 14 nicklas 104       long measurementIntervalInSeconds = getLabEnvironmentConfiguration().getMeasurementIntervalInSeconds();
3014 05 Dec 14 nicklas 105       long interval = measurementIntervalInSeconds * 1000; // Convert to milliseconds
3014 05 Dec 14 nicklas 106       log.debug("Measurement interval in seconds set to = " + measurementIntervalInSeconds);
3017 08 Dec 14 nicklas 107       
3017 08 Dec 14 nicklas 108       if (sc instanceof ServiceSessionControl)
3017 08 Dec 14 nicklas 109       {
3017 08 Dec 14 nicklas 110         ServiceSessionControl ssc = (ServiceSessionControl)sc;
3014 05 Dec 14 nicklas 111
3874 25 Apr 16 nicklas 112         // ----------------------------------------------------------------------
3874 25 Apr 16 nicklas 113         // Important! Update the schema version when adding new tables or columns
3874 25 Apr 16 nicklas 114         // ----------------------------------------------------------------------
3874 25 Apr 16 nicklas 115         final int LABENV_SCHEMA_VERSION = 1;
3874 25 Apr 16 nicklas 116         final String LABENV_SCHEMA_NAME = "labenv";
3874 25 Apr 16 nicklas 117         final String LABENV_APP_ID = "net.sf.basedb.labenv";
3874 25 Apr 16 nicklas 118         
3017 08 Dec 14 nicklas 119         /*
3017 08 Dec 14 nicklas 120           Tell BASE that we want a Hibernate SessionFactory for
3874 25 Apr 16 nicklas 121           the 'labenv' schema.
3017 08 Dec 14 nicklas 122         */
3874 25 Apr 16 nicklas 123         SessionFactoryConfiguration sfConfig = ssc.createSessionFactoryConfiguration(
3874 25 Apr 16 nicklas 124             LABENV_APP_ID, LABENV_SCHEMA_NAME, LABENV_SCHEMA_VERSION, LabEnvironment.class.getClassLoader()
3874 25 Apr 16 nicklas 125           );
3017 08 Dec 14 nicklas 126         
3874 25 Apr 16 nicklas 127         if (log.isDebugEnabled())
3874 25 Apr 16 nicklas 128         {
3874 25 Apr 16 nicklas 129           log.debug("Building SessionFactory: actualCatalog="+sfConfig.getActualCatalog()+"; actualSchema="+sfConfig.getActualSchema());
3874 25 Apr 16 nicklas 130           log.debug("installMode="+sfConfig.getInstallMode()+"; installedSchemaVersion="+sfConfig.getInstalledSchemaVersion());
3874 25 Apr 16 nicklas 131         }
3017 08 Dec 14 nicklas 132         
3874 25 Apr 16 nicklas 133         // Our only entity so far is the SensorData class which maps to SensorData table in this schema.
3874 25 Apr 16 nicklas 134         sfConfig.getMetadataSources().addAnnotatedClass(SensorData.class);
3874 25 Apr 16 nicklas 135         
3017 08 Dec 14 nicklas 136         sessionControl = ssc;
3017 08 Dec 14 nicklas 137         sessionFactory = ssc.buildSessionFactory(sfConfig);
3017 08 Dec 14 nicklas 138       }
3017 08 Dec 14 nicklas 139       
3014 05 Dec 14 nicklas 140       // Start new timer
3014 05 Dec 14 nicklas 141       timer = new TimerTask()
3022 09 Dec 14 nicklas 142       {
3014 05 Dec 14 nicklas 143         @Override
3014 05 Dec 14 nicklas 144         public void run()
3014 05 Dec 14 nicklas 145         {
3017 08 Dec 14 nicklas 146           DbControl dc = null;
3017 08 Dec 14 nicklas 147           Session session = null;
3014 05 Dec 14 nicklas 148           try
3017 08 Dec 14 nicklas 149           {
3017 08 Dec 14 nicklas 150             dc = getInstance().newDbControl();
3017 08 Dec 14 nicklas 151             session = getInstance().newSession(dc);
3017 08 Dec 14 nicklas 152             measureAndStoreLabEnvironmentData(session);
3017 08 Dec 14 nicklas 153             dc.commit();
3014 05 Dec 14 nicklas 154           }
3014 05 Dec 14 nicklas 155           catch (Exception e)
3014 05 Dec 14 nicklas 156           {
3017 08 Dec 14 nicklas 157             log.error("start(): Catched exception e: ", e);
3014 05 Dec 14 nicklas 158           }
3017 08 Dec 14 nicklas 159           finally
3017 08 Dec 14 nicklas 160           {
3021 09 Dec 14 nicklas 161             if (dc != null) dc.close();
3017 08 Dec 14 nicklas 162           }
3014 05 Dec 14 nicklas 163         }
3014 05 Dec 14 nicklas 164       };
3014 05 Dec 14 nicklas 165       
3017 08 Dec 14 nicklas 166       isRunning = true;
3022 09 Dec 14 nicklas 167       timer = Application.getScheduler().schedule(timer, 1000, interval, false);
3017 08 Dec 14 nicklas 168
3014 05 Dec 14 nicklas 169       log.debug("Lab environment service is now running");
3014 05 Dec 14 nicklas 170     }
3014 05 Dec 14 nicklas 171   }
3014 05 Dec 14 nicklas 172
3014 05 Dec 14 nicklas 173   /**
3014 05 Dec 14 nicklas 174     Stop the service if it is running.
3014 05 Dec 14 nicklas 175     @since 1.3
3014 05 Dec 14 nicklas 176   */
3014 05 Dec 14 nicklas 177   public synchronized void stop()
3014 05 Dec 14 nicklas 178   {
3014 05 Dec 14 nicklas 179     if (isRunning)
3014 05 Dec 14 nicklas 180     {
3014 05 Dec 14 nicklas 181       log.debug("Stopping Lab environment cluster service");
3014 05 Dec 14 nicklas 182       if (timer != null)
3014 05 Dec 14 nicklas 183       {
3017 08 Dec 14 nicklas 184         try
3017 08 Dec 14 nicklas 185         {
3017 08 Dec 14 nicklas 186           timer.cancel();
3017 08 Dec 14 nicklas 187           timer = null;
3017 08 Dec 14 nicklas 188         }
3017 08 Dec 14 nicklas 189         catch (Throwable t)
3017 08 Dec 14 nicklas 190         {}
3014 05 Dec 14 nicklas 191       }
3017 08 Dec 14 nicklas 192       if (sessionFactory != null)
3017 08 Dec 14 nicklas 193       {
3017 08 Dec 14 nicklas 194         try
3017 08 Dec 14 nicklas 195         {
3017 08 Dec 14 nicklas 196           sessionFactory.close();
3017 08 Dec 14 nicklas 197           sessionFactory = null;
3017 08 Dec 14 nicklas 198         }
3017 08 Dec 14 nicklas 199         catch (Throwable t)
3017 08 Dec 14 nicklas 200         {}
3017 08 Dec 14 nicklas 201       }
3017 08 Dec 14 nicklas 202       if (sessionControl != null)
3017 08 Dec 14 nicklas 203       {
3017 08 Dec 14 nicklas 204         try
3017 08 Dec 14 nicklas 205         {
3017 08 Dec 14 nicklas 206           sessionControl.close();
3017 08 Dec 14 nicklas 207           sessionControl = null;
3017 08 Dec 14 nicklas 208         }
3017 08 Dec 14 nicklas 209         catch (Throwable t)
3017 08 Dec 14 nicklas 210         {}
3017 08 Dec 14 nicklas 211       }
3014 05 Dec 14 nicklas 212       isRunning = false;
3014 05 Dec 14 nicklas 213       log.debug("Lab environment service has stopped");
3014 05 Dec 14 nicklas 214     }
3014 05 Dec 14 nicklas 215   }
3014 05 Dec 14 nicklas 216
3017 08 Dec 14 nicklas 217   public DbControl newDbControl()
3017 08 Dec 14 nicklas 218   {
3017 08 Dec 14 nicklas 219     return sessionControl != null ? sessionControl.newDbControl() : null;
3017 08 Dec 14 nicklas 220   }
3014 05 Dec 14 nicklas 221   
3017 08 Dec 14 nicklas 222   public Session newSession(DbControl dc)
3017 08 Dec 14 nicklas 223   {
3017 08 Dec 14 nicklas 224     return sessionControl.newSession(sessionFactory.withOptions(), dc);
3017 08 Dec 14 nicklas 225   }
3017 08 Dec 14 nicklas 226   
2303 02 Apr 14 olle 227   private LabEnvironmentConfiguration labEnvironmentConfiguration;
2303 02 Apr 14 olle 228
2303 02 Apr 14 olle 229   public LabEnvironmentConfiguration getLabEnvironmentConfiguration()
2303 02 Apr 14 olle 230   {
2303 02 Apr 14 olle 231     return this.labEnvironmentConfiguration;
2303 02 Apr 14 olle 232   }
2303 02 Apr 14 olle 233
2415 09 May 14 olle 234   public void setLabEnvironmentConfiguration(LabEnvironmentConfiguration labEnvironmentConfiguration)
2415 09 May 14 olle 235   {
2415 09 May 14 olle 236     this.labEnvironmentConfiguration = labEnvironmentConfiguration;
2415 09 May 14 olle 237   }
2415 09 May 14 olle 238
2326 07 Apr 14 olle 239   public void reloadLabEnvironmentConfiguration()
2326 07 Apr 14 olle 240   {
2326 07 Apr 14 olle 241     this.labEnvironmentConfiguration = new LabEnvironmentConfiguration();
2326 07 Apr 14 olle 242   }
2326 07 Apr 14 olle 243
3017 08 Dec 14 nicklas 244     public void measureAndStoreLabEnvironmentData(Session session)
2303 02 Apr 14 olle 245     {
2303 02 Apr 14 olle 246     // Get current dateTime
2303 02 Apr 14 olle 247     Date measurementTime = new Date();
2303 02 Apr 14 olle 248     // Get lab environment configuration
2303 02 Apr 14 olle 249     LabEnvironmentConfiguration labEnvironmentConfiguration = getLabEnvironmentConfiguration();
2303 02 Apr 14 olle 250     List<LabSensorConfig> labSensorConfigList = labEnvironmentConfiguration.getLabSensorConfigList();
2303 02 Apr 14 olle 251       // Get lab sensor measurements and store data with chosen time interval
2303 02 Apr 14 olle 252     int timeoutInSeconds = labEnvironmentConfiguration.getTimeoutInSeconds();
2303 02 Apr 14 olle 253       LabSensorUtil labSensorUtil = new LabSensorUtil(timeoutInSeconds);
3018 09 Dec 14 nicklas 254     LabEnvironmentStorageUtil storage = new LabEnvironmentStorageUtil();
2303 02 Apr 14 olle 255     for (LabSensorConfig labSensorConfig: labSensorConfigList)
2303 02 Apr 14 olle 256     {
3018 09 Dec 14 nicklas 257         measureAndStoreLabEnvironmentData(session, storage, labSensorUtil, labSensorConfig, measurementTime);
2303 02 Apr 14 olle 258     }      
2303 02 Apr 14 olle 259     }
2303 02 Apr 14 olle 260
2303 02 Apr 14 olle 261
3018 09 Dec 14 nicklas 262     private void measureAndStoreLabEnvironmentData(Session session, LabEnvironmentStorageUtil storage, LabSensorUtil labSensorUtil, LabSensorConfig labSensorConfig, Date measurementTime)
2303 02 Apr 14 olle 263     {
2303 02 Apr 14 olle 264       if (labSensorUtil == null)
2303 02 Apr 14 olle 265       {
2303 02 Apr 14 olle 266         int timeoutInSeconds = getLabEnvironmentConfiguration().getTimeoutInSeconds();
2303 02 Apr 14 olle 267           labSensorUtil = new LabSensorUtil(timeoutInSeconds);
2303 02 Apr 14 olle 268       }
2303 02 Apr 14 olle 269       // Get lab sensor measurements and store data
2303 02 Apr 14 olle 270     String labSensorUrl = labSensorConfig.getUrl();
2303 02 Apr 14 olle 271     // Only use active sensors
2303 02 Apr 14 olle 272     if (labSensorUrl != null && labSensorConfig.getStartDate() != null)
2303 02 Apr 14 olle 273     {
2303 02 Apr 14 olle 274       int sensorNumber = labSensorConfig.getNumber();
2303 02 Apr 14 olle 275       // Increment measurementNumberCycle for sensor
2303 02 Apr 14 olle 276       Integer measurementNumberInCycle = measurementNumberInCycleHashMap.get(sensorNumber);
2303 02 Apr 14 olle 277       if (measurementNumberInCycle == null)
2303 02 Apr 14 olle 278       {
2303 02 Apr 14 olle 279         measurementNumberInCycle = 0;
2303 02 Apr 14 olle 280       }
2303 02 Apr 14 olle 281       measurementNumberInCycle++;
2303 02 Apr 14 olle 282       measurementNumberInCycleHashMap.put(sensorNumber, measurementNumberInCycle);
2303 02 Apr 14 olle 283       // Update accumulated measurement time for sensor
2303 02 Apr 14 olle 284       Long accMeasurementUnixTimeInSeconds = accMeasurementUnixTimeInSecondsHashMap.get(sensorNumber);
2303 02 Apr 14 olle 285       if (accMeasurementUnixTimeInSeconds == null)
2303 02 Apr 14 olle 286       {
2303 02 Apr 14 olle 287         accMeasurementUnixTimeInSeconds = 0L;
2303 02 Apr 14 olle 288       }
2303 02 Apr 14 olle 289       accMeasurementUnixTimeInSeconds += measurementTime.getTime()/1000L;
2303 02 Apr 14 olle 290       accMeasurementUnixTimeInSecondsHashMap.put(sensorNumber, accMeasurementUnixTimeInSeconds);
3020 09 Dec 14 nicklas 291       LabEnvironmentData labEnvironmentData = labSensorUtil.createLabEnvironmentData(labSensorUrl, false);
2303 02 Apr 14 olle 292       // Update HashMap with new lab environment for sensor
2303 02 Apr 14 olle 293       List<Double> temperatureList = sensorTemperatureInCycleHashMap.get(sensorNumber);
2303 02 Apr 14 olle 294       if (temperatureList == null)
2303 02 Apr 14 olle 295       {
2303 02 Apr 14 olle 296         temperatureList = new ArrayList<Double>();
2303 02 Apr 14 olle 297       }
2303 02 Apr 14 olle 298       List<Double> humidityList = sensorHumidityInCycleHashMap.get(sensorNumber);
2303 02 Apr 14 olle 299       if (humidityList == null)
2303 02 Apr 14 olle 300       {
2303 02 Apr 14 olle 301         humidityList = new ArrayList<Double>();
2303 02 Apr 14 olle 302       }
2303 02 Apr 14 olle 303       if (labEnvironmentData != null)
2303 02 Apr 14 olle 304       {
2303 02 Apr 14 olle 305         double temperature = labEnvironmentData.getTemperature();
2303 02 Apr 14 olle 306         temperatureList.add(temperature);
2303 02 Apr 14 olle 307         double humidity = labEnvironmentData.getHumidity();
2303 02 Apr 14 olle 308         humidityList.add(humidity);
2303 02 Apr 14 olle 309       }
2303 02 Apr 14 olle 310       else
2303 02 Apr 14 olle 311       {
2303 02 Apr 14 olle 312         temperatureList.add(null);
2303 02 Apr 14 olle 313         humidityList.add(null);
2303 02 Apr 14 olle 314         log.debug("labEnvironmentData == null");
2303 02 Apr 14 olle 315       }
2303 02 Apr 14 olle 316       // Update lab environment HashMaps
2303 02 Apr 14 olle 317       sensorTemperatureInCycleHashMap.put(sensorNumber, temperatureList);
2303 02 Apr 14 olle 318       sensorHumidityInCycleHashMap.put(sensorNumber, humidityList);
2303 02 Apr 14 olle 319       // Check if value should be stored
2303 02 Apr 14 olle 320       int numberOfMeasurementsPerStoredValue = getLabEnvironmentConfiguration().getNumberOfMeasurementsPerStoredValue();
2303 02 Apr 14 olle 321       measurementNumberInCycle = measurementNumberInCycleHashMap.get(sensorNumber);
2303 02 Apr 14 olle 322       log.debug("sensorNumber = " + sensorNumber + " measurementNumberInCycle = " + measurementNumberInCycle + " numberOfMeasurementsPerStoredValue = " + numberOfMeasurementsPerStoredValue);
2303 02 Apr 14 olle 323       if (measurementNumberInCycle >= numberOfMeasurementsPerStoredValue)
2303 02 Apr 14 olle 324       {
2303 02 Apr 14 olle 325         // Get averaged values
2303 02 Apr 14 olle 326         temperatureList = sensorTemperatureInCycleHashMap.get(sensorNumber);
2303 02 Apr 14 olle 327         log.debug("sensorNumber = " + sensorNumber + " temperatureList = " + temperatureList);
2303 02 Apr 14 olle 328         Double averageTemperature = averageValue(temperatureList);
2303 02 Apr 14 olle 329         log.debug("sensorNumber = " + sensorNumber + " averageTemperature = " + averageTemperature);
2303 02 Apr 14 olle 330         humidityList = sensorHumidityInCycleHashMap.get(sensorNumber);
2303 02 Apr 14 olle 331         log.debug("sensorNumber = " + sensorNumber + " humidityList = " + humidityList);
2303 02 Apr 14 olle 332         Double averageHumidity = averageValue(humidityList);
2303 02 Apr 14 olle 333         log.debug("sensorNumber = " + sensorNumber + " averageHumidity = " + averageHumidity);
2424 14 May 14 olle 334         // Get server system time stamp
2424 14 May 14 olle 335         accMeasurementUnixTimeInSeconds = accMeasurementUnixTimeInSecondsHashMap.get(sensorNumber);
2424 14 May 14 olle 336         long unixTimeInSeconds = accMeasurementUnixTimeInSeconds/measurementNumberInCycle;
2424 14 May 14 olle 337         Date storedMeasurementTime = new Date(unixTimeInSeconds*1000L);
2303 02 Apr 14 olle 338         if (averageTemperature != null && averageHumidity != null)
2303 02 Apr 14 olle 339         {
2424 14 May 14 olle 340           // Update database with sensor data using server system time stamp
3018 09 Dec 14 nicklas 341           storage.updateLabEnvDb(session, sensorNumber, storedMeasurementTime, averageTemperature, averageHumidity);
2303 02 Apr 14 olle 342         }
2424 14 May 14 olle 343         // Check if alarm should be reported
2424 14 May 14 olle 344         checkAlarms(labSensorUrl, storedMeasurementTime, averageTemperature, averageHumidity);
2303 02 Apr 14 olle 345         // Reset values for next cycle
2303 02 Apr 14 olle 346         measurementNumberInCycleHashMap.put(sensorNumber, 0);
2303 02 Apr 14 olle 347         accMeasurementUnixTimeInSecondsHashMap.put(sensorNumber, 0L);
2303 02 Apr 14 olle 348         sensorTemperatureInCycleHashMap.put(sensorNumber, null);
2303 02 Apr 14 olle 349         sensorHumidityInCycleHashMap.put(sensorNumber, null);
2303 02 Apr 14 olle 350       }    
2303 02 Apr 14 olle 351     }
2303 02 Apr 14 olle 352     }
2303 02 Apr 14 olle 353
2303 02 Apr 14 olle 354
2303 02 Apr 14 olle 355     /**
2303 02 Apr 14 olle 356      * Returns average value of input list of Double values,
2303 02 Apr 14 olle 357      * ignoring `null` values. Returns `null` if list is `null`,
2303 02 Apr 14 olle 358      * or all values in list are `null`.
2303 02 Apr 14 olle 359      * 
2303 02 Apr 14 olle 360      * @param dataList List<Double> List of input values to average.
2303 02 Apr 14 olle 361      * @return Double Average value of input list, ignoring `null` values.
2303 02 Apr 14 olle 362      */
2303 02 Apr 14 olle 363     private Double averageValue(List<Double> dataList)
2303 02 Apr 14 olle 364     {
2303 02 Apr 14 olle 365     // Calculate averaged value, ignoring null values
2303 02 Apr 14 olle 366     int numValues = 0;
2303 02 Apr 14 olle 367     double accumValue = 0.0;
2303 02 Apr 14 olle 368     if (dataList != null)
2303 02 Apr 14 olle 369     {
2303 02 Apr 14 olle 370       for (Double value: dataList)
2303 02 Apr 14 olle 371       {
2303 02 Apr 14 olle 372         if (value != null)
2303 02 Apr 14 olle 373         {
2303 02 Apr 14 olle 374           numValues++;
2303 02 Apr 14 olle 375           accumValue += value;
2303 02 Apr 14 olle 376         }
2303 02 Apr 14 olle 377       }
2303 02 Apr 14 olle 378     }
2303 02 Apr 14 olle 379     Double averageValue = null;
2303 02 Apr 14 olle 380     if (numValues > 0)
2303 02 Apr 14 olle 381     {
2303 02 Apr 14 olle 382       averageValue = accumValue/numValues;
2303 02 Apr 14 olle 383     }
2303 02 Apr 14 olle 384     return averageValue;
2303 02 Apr 14 olle 385     }
2303 02 Apr 14 olle 386
2303 02 Apr 14 olle 387
2303 02 Apr 14 olle 388     public void checkAlarms(String labSensorUrl, Date measurementTime, LabEnvironmentData labEnvironmentData)
2303 02 Apr 14 olle 389     {
2303 02 Apr 14 olle 390       if (labEnvironmentData != null)
2303 02 Apr 14 olle 391       {
2303 02 Apr 14 olle 392         double temperature = labEnvironmentData.getTemperature();
2303 02 Apr 14 olle 393         double humidity = labEnvironmentData.getHumidity();
2303 02 Apr 14 olle 394         checkAlarms(labSensorUrl, measurementTime, temperature, humidity);
2303 02 Apr 14 olle 395       }
2303 02 Apr 14 olle 396     }
2303 02 Apr 14 olle 397
2303 02 Apr 14 olle 398
2424 14 May 14 olle 399     public void checkAlarms(String labSensorUrl, Date measurementTime, Double temperature, Double humidity)
2303 02 Apr 14 olle 400     {
2415 09 May 14 olle 401       log.debug("checkAlarms(): labSensorUrl = " + labSensorUrl + " measurementTime = " + measurementTime + " temperature = " + temperature + " humidity = " + humidity);
2303 02 Apr 14 olle 402       if (labSensorUrl != null)
2303 02 Apr 14 olle 403       {
2303 02 Apr 14 olle 404         // Get lab environment configuration
2303 02 Apr 14 olle 405         LabEnvironmentConfiguration labEnvironmentConfiguration = getLabEnvironmentConfiguration();
2303 02 Apr 14 olle 406         LabSensorConfig labSensorConfig = labEnvironmentConfiguration.findByUrl(labSensorUrl);
2415 09 May 14 olle 407         int sensorNumber = labSensorConfig.getNumber();
2415 09 May 14 olle 408         log.debug("checkAlarms(): labSensorUrl = " + labSensorUrl + " sensorNumber = " + sensorNumber + " measurementTime = " + measurementTime + " temperature = " + temperature + " humidity = " + humidity);
2424 14 May 14 olle 409       String temperatureStr = null;
2424 14 May 14 olle 410       String humidityStr = null;
2424 14 May 14 olle 411       if (temperature != null)
2424 14 May 14 olle 412       {
2424 14 May 14 olle 413         temperatureStr = Values.formatNumber(temperature.floatValue(), numberOfDecimals);
2424 14 May 14 olle 414       }
2424 14 May 14 olle 415       if (humidity != null)
2424 14 May 14 olle 416       {
2424 14 May 14 olle 417         humidityStr = Values.formatNumber(humidity.floatValue(), numberOfDecimals);
2424 14 May 14 olle 418       }
2303 02 Apr 14 olle 419         List<LabSensorAlarmConfig> alarmList = labSensorConfig.getAlarmList();
2303 02 Apr 14 olle 420         if (alarmList != null)
2303 02 Apr 14 olle 421         {
2424 14 May 14 olle 422           for (LabSensorAlarmConfig alarm: alarmList)
2303 02 Apr 14 olle 423           {
2424 14 May 14 olle 424             if (alarm != null)
2303 02 Apr 14 olle 425             {
2424 14 May 14 olle 426               String startTime = alarm.getStartTime();
2303 02 Apr 14 olle 427               if (startTime != null)
2303 02 Apr 14 olle 428               {
4534 21 Jun 17 nicklas 429                 List<String> alarmTexts = new ArrayList<>();
2466 02 Jun 14 olle 430                 Integer alarmType = null;
2424 14 May 14 olle 431                 if (temperature != null && humidity != null)
2424 14 May 14 olle 432                 {
2424 14 May 14 olle 433                     long startTimeSecondsFromMidnight = alarm.getStartTimeSecondsFromMidnight();
2424 14 May 14 olle 434                     long endTimeSecondsFromMidnight = alarm.getEndTimeSecondsFromMidnight();
2424 14 May 14 olle 435                     String weekdayFilter = alarm.getWeekdayFilter();
2424 14 May 14 olle 436                     boolean performCheck = activeAlarm(measurementTime, startTimeSecondsFromMidnight, endTimeSecondsFromMidnight, weekdayFilter);
2424 14 May 14 olle 437                     log.debug("checkAlarms(): alarmNo = " + alarm.getNo() + " performCheck = " + performCheck);
2424 14 May 14 olle 438                     if (performCheck)
2424 14 May 14 olle 439                     {                 
2424 14 May 14 olle 440                         Double temperatureMin = alarm.getTemperatureMin();
2424 14 May 14 olle 441                         Double temperatureMax = alarm.getTemperatureMax();
2424 14 May 14 olle 442                         Double humidityMin = alarm.getHumidityMin();
2424 14 May 14 olle 443                         Double humidityMax = alarm.getHumidityMax();
2424 14 May 14 olle 444                         List<LabSensorAlarmUserConfig> userList = alarm.getUserList();
4534 21 Jun 17 nicklas 445                         if (temperatureMin != null && temperature < temperatureMin)
4534 21 Jun 17 nicklas 446                          {
4534 21 Jun 17 nicklas 447                             alarmTexts.add("temperature " + temperatureStr + " < " + temperatureMin);
4534 21 Jun 17 nicklas 448                          }
4534 21 Jun 17 nicklas 449                         if (temperatureMax != null && temperature > temperatureMax)
2424 14 May 14 olle 450                         {
4534 21 Jun 17 nicklas 451                           alarmTexts.add("temperature " + temperatureStr + " > " + temperatureMax);
2424 14 May 14 olle 452                         }
4534 21 Jun 17 nicklas 453                         if (humidityMin != null && humidity < humidityMin)
2424 14 May 14 olle 454                         {
4534 21 Jun 17 nicklas 455                           alarmTexts.add("humidity " + humidityStr + " < " + humidityMin);
2424 14 May 14 olle 456                         }
4534 21 Jun 17 nicklas 457                         if (humidityMax != null && humidity > humidityMax)
2424 14 May 14 olle 458                         {
4534 21 Jun 17 nicklas 459                           alarmTexts.add("humidity " + humidityStr + " > " + humidityMax);
2424 14 May 14 olle 460                         }
2466 02 Jun 14 olle 461                         // Set alarm type if alarm should be reported
4534 21 Jun 17 nicklas 462                         if (alarmTexts.size() > 0)
2466 02 Jun 14 olle 463                           {
2466 02 Jun 14 olle 464                           alarmType = LabSensorAlarmConfig.ALARM_BLOCK_TYPE_LAB_ENVIRONMENT_DATA;
2466 02 Jun 14 olle 465                           }
2303 02 Apr 14 olle 466                     }
2424 14 May 14 olle 467                 }
2424 14 May 14 olle 468                 else
2424 14 May 14 olle 469                 {
4534 21 Jun 17 nicklas 470                   alarmTexts.add("Missing data");
2466 02 Jun 14 olle 471                   alarmType = LabSensorAlarmConfig.ALARM_BLOCK_TYPE_MISSING_DATA;
2424 14 May 14 olle 472                 }
4534 21 Jun 17 nicklas 473               if (alarmTexts.size() > 0)
2424 14 May 14 olle 474               {
2424 14 May 14 olle 475                 // Add measurement time and alarm no to alarm text
2424 14 May 14 olle 476                 DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd HH:mm");
2424 14 May 14 olle 477                 String dateStr = dateFormat.format(measurementTime);
4534 21 Jun 17 nicklas 478                 
4534 21 Jun 17 nicklas 479                 String alarmStr = dateStr + ": " + Values.getString(alarmTexts, ", ", true);
4534 21 Jun 17 nicklas 480                 //alarmStr = "Alarm (" + alarm.getNo() + ") " + labSensorUrl + " " + dateStr + ": " + alarmStr;
4534 21 Jun 17 nicklas 481
2424 14 May 14 olle 482                 // Check if alarm has already been reported
2424 14 May 14 olle 483                 Boolean alarmBlocked = alarm.isAlarmBlocked();
2466 02 Jun 14 olle 484                 Integer alarmBlockType = alarm.getAlarmBlockType();
2424 14 May 14 olle 485                 log.debug("labSensorUrl " + labSensorUrl + " alarmBlocked (" + alarm.getNo() + ") " + alarmBlocked);
2466 02 Jun 14 olle 486                 // Report alarm if alarm not blocked or if blocked alarm is of type missing data and current alarm is not
2466 02 Jun 14 olle 487                 if (alarmBlocked == null
2466 02 Jun 14 olle 488                   || !alarmBlocked
2466 02 Jun 14 olle 489                   || alarmBlockType == LabSensorAlarmConfig.ALARM_BLOCK_TYPE_MISSING_DATA
2466 02 Jun 14 olle 490                   && alarmType == LabSensorAlarmConfig.ALARM_BLOCK_TYPE_LAB_ENVIRONMENT_DATA)
2303 02 Apr 14 olle 491                 {
2424 14 May 14 olle 492                   // Report alarm and mark it as reported
2424 14 May 14 olle 493                   log.debug("###### " + alarmStr);
2424 14 May 14 olle 494                   alarm.setAlarmText(alarmStr);
2424 14 May 14 olle 495                   alarm.setAlarmBlocked(true);
2466 02 Jun 14 olle 496                   alarm.setAlarmBlockType(alarmType);
2432 16 May 14 olle 497                   // Send alarm report as email
2432 16 May 14 olle 498                   List<String> emailAddressList = fetchEmailAddressList(alarm);
2432 16 May 14 olle 499                   if (emailAddressList != null)
2432 16 May 14 olle 500                   {
2432 16 May 14 olle 501                     log.debug("alarm no = " + alarm.getNo() + " emailAddressList = " + emailAddressList);
2432 16 May 14 olle 502                     for (String emailAddress: emailAddressList)
2432 16 May 14 olle 503                     {
2432 16 May 14 olle 504                       if (emailAddress != null && !emailAddress.equals(""))
2432 16 May 14 olle 505                       {
2432 16 May 14 olle 506                         String toAddress = emailAddress;
4534 21 Jun 17 nicklas 507                         notification(toAddress, alarm, labSensorConfig);
2432 16 May 14 olle 508                       }
2432 16 May 14 olle 509                     }
2432 16 May 14 olle 510                   }
2303 02 Apr 14 olle 511                 }
2424 14 May 14 olle 512               }
2303 02 Apr 14 olle 513               }
2303 02 Apr 14 olle 514             }
2303 02 Apr 14 olle 515           }
2303 02 Apr 14 olle 516         }
2303 02 Apr 14 olle 517       }
2303 02 Apr 14 olle 518     }
2303 02 Apr 14 olle 519
2424 14 May 14 olle 520
2415 09 May 14 olle 521     private boolean activeAlarm(Date measurementTime, long startTimeSecondsFromMidnight, long endTimeSecondsFromMidnight, String weekdayFilter)
2303 02 Apr 14 olle 522     {
2303 02 Apr 14 olle 523       boolean isActive = true;
2303 02 Apr 14 olle 524       if (measurementTime != null)
2303 02 Apr 14 olle 525       {
2303 02 Apr 14 olle 526         long measurementTimeSecondsFromMidnight = getLabEnvironmentConfiguration().secondsFromMidnight(measurementTime);
2303 02 Apr 14 olle 527         if (startTimeSecondsFromMidnight < endTimeSecondsFromMidnight)
2303 02 Apr 14 olle 528         {
2303 02 Apr 14 olle 529           // One alarm period
2303 02 Apr 14 olle 530             if (startTimeSecondsFromMidnight > 0)
2303 02 Apr 14 olle 531             {
2303 02 Apr 14 olle 532               if (measurementTimeSecondsFromMidnight < startTimeSecondsFromMidnight)
2303 02 Apr 14 olle 533               {
2303 02 Apr 14 olle 534                 isActive = false;
2303 02 Apr 14 olle 535               }
2303 02 Apr 14 olle 536             }
2303 02 Apr 14 olle 537             if (endTimeSecondsFromMidnight > 0)
2303 02 Apr 14 olle 538             {
2303 02 Apr 14 olle 539               if (measurementTimeSecondsFromMidnight > endTimeSecondsFromMidnight)
2303 02 Apr 14 olle 540               {
2303 02 Apr 14 olle 541                 isActive = false;
2303 02 Apr 14 olle 542               }
2303 02 Apr 14 olle 543             }
2303 02 Apr 14 olle 544         }
2303 02 Apr 14 olle 545         else if (startTimeSecondsFromMidnight > endTimeSecondsFromMidnight)
2303 02 Apr 14 olle 546         {
2303 02 Apr 14 olle 547           // Two alarm periods; one from first midnight to end time, and one from start time to next midnight
2303 02 Apr 14 olle 548           isActive = false;
2303 02 Apr 14 olle 549             if (endTimeSecondsFromMidnight > 0)
2303 02 Apr 14 olle 550             {
2303 02 Apr 14 olle 551               if (measurementTimeSecondsFromMidnight < endTimeSecondsFromMidnight)
2303 02 Apr 14 olle 552               {
2303 02 Apr 14 olle 553                 isActive = true;
2303 02 Apr 14 olle 554               }
2303 02 Apr 14 olle 555             }
2303 02 Apr 14 olle 556             if (startTimeSecondsFromMidnight > 0)
2303 02 Apr 14 olle 557             {
2303 02 Apr 14 olle 558               if (measurementTimeSecondsFromMidnight > startTimeSecondsFromMidnight)
2303 02 Apr 14 olle 559               {
2303 02 Apr 14 olle 560                 isActive = true;
2303 02 Apr 14 olle 561               }
2303 02 Apr 14 olle 562             }
2303 02 Apr 14 olle 563         }
2415 09 May 14 olle 564         if (weekdayFilter != null && !weekdayFilter.equals(""))
2415 09 May 14 olle 565         {
2415 09 May 14 olle 566           // Only apply weekday filter if date has passed other filters 
2415 09 May 14 olle 567           if (isActive)
2415 09 May 14 olle 568           {
2415 09 May 14 olle 569             isActive = false;
2415 09 May 14 olle 570             LabEnvironmentStatisticsServlet labEnvironmentStatisticsServlet = new LabEnvironmentStatisticsServlet();
2415 09 May 14 olle 571             isActive = labEnvironmentStatisticsServlet.includeWeekday(measurementTime, weekdayFilter);
2415 09 May 14 olle 572           }
2415 09 May 14 olle 573         }
2303 02 Apr 14 olle 574       }
2303 02 Apr 14 olle 575       return isActive;
2303 02 Apr 14 olle 576     }
2432 16 May 14 olle 577
2432 16 May 14 olle 578
2432 16 May 14 olle 579   /**
2432 16 May 14 olle 580    * Optional notification via e-mail.
2432 16 May 14 olle 581    * 
2432 16 May 14 olle 582    * @param toAddress String E-mail address to send the notification e-mail to.
2432 16 May 14 olle 583    * @param sensorName String Name of the sensor, the alarm concerns.
2432 16 May 14 olle 584    * @param alarmText String Message text for the alarm.
2432 16 May 14 olle 585    */
4534 21 Jun 17 nicklas 586   private void notification(String toAddress, LabSensorAlarmConfig alarm, LabSensorConfig sensor)
2432 16 May 14 olle 587   {
4534 21 Jun 17 nicklas 588     log.debug("toAddress = " + toAddress + " sensorName = \"" + sensor.getName() + "\" alarmText = \"" + alarm.getAlarmText() + "\"");
2432 16 May 14 olle 589     // Get lab environment configuration
2432 16 May 14 olle 590     LabEnvironmentConfiguration labEnvironmentConfiguration = getLabEnvironmentConfiguration();
2432 16 May 14 olle 591     EmailConfig emailConfig = labEnvironmentConfiguration.getEmailConfig();
2432 16 May 14 olle 592     String smtpHost = "";
2432 16 May 14 olle 593     String fromAddress = "noreply@localhost";
2432 16 May 14 olle 594     String fromName = "Anonymous";
2432 16 May 14 olle 595     if (emailConfig != null)
2432 16 May 14 olle 596     {
2432 16 May 14 olle 597       smtpHost = emailConfig.getSmtpHost();
2432 16 May 14 olle 598       if (emailConfig.getFromAddress() != null)
2432 16 May 14 olle 599       {
2432 16 May 14 olle 600         fromAddress = emailConfig.getFromAddress();
2432 16 May 14 olle 601       }
2432 16 May 14 olle 602       if (emailConfig.getFromName() != null)
2432 16 May 14 olle 603       {
2432 16 May 14 olle 604         fromName = emailConfig.getFromName();
2432 16 May 14 olle 605       }
2432 16 May 14 olle 606     }
2432 16 May 14 olle 607     MailUtil mailUtil = new MailUtil();
2432 16 May 14 olle 608     // Set mail subject line 
4534 21 Jun 17 nicklas 609     String mailSubject = "Alarm for " + sensor.getName() + " " + new Date();
2432 16 May 14 olle 610     // Set mail message text
4534 21 Jun 17 nicklas 611     String mailMessage = "Alarm (" + alarm.getNo() + ") " + sensor.getUrl() +  ": " + alarm.getAlarmText();
2432 16 May 14 olle 612     // Send notification mail if job corresponds to mail mode settings
2432 16 May 14 olle 613     log.debug("mailSubject = \"" + mailSubject + "\"");
2432 16 May 14 olle 614     //log.debug("nc.getMode() = " + nc.getMode() + " \"" + NotificationConfiguration.Mode.fromValue(nc.getMode()) + "\"");
2432 16 May 14 olle 615     if (toAddress != null && !toAddress.equals("") && toAddress.contains("@"))
2432 16 May 14 olle 616     {
2444 22 May 14 olle 617       try
2444 22 May 14 olle 618       {
2444 22 May 14 olle 619         mailUtil.sendMail(smtpHost, fromAddress, fromName, toAddress, mailSubject, mailMessage);
2444 22 May 14 olle 620       }
2444 22 May 14 olle 621       catch (Exception e)
2444 22 May 14 olle 622       {
2444 22 May 14 olle 623         log.error("notification: Exception thrown when calling mailUtil.sendMail(" + smtpHost + ", " + fromAddress + ", " + fromName + ", " + toAddress + ", " + mailSubject + ", " + mailMessage + "): " + e);
2444 22 May 14 olle 624       }
2432 16 May 14 olle 625     }
2432 16 May 14 olle 626   }
2432 16 May 14 olle 627
2432 16 May 14 olle 628
2432 16 May 14 olle 629   /**
2432 16 May 14 olle 630    * Returns a list of email addresses for the alarm,
2432 16 May 14 olle 631    * or `null` if none could be found.
2432 16 May 14 olle 632    * 
2432 16 May 14 olle 633    * @param alarm LabSensorAlarmConfig The lab sensor alarm configuration to get email address list for.
2432 16 May 14 olle 634    * @return List<String> Returns a list of email addresses for the alarm, or `null` if none could be found.
2432 16 May 14 olle 635    */
2432 16 May 14 olle 636   private List<String> fetchEmailAddressList(LabSensorAlarmConfig alarm)
2432 16 May 14 olle 637   {
2432 16 May 14 olle 638     List<String> emailAddressList = null;
2432 16 May 14 olle 639     if (alarm != null)
2432 16 May 14 olle 640     {
2432 16 May 14 olle 641       // Get alarm user list
2432 16 May 14 olle 642       List<LabSensorAlarmUserConfig> alarmUserList = alarm.getUserList();
2432 16 May 14 olle 643       if (alarmUserList != null)
2432 16 May 14 olle 644       {
2432 16 May 14 olle 645         for (LabSensorAlarmUserConfig alarmUser: alarmUserList)
2432 16 May 14 olle 646         {
2432 16 May 14 olle 647           if (alarmUser != null)
2432 16 May 14 olle 648           {
2432 16 May 14 olle 649             String emailAddress = alarmUser.getEmailAddress();
2432 16 May 14 olle 650             if (emailAddress != null && !emailAddress.equals(""))
2432 16 May 14 olle 651             {
2432 16 May 14 olle 652               if (emailAddressList == null)
2432 16 May 14 olle 653               {
2432 16 May 14 olle 654                 emailAddressList = new ArrayList<String>();
2432 16 May 14 olle 655               }
2432 16 May 14 olle 656               emailAddressList.add(emailAddress);
2432 16 May 14 olle 657             }
2432 16 May 14 olle 658           }
2432 16 May 14 olle 659         }
2432 16 May 14 olle 660       }
2432 16 May 14 olle 661     }
2432 16 May 14 olle 662     return emailAddressList;
2432 16 May 14 olle 663   }
2303 02 Apr 14 olle 664 }