From ef365f360c5c751c5fad2a42dcf2826297437847 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Fri, 27 May 2022 02:13:33 +0200 Subject: [PATCH] Moved Json Pages to api folder and added auto update javascript to overview pages. --- .../resource/resource/web/event_overview.tmpl | 31 ++++++-- hal-core/resource/resource/web/js/hal.js | 28 +++++--- hal-core/resource/resource/web/map.tmpl | 4 +- .../resource/resource/web/sensor_detail.tmpl | 6 +- .../resource/web/sensor_overview.tmpl | 27 ++++++- .../src/se/hal/intf/HalAbstractDevice.java | 32 +++++++++ .../src/se/hal/page/api/EventJsonPage.java | 72 +++++++++++++++++++ .../se/hal/page/{ => api}/MapJsonPage.java | 4 +- .../se/hal/page/{ => api}/SensorJsonPage.java | 49 ++++++------- hal-core/src/se/hal/plugin.json | 5 +- .../resource/resource/web/pc_overview.tmpl | 8 +-- 11 files changed, 210 insertions(+), 56 deletions(-) create mode 100644 hal-core/src/se/hal/page/api/EventJsonPage.java rename hal-core/src/se/hal/page/{ => api}/MapJsonPage.java (98%) rename hal-core/src/se/hal/page/{ => api}/SensorJsonPage.java (73%) diff --git a/hal-core/resource/resource/web/event_overview.tmpl b/hal-core/resource/resource/web/event_overview.tmpl index 4164f109..c4150ef0 100644 --- a/hal-core/resource/resource/web/event_overview.tmpl +++ b/hal-core/resource/resource/web/event_overview.tmpl @@ -5,20 +5,20 @@
Local Events
- +
- + - + {{#events}} - + - +
Name TypeDataData Last UpdateActionsActions
{{.getName()}} {{.getDeviceConfig().getClass().getSimpleName()}} {{.getDeviceData()}}{{.getDeviceData().getTimestamp()}}{{.getDeviceData().getTimestamp()}}
@@ -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); \ No newline at end of file diff --git a/hal-core/resource/resource/web/js/hal.js b/hal-core/resource/resource/web/js/hal.js index 5c495c18..0781738f 100644 --- a/hal-core/resource/resource/web/js/hal.js +++ b/hal-core/resource/resource/web/js/hal.js @@ -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'; diff --git a/hal-core/resource/resource/web/map.tmpl b/hal-core/resource/resource/web/map.tmpl index 2d7b6875..d60ff8bd 100644 --- a/hal-core/resource/resource/web/map.tmpl +++ b/hal-core/resource/resource/web/map.tmpl @@ -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"), diff --git a/hal-core/resource/resource/web/sensor_detail.tmpl b/hal-core/resource/resource/web/sensor_detail.tmpl index 550a73e0..aaa2fb72 100644 --- a/hal-core/resource/resource/web/sensor_detail.tmpl +++ b/hal-core/resource/resource/web/sensor_detail.tmpl @@ -93,8 +93,8 @@ \ No newline at end of file diff --git a/hal-core/resource/resource/web/sensor_overview.tmpl b/hal-core/resource/resource/web/sensor_overview.tmpl index 3d05e9af..3a7b537c 100644 --- a/hal-core/resource/resource/web/sensor_overview.tmpl +++ b/hal-core/resource/resource/web/sensor_overview.tmpl @@ -5,7 +5,7 @@
Local Sensors
- +
@@ -13,11 +13,11 @@ {{#sensors}} - + - + {{/sensors}}
Name TypeLast Update
{{.getName()}} {{.getDeviceConfig().getClass().getSimpleName()}} {{.getDeviceData()}}{{.getDeviceData().getTimestamp()}}{{.getDeviceData().getTimestamp()}}
@@ -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); \ No newline at end of file diff --git a/hal-core/src/se/hal/intf/HalAbstractDevice.java b/hal-core/src/se/hal/intf/HalAbstractDevice.java index 8a1bb0ac..6b22de5a 100644 --- a/hal-core/src/se/hal/intf/HalAbstractDevice.java +++ b/hal-core/src/se/hal/intf/HalAbstractDevice.java @@ -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 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; + } } diff --git a/hal-core/src/se/hal/page/api/EventJsonPage.java b/hal-core/src/se/hal/page/api/EventJsonPage.java new file mode 100644 index 00000000..deeb1678 --- /dev/null +++ b/hal-core/src/se/hal/page/api/EventJsonPage.java @@ -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: + *
+ * Event filtering parameters:
+ * id: comma separated numeric id for specific events
+ * type: event data type name
+ * 
+ */ +public class EventJsonPage extends HalJsonPage { + private static final Logger logger = LogUtil.getLogger(); + + + public EventJsonPage() { + super("api/event"); + } + + @Override + public DataNode jsonRespond( + Map session, + Map cookie, + Map 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 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; + } +} diff --git a/hal-core/src/se/hal/page/MapJsonPage.java b/hal-core/src/se/hal/page/api/MapJsonPage.java similarity index 98% rename from hal-core/src/se/hal/page/MapJsonPage.java rename to hal-core/src/se/hal/page/api/MapJsonPage.java index ade55206..f256c3cb 100644 --- a/hal-core/src/se/hal/page/MapJsonPage.java +++ b/hal-core/src/se/hal/page/api/MapJsonPage.java @@ -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"); } diff --git a/hal-core/src/se/hal/page/SensorJsonPage.java b/hal-core/src/se/hal/page/api/SensorJsonPage.java similarity index 73% rename from hal-core/src/se/hal/page/SensorJsonPage.java rename to hal-core/src/se/hal/page/api/SensorJsonPage.java index b139729c..87e219af 100644 --- a/hal-core/src/se/hal/page/SensorJsonPage.java +++ b/hal-core/src/se/hal/page/api/SensorJsonPage.java @@ -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 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 dataList) { + private DataNode getAggregateDataNode(long endTime, List 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; } } diff --git a/hal-core/src/se/hal/plugin.json b/hal-core/src/se/hal/plugin.json index cbf93ccc..35711a8d 100644 --- a/hal-core/src/se/hal/plugin.json +++ b/hal-core/src/se/hal/plugin.json @@ -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"}, diff --git a/plugins/hal-powerchallenge/resource/resource/web/pc_overview.tmpl b/plugins/hal-powerchallenge/resource/resource/web/pc_overview.tmpl index be557c5a..4c9965e7 100644 --- a/plugins/hal-powerchallenge/resource/resource/web/pc_overview.tmpl +++ b/plugins/hal-powerchallenge/resource/resource/web/pc_overview.tmpl @@ -20,10 +20,10 @@