Moved Json Pages to api folder and added auto update javascript to overview pages.
This commit is contained in:
parent
95ff5b81c0
commit
ef365f360c
11 changed files with 210 additions and 56 deletions
|
|
@ -5,20 +5,20 @@
|
|||
<div class="panel-heading">Local Events</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<table class="table table-hover table-condensed">
|
||||
<table id="event-device-table" class="table table-hover table-condensed">
|
||||
<thead>
|
||||
<th class="col-md-4">Name</th>
|
||||
<th class="col-md-3">Type</th>
|
||||
<th class="col-md-2">Data</th>
|
||||
<th class="col-md-1">Data</th>
|
||||
<th class="col-md-2">Last Update</th>
|
||||
<th class="col-md-1 text-right">Actions</th>
|
||||
<th class="col-md-2 text-right">Actions</th>
|
||||
</thead>
|
||||
{{#events}}
|
||||
<tr>
|
||||
<tr data-device-id="{{.getId()}}">
|
||||
<td><a href="?id={{.getId()}}">{{.getName()}}</a></td>
|
||||
<td>{{.getDeviceConfig().getClass().getSimpleName()}}</td>
|
||||
<td>{{.getDeviceData()}}</td>
|
||||
<td><span class="timestamp">{{.getDeviceData().getTimestamp()}}</span></td>
|
||||
<td class="timestamp">{{.getDeviceData().getTimestamp()}}</td>
|
||||
<td>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="modify">
|
||||
|
|
@ -44,4 +44,25 @@
|
|||
$(this).closest('form').submit();
|
||||
});
|
||||
});
|
||||
|
||||
// Auto update
|
||||
|
||||
setInterval(function() {
|
||||
fetch('/api/event')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
var table = document.getElementById('event-device-table');
|
||||
|
||||
for (const row of table.rows) {
|
||||
var dataItem = data.find(item => item.id == row.dataset.deviceId);
|
||||
|
||||
if (dataItem) {
|
||||
row.cells[2].innerHTML = dataItem.data?.valueStr;
|
||||
row.cells[3].innerHTML = dataItem.data?.timestamp;
|
||||
$(row.cells[3]).relTimestamp();
|
||||
$(row.cells[4].querySelector('[type="checkbox"]')).bootstrapSwitch('state', dataItem.data?.value === 1, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
</script>
|
||||
28
hal-core/resource/resource/web/js/hal.js
vendored
28
hal-core/resource/resource/web/js/hal.js
vendored
|
|
@ -101,26 +101,32 @@ function createChart(elementId, url, updateTime=-1){
|
|||
});
|
||||
}
|
||||
function updateChart(chart, url, updateTime=-1){
|
||||
console.log('Updating chart: '+chart.element.id);
|
||||
$.getJSON(url, function(json){
|
||||
console.log('Updating chart: ' + chart.element.id);
|
||||
|
||||
$.getJSON(url, function(json) {
|
||||
chart.load(getChartData(json));
|
||||
});
|
||||
if (updateTime > 0)
|
||||
setTimeout(function(){ updateChart(chart, url, updateTime); }, updateTime);
|
||||
|
||||
if (updateTime > 0) {
|
||||
setTimeout(function() {
|
||||
updateChart(chart, url, updateTime);
|
||||
}, updateTime);
|
||||
}
|
||||
}
|
||||
function getChartData(json){
|
||||
var dataXaxis = {};
|
||||
var dataYaxis = {};
|
||||
var data = [];
|
||||
var labels = [];
|
||||
json.forEach(function(sensor, i) {
|
||||
var index = 'data'+i;
|
||||
labels[index] = sensor.user +": "+ sensor.name;
|
||||
dataXaxis[index] = 'data'+i+'x';
|
||||
data.push([index+'x'].concat(sensor.timestamps));
|
||||
data.push([index].concat(sensor.data));
|
||||
|
||||
if (sensor.type == "PowerConsumptionSensorData")
|
||||
json.forEach(function(sensor, i) {
|
||||
var index = 'data' + i;
|
||||
labels[index] = sensor.user + ': ' + sensor.name;
|
||||
dataXaxis[index] = 'data' + i + 'x';
|
||||
data.push([index + 'x'].concat(sensor.aggregate.timestamps));
|
||||
data.push([index].concat(sensor.aggregate.data));
|
||||
|
||||
if (sensor.type == 'PowerConsumptionSensorData')
|
||||
dataYaxis[index] = 'y';
|
||||
else //if (sensor.type == "TemperatureSensorData")
|
||||
dataYaxis[index] = 'y2';
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@
|
|||
|
||||
function drawMap(){
|
||||
// Get map data
|
||||
$.getJSON("/data/map?action=getdata", function(json){
|
||||
$.getJSON("/api/map?action=getdata", function(json){
|
||||
// reset map
|
||||
svg.clear();
|
||||
|
||||
|
|
@ -183,7 +183,7 @@
|
|||
$.ajax({
|
||||
async: false,
|
||||
dataType: "json",
|
||||
url: "/data/map?",
|
||||
url: "/api/map?",
|
||||
data: {
|
||||
action: "save",
|
||||
id: element.attr("device-id"),
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@
|
|||
|
||||
<script>
|
||||
$(function(){
|
||||
createChart("#min-chart", "/data/sensor?aggr=minute&id={{sensor.getId()}}", 5*60*1000);
|
||||
createChart("#hour-chart", "/data/sensor?aggr=hour&id={{sensor.getId()}}", 60*60*1000);
|
||||
createChart("#week-chart", "/data/sensor?aggr=week&id={{sensor.getId()}}", 7*24*60*60*1000);
|
||||
createChart("#min-chart", "/api/sensor?aggr=minute&id={{sensor.getId()}}", 5*60*1000);
|
||||
createChart("#hour-chart", "/api/sensor?aggr=hour&id={{sensor.getId()}}", 60*60*1000);
|
||||
createChart("#week-chart", "/api/sensor?aggr=week&id={{sensor.getId()}}", 7*24*60*60*1000);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
<div class="panel-heading">Local Sensors</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<table class="table table-hover table-condensed">
|
||||
<table id="sensor-device-table" class="table table-hover table-condensed">
|
||||
<thead>
|
||||
<th class="col-md-4">Name</th>
|
||||
<th class="col-md-3">Type</th>
|
||||
|
|
@ -13,11 +13,11 @@
|
|||
<th class="col-md-2">Last Update</th>
|
||||
</thead>
|
||||
{{#sensors}}
|
||||
<tr>
|
||||
<tr data-device-id="{{.getId()}}">
|
||||
<td><a href="?id={{.getId()}}">{{.getName()}}</a></td>
|
||||
<td>{{.getDeviceConfig().getClass().getSimpleName()}}</td>
|
||||
<td>{{.getDeviceData()}}</td>
|
||||
<td><span class="timestamp">{{.getDeviceData().getTimestamp()}}</span></td>
|
||||
<td class="timestamp">{{.getDeviceData().getTimestamp()}}</td>
|
||||
</tr>
|
||||
{{/sensors}}
|
||||
</table>
|
||||
|
|
@ -31,4 +31,25 @@
|
|||
$(this).closest('form').submit();
|
||||
});
|
||||
});
|
||||
|
||||
// Auto update
|
||||
|
||||
setInterval(function() {
|
||||
fetch('/api/sensor')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
var table = document.getElementById('sensor-device-table');
|
||||
|
||||
for (const row of table.rows) {
|
||||
var dataItem = data.find(item => item.id == row.dataset.deviceId);
|
||||
|
||||
if (dataItem) {
|
||||
row.cells[2].innerHTML = dataItem.data?.valueStr;
|
||||
row.cells[3].innerHTML = dataItem.data?.timestamp;
|
||||
|
||||
$(row.cells[3]).relTimestamp();
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
</script>
|
||||
|
|
@ -6,6 +6,7 @@ import se.hal.util.HalDeviceChangeListener;
|
|||
import zutil.db.DBConnection;
|
||||
import zutil.db.bean.DBBean;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.parser.DataNode;
|
||||
import zutil.parser.json.JSONParser;
|
||||
import zutil.parser.json.JSONWriter;
|
||||
import zutil.ui.conf.Configurator;
|
||||
|
|
@ -214,4 +215,35 @@ public abstract class HalAbstractDevice<V extends HalAbstractDevice, C extends H
|
|||
public List<HalDeviceReportListener> getReportListeners() {
|
||||
return deviceListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a DataNode object containing general Device information that can be written in JSON format.
|
||||
*/
|
||||
public DataNode getDataNode() {
|
||||
DataNode deviceNode = new DataNode(DataNode.DataType.Map);
|
||||
deviceNode.set("id", getId());
|
||||
deviceNode.set("name", getName());
|
||||
deviceNode.set("user", getUser().getUsername());
|
||||
deviceNode.set("x", getX());
|
||||
deviceNode.set("y", getY());
|
||||
|
||||
if (getDeviceConfig() != null) {
|
||||
DataNode configNode = deviceNode.set("config", DataNode.DataType.Map);
|
||||
configNode.set("type", getDeviceConfig().getClass().getSimpleName());
|
||||
configNode.set("typeData", getDeviceConfig().getDeviceDataClass().getSimpleName());
|
||||
|
||||
for (Configurator.ConfigurationParam param : getDeviceConfigurator().getConfiguration()) {
|
||||
configNode.set(param.getName(), param.getString());
|
||||
}
|
||||
}
|
||||
|
||||
if (getDeviceData() != null) {
|
||||
DataNode dataNode = deviceNode.set("data", DataNode.DataType.Map);
|
||||
dataNode.set("value", getDeviceData().getData());
|
||||
dataNode.set("valueStr", getDeviceData().toString());
|
||||
dataNode.set("timestamp", getDeviceData().getTimestamp());
|
||||
}
|
||||
|
||||
return deviceNode;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
72
hal-core/src/se/hal/page/api/EventJsonPage.java
Normal file
72
hal-core/src/se/hal/page/api/EventJsonPage.java
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package se.hal.page.api;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.daemon.SensorDataAggregatorDaemon;
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import se.hal.struct.Event;
|
||||
import zutil.ArrayUtil;
|
||||
import zutil.ObjectUtil;
|
||||
import zutil.db.DBConnection;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.parser.DataNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Available HTTP Get Request parameters:
|
||||
* <pre>
|
||||
* Event filtering parameters:
|
||||
* id: comma separated numeric id for specific events
|
||||
* type: event data type name
|
||||
* </pre>
|
||||
*/
|
||||
public class EventJsonPage extends HalJsonPage {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
|
||||
public EventJsonPage() {
|
||||
super("api/event");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataNode jsonRespond(
|
||||
Map<String, Object> session,
|
||||
Map<String, String> cookie,
|
||||
Map<String, String> request) throws Exception{
|
||||
|
||||
DBConnection db = HalContext.getDB();
|
||||
DataNode root = new DataNode(DataNode.DataType.List);
|
||||
|
||||
// Get sensors
|
||||
|
||||
String[] req_ids = new String[0];
|
||||
if (request.get("id") != null)
|
||||
req_ids = request.get("id").split(",");
|
||||
String req_type = request.get("type");
|
||||
|
||||
List<Event> events = new ArrayList<>();
|
||||
for (Event event : Event.getLocalEvents(db)) {
|
||||
|
||||
if (ArrayUtil.contains(req_ids, "" + event.getId())) { // id filtering
|
||||
events.add(event);
|
||||
} else if (!ObjectUtil.isEmpty(req_type) &&
|
||||
event.getDeviceConfig().getDeviceDataClass().getSimpleName().contains(req_type)) { // device type filtering
|
||||
events.add(event);
|
||||
} else { // no options defined, then add all sensors
|
||||
events.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate DataNode
|
||||
|
||||
for (Event sensor : events) {
|
||||
DataNode deviceNode = sensor.getDataNode();
|
||||
root.add(deviceNode);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package se.hal.page;
|
||||
package se.hal.page.api;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.intf.HalAbstractDevice;
|
||||
|
|
@ -20,7 +20,7 @@ public class MapJsonPage extends HalJsonPage {
|
|||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
public MapJsonPage() {
|
||||
super("data/map");
|
||||
super("api/map");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package se.hal.page;
|
||||
package se.hal.page.api;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.daemon.SensorDataAggregatorDaemon;
|
||||
|
|
@ -7,6 +7,7 @@ import se.hal.struct.Sensor;
|
|||
import se.hal.util.AggregateDataListSqlResult;
|
||||
import se.hal.util.UTCTimeUtility;
|
||||
import zutil.ArrayUtil;
|
||||
import zutil.ObjectUtil;
|
||||
import zutil.db.DBConnection;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.parser.DataNode;
|
||||
|
|
@ -32,7 +33,7 @@ public class SensorJsonPage extends HalJsonPage {
|
|||
|
||||
|
||||
public SensorJsonPage() {
|
||||
super("data/sensor");
|
||||
super("api/sensor");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -44,27 +45,25 @@ public class SensorJsonPage extends HalJsonPage {
|
|||
DBConnection db = HalContext.getDB();
|
||||
DataNode root = new DataNode(DataNode.DataType.List);
|
||||
|
||||
//// Get sensors
|
||||
String[] req_ids = null;
|
||||
// Get sensors
|
||||
String[] req_ids = new String[0];
|
||||
if (request.get("id") != null)
|
||||
req_ids = request.get("id").split(",");
|
||||
String req_type = request.get("type");
|
||||
|
||||
List<Sensor> sensors = new ArrayList<>();
|
||||
for (Sensor sensor : Sensor.getSensors(db)) {
|
||||
if (sensor.getDeviceConfig() == null) // Show all sensors for now
|
||||
continue;
|
||||
|
||||
if (req_ids == null && req_type==null) // no options defined, then add all sensors
|
||||
if (ArrayUtil.contains(req_ids, "" + sensor.getId())) { // id filtering
|
||||
sensors.add(sensor);
|
||||
else if (req_ids != null && ArrayUtil.contains(req_ids, ""+sensor.getId())) // id filtering
|
||||
} else if (!ObjectUtil.isEmpty(req_type) &&
|
||||
sensor.getDeviceConfig().getDeviceDataClass().getSimpleName().contains(req_type)) { // device type filtering
|
||||
sensors.add(sensor);
|
||||
else if (req_type != null && !req_type.isEmpty() &&
|
||||
sensor.getDeviceConfig().getDeviceDataClass().getSimpleName().contains(req_type)) // device type filtering
|
||||
} else { // no options defined, then add all sensors
|
||||
sensors.add(sensor);
|
||||
}
|
||||
}
|
||||
|
||||
//// Figure out aggregation period
|
||||
// Figure out aggregation period
|
||||
SensorDataAggregatorDaemon.AggregationPeriodLength aggrType = null;
|
||||
long aggrLength = -1;
|
||||
if (request.get("aggr") != null) {
|
||||
|
|
@ -88,34 +87,33 @@ public class SensorJsonPage extends HalJsonPage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generate DataNode
|
||||
// Generate DataNode
|
||||
for (Sensor sensor : sensors) {
|
||||
DataNode deviceNode = new DataNode(DataNode.DataType.Map);
|
||||
deviceNode.set("id", sensor.getId());
|
||||
deviceNode.set("name", sensor.getName());
|
||||
deviceNode.set("user", sensor.getUser().getUsername());
|
||||
deviceNode.set("type", sensor.getDeviceConfig().getDeviceDataClass().getSimpleName());
|
||||
deviceNode.set("x", sensor.getX());
|
||||
deviceNode.set("y", sensor.getY());
|
||||
DataNode deviceNode = sensor.getDataNode();
|
||||
|
||||
if (aggrLength > 0) {
|
||||
addAggregateDataToDataNode(deviceNode, aggrLength,
|
||||
DataNode aggregateNode = getAggregateDataNode(aggrLength,
|
||||
AggregateDataListSqlResult.getAggregateDataForPeriod(db, sensor, aggrType, aggrLength));
|
||||
deviceNode.set("aggregate", aggregateNode);
|
||||
}
|
||||
|
||||
root.add(deviceNode);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void addAggregateDataToDataNode(DataNode deviceNode, long endTime, List<AggregateDataListSqlResult.AggregateData> dataList) {
|
||||
private DataNode getAggregateDataNode(long endTime, List<AggregateDataListSqlResult.AggregateData> dataList) {
|
||||
DataNode aggregateNode = new DataNode(DataNode.DataType.Map);
|
||||
DataNode timestampNode = new DataNode(DataNode.DataType.List);
|
||||
DataNode dataNode = new DataNode(DataNode.DataType.List);
|
||||
|
||||
// end timestamp
|
||||
if (endTime != UTCTimeUtility.INFINITY) {
|
||||
timestampNode.add(System.currentTimeMillis() - endTime);
|
||||
dataNode.add((String)null);
|
||||
}
|
||||
|
||||
// actual data
|
||||
for (AggregateDataListSqlResult.AggregateData data : dataList) {
|
||||
timestampNode.add(data.timestamp);
|
||||
|
|
@ -124,12 +122,15 @@ public class SensorJsonPage extends HalJsonPage {
|
|||
else
|
||||
dataNode.add(data.data);
|
||||
}
|
||||
|
||||
// start timestamp
|
||||
timestampNode.add(System.currentTimeMillis());
|
||||
dataNode.add((String)null);
|
||||
|
||||
deviceNode.set("timestamps", timestampNode);
|
||||
deviceNode.set("data", dataNode);
|
||||
aggregateNode.set("timestamps", timestampNode);
|
||||
aggregateNode.set("data", dataNode);
|
||||
|
||||
return aggregateNode;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -12,8 +12,9 @@
|
|||
{"se.hal.intf.HalDaemon": "se.hal.daemon.SensorDataAggregatorDaemon"},
|
||||
{"se.hal.intf.HalDaemon": "se.hal.daemon.SensorDataCleanupDaemon"},
|
||||
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.MapJsonPage"},
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.SensorJsonPage"},
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.api.MapJsonPage"},
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.api.EventJsonPage"},
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.api.SensorJsonPage"},
|
||||
|
||||
{"se.hal.intf.HalWebPage": "se.hal.page.MapWebPage"},
|
||||
{"se.hal.intf.HalWebPage": "se.hal.page.SensorOverviewWebPage"},
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
<script>
|
||||
|
||||
$(function(){
|
||||
createChart("#minute-power-chart", "/data/sensor?aggr=minute", 5*60*1000);
|
||||
createChart("#hour-power-chart", "/data/sensor?aggr=hour", 60*60*1000);
|
||||
createChart("#day-power-chart", "/data/sensor?aggr=day", 24*60*60*1000);
|
||||
createChart("#week-power-chart", "/data/sensor?aggr=week", 7*24*60*60*1000);
|
||||
createChart("#minute-power-chart", "/api/sensor?aggr=minute", 5*60*1000);
|
||||
createChart("#hour-power-chart", "/api/sensor?aggr=hour", 60*60*1000);
|
||||
createChart("#day-power-chart", "/api/sensor?aggr=day", 24*60*60*1000);
|
||||
createChart("#week-power-chart", "/api/sensor?aggr=week", 7*24*60*60*1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue