Made alerts bold, fixed sensor not responding alert, refactored aggregator a small bit
This commit is contained in:
parent
0b41bbc446
commit
33de44b166
4 changed files with 66 additions and 41 deletions
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
// TEMPERATURE SENSOR
|
// TEMPERATURE SENSOR
|
||||||
#define TEMPERATURE_ENABLED // comment out to disable 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_PROTOCOL ProtocolOregon(11, DEVICE_BASE_ID + 2)
|
||||||
#define TEMPERATURE_TIMER_MULTIPLIER 10
|
#define TEMPERATURE_TIMER_MULTIPLIER 10
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<span class="glyphicon glyphicon-minus-sign" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-minus-sign" aria-hidden="true"></span>
|
||||||
<strong>Error:</strong> {{.getMessage()}}
|
<strong>{{.getMessage()}}</strong>
|
||||||
</div>
|
</div>
|
||||||
{{/.isError()}}
|
{{/.isError()}}
|
||||||
{{#.isWarning()}}
|
{{#.isWarning()}}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
|
||||||
<strong>Warning:</strong> {{.getMessage()}}
|
<strong>{{.getMessage()}}</strong>
|
||||||
</div>
|
</div>
|
||||||
{{/.isWarning()}}
|
{{/.isWarning()}}
|
||||||
{{#.isSuccess()}}
|
{{#.isSuccess()}}
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
|
||||||
<strong>Success:</strong> {{.getMessage()}}
|
<strong>{{.getMessage()}}</strong>
|
||||||
</div>
|
</div>
|
||||||
{{/.isSuccess()}}
|
{{/.isSuccess()}}
|
||||||
{{#.isInfo()}}
|
{{#.isInfo()}}
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
|
||||||
<strong>Info:</strong> {{.getMessage()}}
|
<strong>{{.getMessage()}}</strong>
|
||||||
</div>
|
</div>
|
||||||
{{/.isInfo()}}
|
{{/.isInfo()}}
|
||||||
{{/alerts}}
|
{{/alerts}}
|
||||||
|
|
|
||||||
|
|
@ -91,39 +91,33 @@ public class SensorDataAggregatorDaemon implements HalDaemon {
|
||||||
DBConnection db = HalContext.getDB();
|
DBConnection db = HalContext.getDB();
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement stmt = null;
|
||||||
try {
|
try {
|
||||||
|
Long maxAggrTimestampInDB = getLatestAggrTimestamp(db, sensor, aggrPeriodLength);
|
||||||
stmt = db.getPreparedStatement("SELECT MAX(timestamp_end) FROM sensor_data_aggr"
|
if(maxAggrTimestampInDB == null)
|
||||||
+ " WHERE sensor_id == ?"
|
maxAggrTimestampInDB = 0l;
|
||||||
+ " 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<Long>());
|
|
||||||
if(maxTimestampFoundForSensor == null)
|
|
||||||
maxTimestampFoundForSensor = 0l;
|
|
||||||
|
|
||||||
long latestCompletePeriodEndTimestamp = new UTCTimePeriod(aggregationStartTime, aggrPeriodLength).getPreviosPeriod().getEndTimestamp();
|
long latestCompletePeriodEndTimestamp = new UTCTimePeriod(aggregationStartTime, aggrPeriodLength).getPreviosPeriod().getEndTimestamp();
|
||||||
long oldestPeriodStartTimestamp = new UTCTimePeriod(aggregationStartTime-ageLimitInMs, aggrPeriodLength).getStartTimestamp();
|
long oldestPeriodStartTimestamp = new UTCTimePeriod(aggregationStartTime-ageLimitInMs, aggrPeriodLength).getStartTimestamp();
|
||||||
|
|
||||||
if(latestCompletePeriodEndTimestamp == maxTimestampFoundForSensor){
|
// Check if the sensor has stopped responding for 15 min or 3 times the data interval and alert the user
|
||||||
logger.fine("no new data to evaluate - aggregation is up to date");
|
if (aggrPeriodLength == AggregationPeriodLength.FIVE_MINUTES) {
|
||||||
// Check if the sensor has stopped responding
|
Long maxRawTimestampInDB = getLatestRawTimestamp(db, sensor);
|
||||||
if (maxTimestampFoundForSensor + sensor.getDeviceConfig().getDataInterval()*3 < System.currentTimeMillis()){
|
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");
|
logger.fine("Sensor \"" + sensorId + "\" has stopped sending data");
|
||||||
HalAlertManager.getInstance().addAlert(new HalAlert(AlertLevel.WARNING,
|
HalAlertManager.getInstance().addAlert(new HalAlert(AlertLevel.WARNING,
|
||||||
"Sensor \""+sensor.getName()+"\" has stopped responding", AlertTTL.DISMISSED));
|
"Sensor \"" + sensor.getName() + "\" has stopped responding " +
|
||||||
|
"since <span class=\"timestamp\">"+maxRawTimestampInDB+"</span>", AlertTTL.DISMISSED));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(latestCompletePeriodEndTimestamp == maxAggrTimestampInDB){
|
||||||
|
logger.fine("no new data to evaluate - aggregation is up to date");
|
||||||
return;
|
return;
|
||||||
}else{
|
}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"
|
stmt = db.getPreparedStatement("SELECT *, 1 AS confidence FROM sensor_data_raw"
|
||||||
|
|
@ -133,7 +127,7 @@ public class SensorDataAggregatorDaemon implements HalDaemon {
|
||||||
+ " AND timestamp >= ? "
|
+ " AND timestamp >= ? "
|
||||||
+" ORDER BY timestamp ASC");
|
+" ORDER BY timestamp ASC");
|
||||||
stmt.setLong(1, sensorId);
|
stmt.setLong(1, sensorId);
|
||||||
stmt.setLong(2, maxTimestampFoundForSensor);
|
stmt.setLong(2, maxAggrTimestampInDB);
|
||||||
stmt.setLong(3, latestCompletePeriodEndTimestamp);
|
stmt.setLong(3, latestCompletePeriodEndTimestamp);
|
||||||
stmt.setLong(4, oldestPeriodStartTimestamp);
|
stmt.setLong(4, oldestPeriodStartTimestamp);
|
||||||
DBConnection.exec(stmt, new DataAggregator(sensorId, aggrPeriodLength, expectedSampleCount, aggrMethod, aggregationStartTime));
|
DBConnection.exec(stmt, new DataAggregator(sensorId, aggrPeriodLength, expectedSampleCount, aggrMethod, aggregationStartTime));
|
||||||
|
|
@ -142,6 +136,31 @@ public class SensorDataAggregatorDaemon implements HalDaemon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<Long>());
|
||||||
|
}
|
||||||
|
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<Long>());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal class for aggregating data to the aggregated DB table
|
* Internal class for aggregating data to the aggregated DB table
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ public class HalAlertManager implements HttpPage {
|
||||||
alerts.add(alert);
|
alerts.add(alert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Templator generateAlerts(){
|
public Templator generateAlerts(){
|
||||||
try {
|
try {
|
||||||
// clone alert list and update ttl of alerts
|
// clone alert list and update ttl of alerts
|
||||||
|
|
@ -110,23 +111,19 @@ public class HalAlertManager implements HttpPage {
|
||||||
private int id;
|
private int id;
|
||||||
private AlertLevel level;
|
private AlertLevel level;
|
||||||
private String msg;
|
private String msg;
|
||||||
protected int ttl;
|
private int ttl;
|
||||||
|
|
||||||
public HalAlert(AlertLevel level, String msg, AlertTTL ttl) {
|
public HalAlert(AlertLevel level, String msg, AlertTTL ttl) {
|
||||||
this.id = nextId++;
|
this.id = nextId++;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.msg = msg;
|
this.msg = msg;
|
||||||
switch (ttl){
|
setTTL(ttl);
|
||||||
case ONE_VIEW: this.ttl = 1; break;
|
|
||||||
case DISMISSED: this.ttl = Integer.MAX_VALUE; break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AlertLevel getLevel() {
|
public AlertLevel getLevel() {
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
@ -134,11 +131,20 @@ public class HalAlertManager implements HttpPage {
|
||||||
public boolean isWarning(){ return level == AlertLevel.WARNING; }
|
public boolean isWarning(){ return level == AlertLevel.WARNING; }
|
||||||
public boolean isSuccess(){ return level == AlertLevel.SUCCESS; }
|
public boolean isSuccess(){ return level == AlertLevel.SUCCESS; }
|
||||||
public boolean isInfo(){ return level == AlertLevel.INFO; }
|
public boolean isInfo(){ return level == AlertLevel.INFO; }
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return msg;
|
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
|
@Override
|
||||||
public boolean equals(Object obj){
|
public boolean equals(Object obj){
|
||||||
if (obj instanceof HalAlert)
|
if (obj instanceof HalAlert)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue