Fixed up the API and added API doc
This commit is contained in:
parent
253208b6f9
commit
0efa7320e3
12 changed files with 313 additions and 58 deletions
25
hal-core/resource/resource/web/api/docs.html
Normal file
25
hal-core/resource/resource/web/api/docs.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Hal OpenAPI Documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.15.3/swagger-ui.css">
|
||||
<script src="https://unpkg.com/swagger-ui-dist@4.15.3/swagger-ui-bundle.js"></script>
|
||||
|
||||
<script>
|
||||
function render() {
|
||||
var ui = SwaggerUIBundle({
|
||||
url: '/api/openapi.json',
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||
]
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="render()">
|
||||
<div id="swagger-ui"></div>
|
||||
</body>
|
||||
</html>
|
||||
189
hal-core/resource/resource/web/api/openapi.json
Normal file
189
hal-core/resource/resource/web/api/openapi.json
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"sensorClass": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"$ref": "#/components/schemas/dataClass"
|
||||
},
|
||||
"name": {"type": "string"},
|
||||
"id": {"type": "integer"},
|
||||
"map_x": {"type": "number"},
|
||||
"map_y": {"type": "number"},
|
||||
"user": {"type": "string"},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"$ref": "#/components/schemas/configClass"
|
||||
},
|
||||
"aggregate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"timestamps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"eventClass": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"$ref": "#/components/schemas/dataClass"
|
||||
},
|
||||
"name": {"type": "string"},
|
||||
"id": {"type": "integer"},
|
||||
"map_x": {"type": "number"},
|
||||
"map_y": {"type": "number"},
|
||||
"user": {"type": "string"},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"$ref": "#/components/schemas/configClass"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"configClass": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"typeConfig": {"type": "string"},
|
||||
"typeData": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"dataClass": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"valueStr": {"type": "string"},
|
||||
"value": {"type": "number"},
|
||||
"timestamp": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"description": "Hal Server",
|
||||
"url": "/api"
|
||||
}
|
||||
],
|
||||
"openapi": "3.0.1",
|
||||
"paths": {
|
||||
"/event": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/components/schemas/eventClass"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"in": "query",
|
||||
"name": "id",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "query",
|
||||
"name": "typeConfig",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "query",
|
||||
"name": "typeData",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/sensor": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"$ref": "#/components/schemas/sensorClass"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"in": "query",
|
||||
"name": "id",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "query",
|
||||
"name": "typeConfig",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"in": "query",
|
||||
"name": "typeData",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"min",
|
||||
"hour",
|
||||
"day",
|
||||
"week",
|
||||
]
|
||||
},
|
||||
"in": "query",
|
||||
"name": "aggregation",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"description": "This API allows developers and external tools to interface to Hal data and trigger different actions.",
|
||||
"title": "Hal REST API",
|
||||
"version": ""
|
||||
}
|
||||
}
|
||||
|
|
@ -93,8 +93,8 @@
|
|||
|
||||
<script>
|
||||
$(function(){
|
||||
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);
|
||||
createChart("#min-chart", "/api/sensor?aggregation=minute&id={{sensor.getId()}}", 5*60*1000);
|
||||
createChart("#hour-chart", "/api/sensor?aggregation=hour&id={{sensor.getId()}}", 60*60*1000);
|
||||
createChart("#week-chart", "/api/sensor?aggregation=week&id={{sensor.getId()}}", 7*24*60*60*1000);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
<title>HAL is initializing...</title>
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="css/hal.css" rel="stylesheet">
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/hal.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ public class HalServer {
|
|||
http.setPage("/", new HttpRedirectPage("/map"));
|
||||
http.setPage(HalAlertManager.getInstance().getUrl(), HalAlertManager.getInstance());
|
||||
|
||||
for (Iterator<HalWebPage> it = pluginManager.getSingletonIterator(HalJsonPage.class); it.hasNext(); )
|
||||
for (Iterator<HalWebPage> it = pluginManager.getSingletonIterator(HalApiEndpoint.class); it.hasNext(); )
|
||||
registerPage(it.next());
|
||||
for (Iterator<HalWebPage> it = pluginManager.getSingletonIterator(HalWebPage.class); it.hasNext(); )
|
||||
registerPage(it.next());
|
||||
|
|
|
|||
|
|
@ -224,12 +224,12 @@ public abstract class HalAbstractDevice<V extends HalAbstractDevice, C extends H
|
|||
deviceNode.set("id", getId());
|
||||
deviceNode.set("name", getName());
|
||||
deviceNode.set("user", getUser().getUsername());
|
||||
deviceNode.set("x", getX());
|
||||
deviceNode.set("y", getY());
|
||||
deviceNode.set("map_x", getX());
|
||||
deviceNode.set("map_y", getY());
|
||||
|
||||
if (getDeviceConfig() != null) {
|
||||
DataNode configNode = deviceNode.set("config", DataNode.DataType.Map);
|
||||
configNode.set("type", getDeviceConfig().getClass().getSimpleName());
|
||||
configNode.set("typeConfig", getDeviceConfig().getClass().getSimpleName());
|
||||
configNode.set("typeData", getDeviceConfig().getDeviceDataClass().getSimpleName());
|
||||
|
||||
for (Configurator.ConfigurationParam param : getDeviceConfigurator().getConfiguration()) {
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ import java.util.logging.Logger;
|
|||
/**
|
||||
* A interface defining a Hal json endpoint
|
||||
*/
|
||||
public abstract class HalJsonPage extends HalWebPage {
|
||||
public abstract class HalApiEndpoint extends HalWebPage {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
public HalJsonPage(String id) {
|
||||
public HalApiEndpoint(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package se.hal.page.api;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import se.hal.intf.HalApiEndpoint;
|
||||
import se.hal.struct.Event;
|
||||
import zutil.ArrayUtil;
|
||||
import zutil.ObjectUtil;
|
||||
|
|
@ -22,11 +22,11 @@ import java.util.logging.Logger;
|
|||
* type: event data type name
|
||||
* </pre>
|
||||
*/
|
||||
public class EventJsonPage extends HalJsonPage {
|
||||
public class EventApiEndpoint extends HalApiEndpoint {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
|
||||
public EventJsonPage() {
|
||||
public EventApiEndpoint() {
|
||||
super("api/event");
|
||||
}
|
||||
|
||||
|
|
@ -39,31 +39,49 @@ public class EventJsonPage extends HalJsonPage {
|
|||
DBConnection db = HalContext.getDB();
|
||||
DataNode root = new DataNode(DataNode.DataType.List);
|
||||
|
||||
// Get Events
|
||||
// --------------------------------------
|
||||
// Get Action
|
||||
// --------------------------------------
|
||||
|
||||
String[] req_ids = new String[0];
|
||||
if (request.get("id") != null)
|
||||
req_ids = request.get("id").split(",");
|
||||
String req_type = request.get("type");
|
||||
|
||||
String req_typeConfig = request.get("typeConfig");
|
||||
String req_typeData = request.get("typeData");
|
||||
|
||||
// Filter devices
|
||||
|
||||
List<Event> events = new ArrayList<>();
|
||||
for (Event event : Event.getLocalEvents(db)) {
|
||||
if (ArrayUtil.contains(req_ids, "" + event.getId())) { // id filtering
|
||||
events.add(event);
|
||||
boolean filter_match = true;
|
||||
|
||||
// id filtering
|
||||
if (!ObjectUtil.isEmpty(req_ids) && !ArrayUtil.contains(req_ids, "" + event.getId())) {
|
||||
filter_match = false;
|
||||
}
|
||||
|
||||
if (!ObjectUtil.isEmpty(req_type) &&
|
||||
event.getDeviceConfig().getDeviceDataClass().getSimpleName().contains(req_type)) { // device type filtering
|
||||
events.add(event);
|
||||
// device type filtering
|
||||
if (!ObjectUtil.isEmpty(req_typeConfig) &&
|
||||
!event.getDeviceConfig().getClass().getSimpleName().equals(req_typeConfig)) {
|
||||
filter_match = false;
|
||||
}
|
||||
|
||||
// no options defined, then add all events
|
||||
if (ObjectUtil.isEmpty(req_ids, req_type)) {
|
||||
// data type filtering
|
||||
if (!ObjectUtil.isEmpty(req_typeData) &&
|
||||
!event.getDeviceConfig().getDeviceDataClass().getSimpleName().equals(req_typeData)) {
|
||||
filter_match = false;
|
||||
}
|
||||
|
||||
// Check the filter
|
||||
if (filter_match) {
|
||||
events.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
// Generate DataNode
|
||||
// --------------------------------------
|
||||
|
||||
for (Event event : events) {
|
||||
DataNode deviceNode = event.getDataNode();
|
||||
|
|
@ -2,7 +2,7 @@ package se.hal.page.api;
|
|||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.intf.HalAbstractDevice;
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import se.hal.intf.HalApiEndpoint;
|
||||
import se.hal.struct.Event;
|
||||
import se.hal.struct.Sensor;
|
||||
import zutil.db.DBConnection;
|
||||
|
|
@ -16,10 +16,10 @@ import java.util.logging.Logger;
|
|||
/**
|
||||
* TODO: This json endpoint might not be needed as we have SensorJsonPage?
|
||||
*/
|
||||
public class MapJsonPage extends HalJsonPage {
|
||||
public class MapApiEndpoint extends HalApiEndpoint {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
public MapJsonPage() {
|
||||
public MapApiEndpoint() {
|
||||
super("api/map");
|
||||
}
|
||||
|
||||
|
|
@ -2,7 +2,7 @@ package se.hal.page.api;
|
|||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.daemon.SensorDataAggregatorDaemon;
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import se.hal.intf.HalApiEndpoint;
|
||||
import se.hal.struct.Sensor;
|
||||
import se.hal.util.AggregateDataListSqlResult;
|
||||
import se.hal.util.UTCTimeUtility;
|
||||
|
|
@ -28,11 +28,11 @@ import java.util.logging.Logger;
|
|||
* aggr: Aggregation periods, needs to be provided to retrieve data. Possible values: minute,hour,day,week
|
||||
* </pre>
|
||||
*/
|
||||
public class SensorJsonPage extends HalJsonPage {
|
||||
public class SensorApiEndpoint extends HalApiEndpoint {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
|
||||
public SensorJsonPage() {
|
||||
public SensorApiEndpoint() {
|
||||
super("api/sensor");
|
||||
}
|
||||
|
||||
|
|
@ -45,60 +45,83 @@ public class SensorJsonPage extends HalJsonPage {
|
|||
DBConnection db = HalContext.getDB();
|
||||
DataNode root = new DataNode(DataNode.DataType.List);
|
||||
|
||||
// Get sensors
|
||||
String[] req_ids = new String[0];
|
||||
// --------------------------------------
|
||||
// Get Action
|
||||
// --------------------------------------
|
||||
|
||||
String[] reqIds = new String[0];
|
||||
if (request.get("id") != null)
|
||||
req_ids = request.get("id").split(",");
|
||||
String req_type = request.get("type");
|
||||
reqIds = request.get("id").split(",");
|
||||
|
||||
String reqTypeConfig = request.get("typeConfig");
|
||||
String reqTypeData = request.get("typeData");
|
||||
|
||||
|
||||
List<Sensor> sensors = new ArrayList<>();
|
||||
for (Sensor sensor : Sensor.getSensors(db)) {
|
||||
if (ArrayUtil.contains(req_ids, "" + sensor.getId())) { // id filtering
|
||||
sensors.add(sensor);
|
||||
boolean filter_match = true;
|
||||
|
||||
// id filtering
|
||||
if (!ObjectUtil.isEmpty(reqIds) && !ArrayUtil.contains(reqIds, "" + sensor.getId())) {
|
||||
filter_match = false;
|
||||
}
|
||||
|
||||
if (!ObjectUtil.isEmpty(req_type) &&
|
||||
sensor.getDeviceConfig().getDeviceDataClass().getSimpleName().contains(req_type)) { // device type filtering
|
||||
sensors.add(sensor);
|
||||
// device type filtering
|
||||
if (!ObjectUtil.isEmpty(reqTypeConfig) &&
|
||||
!sensor.getDeviceConfig().getClass().getSimpleName().equals(reqTypeConfig)) {
|
||||
filter_match = false;
|
||||
}
|
||||
|
||||
// no options defined, then add all sensors
|
||||
if (ObjectUtil.isEmpty(req_ids, req_type)) {
|
||||
// data type filtering
|
||||
if (!ObjectUtil.isEmpty(reqTypeData) &&
|
||||
!sensor.getDeviceConfig().getDeviceDataClass().getSimpleName().equals(reqTypeData)) {
|
||||
filter_match = false;
|
||||
}
|
||||
|
||||
// Check the filter
|
||||
if (filter_match) {
|
||||
sensors.add(sensor);
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out aggregation period
|
||||
// --------------------------------------
|
||||
// Was aggregated data requested
|
||||
// --------------------------------------
|
||||
|
||||
SensorDataAggregatorDaemon.AggregationPeriodLength aggrType = null;
|
||||
long aggrLength = -1;
|
||||
if (request.get("aggr") != null) {
|
||||
switch (request.get("aggr")) {
|
||||
long aggregationLength = -1;
|
||||
|
||||
if (request.get("aggregation") != null) {
|
||||
switch (request.get("aggregation")) {
|
||||
case "minute":
|
||||
aggrType = SensorDataAggregatorDaemon.AggregationPeriodLength.FIVE_MINUTES;
|
||||
aggrLength = UTCTimeUtility.DAY_IN_MS;
|
||||
aggregationLength = UTCTimeUtility.DAY_IN_MS;
|
||||
break;
|
||||
case "hour":
|
||||
aggrType = SensorDataAggregatorDaemon.AggregationPeriodLength.HOUR;
|
||||
aggrLength = UTCTimeUtility.WEEK_IN_MS;
|
||||
aggregationLength = UTCTimeUtility.WEEK_IN_MS;
|
||||
break;
|
||||
case "day":
|
||||
aggrType = SensorDataAggregatorDaemon.AggregationPeriodLength.DAY;
|
||||
aggrLength = UTCTimeUtility.INFINITY;
|
||||
aggregationLength = UTCTimeUtility.INFINITY;
|
||||
break;
|
||||
case "week":
|
||||
aggrType = SensorDataAggregatorDaemon.AggregationPeriodLength.WEEK;
|
||||
aggrLength = UTCTimeUtility.INFINITY;
|
||||
aggregationLength = UTCTimeUtility.INFINITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
// Generate DataNode
|
||||
// --------------------------------------
|
||||
|
||||
for (Sensor sensor : sensors) {
|
||||
DataNode deviceNode = sensor.getDataNode();
|
||||
|
||||
if (aggrLength > 0) {
|
||||
DataNode aggregateNode = getAggregateDataNode(aggrLength,
|
||||
AggregateDataListSqlResult.getAggregateDataForPeriod(db, sensor, aggrType, aggrLength));
|
||||
if (aggregationLength > 0) {
|
||||
DataNode aggregateNode = getAggregateDataNode(aggregationLength,
|
||||
AggregateDataListSqlResult.getAggregateDataForPeriod(db, sensor, aggrType, aggregationLength));
|
||||
deviceNode.set("aggregate", aggregateNode);
|
||||
}
|
||||
|
||||
|
|
@ -12,9 +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.api.MapJsonPage"},
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.api.EventJsonPage"},
|
||||
{"se.hal.intf.HalJsonPage": "se.hal.page.api.SensorJsonPage"},
|
||||
{"se.hal.intf.HalApiEndpoint": "se.hal.page.api.EventApiEndpoint"},
|
||||
{"se.hal.intf.HalApiEndpoint": "se.hal.page.api.MapApiEndpoint"},
|
||||
{"se.hal.intf.HalApiEndpoint": "se.hal.page.api.SensorApiEndpoint"},
|
||||
|
||||
{"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", "/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);
|
||||
createChart("#minute-power-chart", "/api/sensor?aggregation=minute", 5*60*1000);
|
||||
createChart("#hour-power-chart", "/api/sensor?aggregation=hour", 60*60*1000);
|
||||
createChart("#day-power-chart", "/api/sensor?aggregation=day", 24*60*60*1000);
|
||||
createChart("#week-power-chart", "/api/sensor?aggregation=week", 7*24*60*60*1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue