Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ Mihaela Aleksandrova
Kevin Lin
Sam Sulaimanov
Igor Melnyk
Wouter Voorberg
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ services:
volumes:
- postgresql-data:/var/lib/postgresql/data
- manager-data:/storage
ports:
- "5432:5432"

keycloak:
restart: always
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class AssetDatapointIntervalQuery extends AssetDatapointQuery {
public Formula formula;

public enum Formula {
MIN, AVG, MAX
MIN, AVG, MAX, DELTA
}

public AssetDatapointIntervalQuery() {
Expand All @@ -42,9 +42,21 @@ public String getSQLQuery(String tableName, Class<?> attributeType) throws Illeg
boolean isBoolean = Boolean.class.isAssignableFrom(attributeType);
String function = (gapFill ? "public.time_bucket_gapfill" : "public.time_bucket");
if (isNumber) {
return "select " + function + "(cast(? as interval), timestamp) AS x, " + this.formula.toString().toLowerCase() + "(cast(value as numeric)) FROM " + tableName + " WHERE ENTITY_ID = ? and ATTRIBUTE_NAME = ? and TIMESTAMP >= ? and TIMESTAMP <= ? GROUP BY x ORDER by x ASC";
if (this.formula == Formula.DELTA) {
this.gapFill = true; //check where this is set in using this code
//Returns the delta between the start and end of the period. Ex. for interval 1 minute, 10:41 will hold the difference between 10:41:00 and 10:42:00.
return "WITH interval_data AS (" + "SELECT " + function + "(cast(? as interval), timestamp) AS x, public.locf(public.last(value::DOUBLE PRECISION, timestamp)) AS numeric_value " +
"FROM " + tableName + " " + "WHERE ENTITY_ID = ? AND ATTRIBUTE_NAME = ? AND TIMESTAMP >= ? AND TIMESTAMP <= ? GROUP BY x ) SELECT x, COALESCE(numeric_value - LAG(numeric_value, 1, numeric_value) OVER (ORDER BY x), numeric_value) AS delta FROM interval_data ORDER BY x ASC";

} else {
return "select " + function + "(cast(? as interval), timestamp) AS x, " + this.formula.toString().toLowerCase() + "(cast(value as numeric)) FROM " + tableName + " WHERE ENTITY_ID = ? and ATTRIBUTE_NAME = ? and TIMESTAMP >= ? and TIMESTAMP <= ? GROUP BY x ORDER by x ASC";
}
} else if (isBoolean) {
return "select " + function + "(cast(? as interval), timestamp) AS x, " + this.formula.toString().toLowerCase() + "(case when cast(cast(value as text) as boolean) is true then 1 else 0 end) FROM " + tableName + " WHERE ENTITY_ID = ? and ATTRIBUTE_NAME = ? and TIMESTAMP >= ? and TIMESTAMP <= ? GROUP BY x ORDER by x ASC";
if (this.formula == Formula.DELTA) {
throw new IllegalStateException("Query of type DELTA is not applicable for boolean attributes.");
} else {
return "select " + function + "(cast(? as interval), timestamp) AS x, " + this.formula.toString().toLowerCase() + "(case when cast(cast(value as text) as boolean) is true then 1 else 0 end) FROM " + tableName + " WHERE ENTITY_ID = ? and ATTRIBUTE_NAME = ? and TIMESTAMP >= ? and TIMESTAMP <= ? GROUP BY x ORDER by x ASC";
}
} else {
throw new IllegalStateException("Query of type Interval requires either a number or a boolean attribute.");
}
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
],
"devDependencies": {
"@openremote/util": "workspace:*"
},
"dependencies": {
"@openremote/or-attribute-report": "workspace:^"
}
}
20 changes: 19 additions & 1 deletion ui/app/shared/locales/en/or.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@
"dataSampling": "Data sampling",
"algorithm": "Algorithm",
"algorithmMethod": "Method per interval",
"methodMaxAttributes": "Maximum",
"methodMinAttributes": "Minimum",
"methodAvgAttributes": "Average",
"methodDeltaAttributes": "Difference",
"methodMedianAttributes": "Median",
"methodModeAttributes": "Mode",
"methodSumAttributes": "Sum",
"methodCountAttributes": "Count",
"addAttribute": "Add attribute",
"selectAttributes": "Select attributes",
"selectAttribute": "Select attribute",
Expand Down Expand Up @@ -762,6 +770,9 @@
"showLegend": "Show legend",
"showGeoJson": "Show GeoJSON overlay",
"showValueAs": "Show value as",
"defaultStacked": "Stack by default",
"showToolBox": "Show Toolbox",
"isChart": "Bar chart instead of table",
"customLabel": "Custom label",
"customTimeSpan": "Custom",
"userCanEdit": "Allow user input",
Expand All @@ -773,7 +784,9 @@
"zoom": "Zoom",
"center": "Center",
"imageUrl": "Image URL",
"noImageSelected": "No image selected"
"noImageSelected": "No image selected",
"noData": "No data",
"noDataOrMethod": "No data or no method per interval selected for selected attributes"
},
"south": "South",
"east": "East",
Expand Down Expand Up @@ -858,6 +871,11 @@
"AVG": "Average (mean)",
"MIN": "Minimum",
"MAX": "Maximum",
"DELTA":"Difference",
"COUNT": "Count",
"MEDIAN": "Median",
"MODE": "Mode",
"SUM": "Sum",
"alarm": {
"": "Alarm",
"alarm_plural": "Alarms",
Expand Down
1 change: 1 addition & 0 deletions ui/component/or-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
{ "path": "../../component/or-map" },
{ "path": "../../component/or-attribute-input" },
{ "path": "../../component/or-attribute-picker" },
{ "path": "../../component/or-attribute-report" },
{ "path": "../../component/or-asset-tree" },
{ "path": "../../component/or-asset-viewer" },
{ "path": "../../component/or-data-viewer" },
Expand Down
8 changes: 8 additions & 0 deletions ui/component/or-attribute-report/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build/
build.gradle
test/
src/
webpack.config.js
tsconfig.json
dist/*.map
*.tsbuildinfo
31 changes: 31 additions & 0 deletions ui/component/or-attribute-report/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# @openremote/or-attribute-report \<or-attribute-report\>
[![NPM Version][npm-image]][npm-url]
[![Linux Build][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]

Web Component for showing calculated values at intervals of an attribute.

## Install
```bash
npm i @openremote/or-attribute-report
yarn add @openremote/or-attribute-report
```

## Usage
For a full list of properties, methods and options refer to the TypeDoc generated [documentation]().


## Supported Browsers
The last 2 versions of all modern browsers are supported, including Chrome, Safari, Opera, Firefox, Edge. In addition,
Internet Explorer 11 is also supported.


## License
[GNU AGPL](https://www.gnu.org/licenses/agpl-3.0.en.html)

[npm-image]: https://img.shields.io/npm/v/live-xxx.svg
[npm-url]: https://npmjs.org/package/@openremote/or-attribute-report
[travis-image]: https://img.shields.io/travis/live-js/live-xxx/master.svg
[travis-url]: https://travis-ci.org/live-js/live-xxx
[coveralls-image]: https://img.shields.io/coveralls/live-js/live-xxx/master.svg
[coveralls-url]: https://coveralls.io/r/live-js/live-xxx?branch=master
15 changes: 15 additions & 0 deletions ui/component/or-attribute-report/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
buildDir = "dist"

task clean() {
doLast {
delete "dist"
}
}

task prepareUi() {
dependsOn clean, npmPrepare
}

task publishUi() {
dependsOn clean, npmPublish
}
42 changes: 42 additions & 0 deletions ui/component/or-attribute-report/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "@openremote/or-attribute-report",
"version": "1.3.3",
"description": "OpenRemote attribute report",
"main": "dist/umd/index.bundle.js",
"module": "lib/index.js",
"exports": {
".": "./lib/index.js",
"./*": "./lib/*.js"
},
"types": "lib/index.d.ts",
"scripts": {
"test": "echo \"No tests\" && exit 0",
"prepack": "npx webpack"
},
"author": "OpenRemote",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@material/data-table": "^9.0.0",
"@material/dialog": "^9.0.0",
"@openremote/core": "workspace:*",
"@openremote/or-asset-tree": "workspace:*",
"@openremote/or-attribute-picker": "workspace:*",
"@openremote/or-components": "workspace:*",
"@openremote/or-icon": "workspace:*",
"@openremote/or-mwc-components": "workspace:*",
"@openremote/or-translate": "workspace:*",
"chart.js": "^3.6.0",
"echarts": "^5.6.0",
"jsonpath-plus": "^6.0.1",
"lit": "^2.0.2",
"moment": "^2.29.4"
},
"devDependencies": {
"@openremote/util": "workspace:*",
"@types/chart.js": "^2.9.34",
"@types/offscreencanvas": "^2019.6.4"
},
"publishConfig": {
"access": "public"
}
}
Loading
Loading