diff --git a/arduino/HalMultiSensor/HalConfiguration.h b/arduino/HalMultiSensor/HalConfiguration.h index 374981c5..4fbe1342 100755 --- a/arduino/HalMultiSensor/HalConfiguration.h +++ b/arduino/HalMultiSensor/HalConfiguration.h @@ -16,7 +16,7 @@ // TEMPERATURE SENSOR #define TEMPERATURE_ENABLED // comment out to disable sensor -#define TEMPERATURE_SENSOR SensorDHT(DHT11, 10) +#define TEMPERATURE_SENSOR SensorDHT(DHT22, 10) #define TEMPERATURE_PROTOCOL ProtocolOregon(11, DEVICE_BASE_ID + 2) #define TEMPERATURE_TIMER_MULTIPLIER 10 diff --git a/resource/web/main_alerts.tmpl b/resource/web/main_alerts.tmpl index 7eee7d3a..e6fdb466 100755 --- a/resource/web/main_alerts.tmpl +++ b/resource/web/main_alerts.tmpl @@ -5,7 +5,7 @@ - Error: {{.getMessage()}} + {{.getMessage()}} {{/.isError()}} {{#.isWarning()}} @@ -14,7 +14,7 @@ - Warning: {{.getMessage()}} + {{.getMessage()}} {{/.isWarning()}} {{#.isSuccess()}} @@ -23,7 +23,7 @@ - Success: {{.getMessage()}} + {{.getMessage()}} {{/.isSuccess()}} {{#.isInfo()}} @@ -32,7 +32,7 @@ - Info: {{.getMessage()}} + {{.getMessage()}} {{/.isInfo()}} {{/alerts}} diff --git a/src/se/hal/daemon/SensorDataAggregatorDaemon.java b/src/se/hal/daemon/SensorDataAggregatorDaemon.java index 7bd9d1e1..5a6eb74e 100755 --- a/src/se/hal/daemon/SensorDataAggregatorDaemon.java +++ b/src/se/hal/daemon/SensorDataAggregatorDaemon.java @@ -91,39 +91,33 @@ public class SensorDataAggregatorDaemon implements HalDaemon { DBConnection db = HalContext.getDB(); PreparedStatement stmt = null; try { - - stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr" - + " WHERE sensor_id == ?" - + " AND timestamp_end-timestamp_start == ?"); - stmt.setLong(1, sensorId); - switch(aggrPeriodLength){ - case SECOND: stmt.setLong(2, UTCTimeUtility.SECOND_IN_MS-1); break; - case MINUTE: stmt.setLong(2, UTCTimeUtility.MINUTE_IN_MS-1); break; - case FIVE_MINUTES: stmt.setLong(2, UTCTimeUtility.FIVE_MINUTES_IN_MS-1); break; - case FIFTEEN_MINUTES: stmt.setLong(2, UTCTimeUtility.FIFTEEN_MINUTES_IN_MS-1); break; - case HOUR: stmt.setLong(2, UTCTimeUtility.HOUR_IN_MS-1); break; - case DAY: stmt.setLong(2, UTCTimeUtility.DAY_IN_MS-1); break; - case WEEK: stmt.setLong(2, UTCTimeUtility.WEEK_IN_MS-1); break; - default: logger.warning("aggregation period length is not supported."); return; - } - Long maxTimestampFoundForSensor = DBConnection.exec(stmt, new SimpleSQLResult()); - if(maxTimestampFoundForSensor == null) - maxTimestampFoundForSensor = 0l; + Long maxAggrTimestampInDB = getLatestAggrTimestamp(db, sensor, aggrPeriodLength); + if(maxAggrTimestampInDB == null) + maxAggrTimestampInDB = 0l; long latestCompletePeriodEndTimestamp = new UTCTimePeriod(aggregationStartTime, aggrPeriodLength).getPreviosPeriod().getEndTimestamp(); long oldestPeriodStartTimestamp = new UTCTimePeriod(aggregationStartTime-ageLimitInMs, aggrPeriodLength).getStartTimestamp(); - - if(latestCompletePeriodEndTimestamp == maxTimestampFoundForSensor){ - logger.fine("no new data to evaluate - aggregation is up to date"); - // Check if the sensor has stopped responding - if (maxTimestampFoundForSensor + sensor.getDeviceConfig().getDataInterval()*3 < System.currentTimeMillis()){ + + // Check if the sensor has stopped responding for 15 min or 3 times the data interval and alert the user + if (aggrPeriodLength == AggregationPeriodLength.FIVE_MINUTES) { + Long maxRawTimestampInDB = getLatestRawTimestamp(db, sensor); + long dataInterval = sensor.getDeviceConfig().getDataInterval(); + if (dataInterval < UTCTimeUtility.FIVE_MINUTES_IN_MS) + dataInterval = UTCTimeUtility.FIVE_MINUTES_IN_MS; + if (maxRawTimestampInDB != null && + maxRawTimestampInDB + (dataInterval * 3) < System.currentTimeMillis()) { logger.fine("Sensor \"" + sensorId + "\" has stopped sending data"); - HalAlertManager.getInstance().addAlert(new HalAlert(AlertLevel.WARNING, - "Sensor \""+sensor.getName()+"\" has stopped responding", AlertTTL.DISMISSED)); - } + HalAlertManager.getInstance().addAlert(new HalAlert(AlertLevel.WARNING, + "Sensor \"" + sensor.getName() + "\" has stopped responding " + + "since "+maxRawTimestampInDB+"", AlertTTL.DISMISSED)); + } + } + + if(latestCompletePeriodEndTimestamp == maxAggrTimestampInDB){ + logger.fine("no new data to evaluate - aggregation is up to date"); return; }else{ - logger.fine("evaluating period: "+ (maxTimestampFoundForSensor+1) + "=>" + latestCompletePeriodEndTimestamp + " (" + UTCTimeUtility.getDateString(maxTimestampFoundForSensor+1) + "=>" + UTCTimeUtility.getDateString(latestCompletePeriodEndTimestamp) + ") with expected sample count: " + expectedSampleCount); + logger.fine("evaluating period: "+ (maxAggrTimestampInDB+1) + "=>" + latestCompletePeriodEndTimestamp + " (" + UTCTimeUtility.getDateString(maxAggrTimestampInDB+1) + "=>" + UTCTimeUtility.getDateString(latestCompletePeriodEndTimestamp) + ") with expected sample count: " + expectedSampleCount); } stmt = db.getPreparedStatement("SELECT *, 1 AS confidence FROM sensor_data_raw" @@ -133,7 +127,7 @@ public class SensorDataAggregatorDaemon implements HalDaemon { + " AND timestamp >= ? " +" ORDER BY timestamp ASC"); stmt.setLong(1, sensorId); - stmt.setLong(2, maxTimestampFoundForSensor); + stmt.setLong(2, maxAggrTimestampInDB); stmt.setLong(3, latestCompletePeriodEndTimestamp); stmt.setLong(4, oldestPeriodStartTimestamp); DBConnection.exec(stmt, new DataAggregator(sensorId, aggrPeriodLength, expectedSampleCount, aggrMethod, aggregationStartTime)); @@ -141,7 +135,32 @@ public class SensorDataAggregatorDaemon implements HalDaemon { logger.log(Level.SEVERE, null, e); } } - + + private Long getLatestAggrTimestamp(DBConnection db, Sensor sensor, AggregationPeriodLength aggrPeriodLength) throws SQLException { + PreparedStatement stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr" + + " WHERE sensor_id == ?" + + " AND timestamp_end-timestamp_start == ?"); + stmt.setLong(1, sensor.getId()); + switch(aggrPeriodLength){ + case SECOND: stmt.setLong(2, UTCTimeUtility.SECOND_IN_MS-1); break; + case MINUTE: stmt.setLong(2, UTCTimeUtility.MINUTE_IN_MS-1); break; + case FIVE_MINUTES: stmt.setLong(2, UTCTimeUtility.FIVE_MINUTES_IN_MS-1); break; + case FIFTEEN_MINUTES: stmt.setLong(2, UTCTimeUtility.FIFTEEN_MINUTES_IN_MS-1); break; + case HOUR: stmt.setLong(2, UTCTimeUtility.HOUR_IN_MS-1); break; + case DAY: stmt.setLong(2, UTCTimeUtility.DAY_IN_MS-1); break; + case WEEK: stmt.setLong(2, UTCTimeUtility.WEEK_IN_MS-1); break; + default: + throw new IllegalArgumentException("aggregation period length is not supported."); + } + return DBConnection.exec(stmt, new SimpleSQLResult()); + } + private Long getLatestRawTimestamp(DBConnection db, Sensor sensor) throws SQLException { + PreparedStatement stmt = db.getPreparedStatement("SELECT MAX(timestamp) FROM sensor_data_raw WHERE sensor_id == ?"); + stmt.setLong(1, sensor.getId()); + return DBConnection.exec(stmt, new SimpleSQLResult()); + } + + /** * Internal class for aggregating data to the aggregated DB table */ diff --git a/src/se/hal/page/HalAlertManager.java b/src/se/hal/page/HalAlertManager.java index e71f0e80..1a2712a6 100755 --- a/src/se/hal/page/HalAlertManager.java +++ b/src/se/hal/page/HalAlertManager.java @@ -46,6 +46,7 @@ public class HalAlertManager implements HttpPage { alerts.add(alert); } + public Templator generateAlerts(){ try { // clone alert list and update ttl of alerts @@ -110,23 +111,19 @@ public class HalAlertManager implements HttpPage { private int id; private AlertLevel level; private String msg; - protected int ttl; + private int ttl; public HalAlert(AlertLevel level, String msg, AlertTTL ttl) { this.id = nextId++; this.level = level; this.msg = msg; - switch (ttl){ - case ONE_VIEW: this.ttl = 1; break; - case DISMISSED: this.ttl = Integer.MAX_VALUE; break; - } + setTTL(ttl); } public int getId() { return id; } - public AlertLevel getLevel() { return level; } @@ -134,11 +131,20 @@ public class HalAlertManager implements HttpPage { public boolean isWarning(){ return level == AlertLevel.WARNING; } public boolean isSuccess(){ return level == AlertLevel.SUCCESS; } public boolean isInfo(){ return level == AlertLevel.INFO; } - public String getMessage() { return msg; } + public void setTTL(AlertTTL ttl){ + switch (ttl){ + case ONE_VIEW: this.ttl = 1; break; + case DISMISSED: this.ttl = Integer.MAX_VALUE; break; + } + } + public void dissmiss(){ + ttl = -1; + } + @Override public boolean equals(Object obj){ if (obj instanceof HalAlert)