From 243e1b19af1b683f2d1bb8ba347eff8c9fb948e6 Mon Sep 17 00:00:00 2001 From: TrueCharts-Bot Date: Sat, 13 Apr 2024 12:47:01 +0000 Subject: [PATCH] Commit new Chart releases for TrueCharts Signed-off-by: TrueCharts-Bot --- .../TeslaMate/0.0.2}/.helmignore | 0 incubator/TeslaMate/0.0.2/CHANGELOG.md | 3 + incubator/TeslaMate/0.0.2/Chart.yaml | 39 + incubator/TeslaMate/0.0.2/README.md | 28 + incubator/TeslaMate/0.0.2/app-changelog.md | 9 + incubator/TeslaMate/0.0.2/app-readme.md | 8 + .../TeslaMate/0.0.2}/charts/common-20.3.6.tgz | Bin .../teslamate/battery-health-lfp.json | 1448 +++++++ .../dashboards/teslamate/battery-health.json | 1704 +++++++++ .../dashboards/teslamate/charge-level.json | 263 ++ .../0.0.2/dashboards/teslamate/charges.json | 1335 +++++++ .../teslamate/charging-stats-lfp.json | 1900 +++++++++ .../dashboards/teslamate/charging-stats.json | 1920 ++++++++++ .../dashboards/teslamate/drive-stats.json | 1148 ++++++ .../0.0.2/dashboards/teslamate/drives.json | 1006 +++++ .../dashboards/teslamate/efficiency.json | 1227 ++++++ .../teslamate/internal/charge-details.json | 1238 ++++++ .../teslamate/internal/drive-details.json | 2059 ++++++++++ .../teslamate/reports/dutch-tax.json | 515 +++ .../dashboards/teslamate1/locations.json | 1120 ++++++ .../0.0.2/dashboards/teslamate1/mileage.json | 317 ++ .../dashboards/teslamate1/overview-lfp.json | 1631 ++++++++ .../0.0.2/dashboards/teslamate1/overview.json | 1640 ++++++++ .../teslamate1/projected-range.json | 772 ++++ .../0.0.2/dashboards/teslamate1/states.json | 508 +++ .../dashboards/teslamate1/statistics.json | 971 +++++ .../0.0.2/dashboards/teslamate1/timeline.json | 824 ++++ .../0.0.2/dashboards/teslamate1/trip.json | 2643 +++++++++++++ .../0.0.2/dashboards/teslamate1/updates.json | 723 ++++ .../dashboards/teslamate1/vampire-drain.json | 744 ++++ .../0.0.2/dashboards/teslamate1/visited.json | 318 ++ .../dashboards/teslamate2/BatteryHealth.json | 1841 +++++++++ .../dashboards/teslamate2/BrowseCharges.json | 1486 +++++++ .../teslamate2/ChargingCostsStats.json | 3404 +++++++++++++++++ .../teslamate2/ChargingCurveStats.json | 870 +++++ .../teslamate2/ContinuousTrips.json | 810 ++++ .../teslamate2/CurrentChargeView.json | 1953 ++++++++++ .../teslamate2/CurrentDriveView.json | 1858 +++++++++ .../dashboards/teslamate2/CurrentState.json | 1841 +++++++++ .../teslamate2/DCChargingCurvesByCarrier.json | 1026 +++++ .../teslamate2/DatabaseDashboadInfo.json | 1233 ++++++ .../dashboards/teslamate2/IncompleteData.json | 446 +++ .../dashboards/teslamate2/MileageStats.json | 816 ++++ .../dashboards/teslamate2/SpeedRates.json | 1218 ++++++ .../dashboards/teslamate2/TrackingDrives.json | 1363 +++++++ incubator/TeslaMate/0.0.2/ix_values.yaml | 84 + incubator/TeslaMate/0.0.2/questions.yaml | 2911 ++++++++++++++ .../TeslaMate/0.0.2}/templates/NOTES.txt | 0 .../TeslaMate/0.0.2/templates/_configmap.tpl | 29 + .../TeslaMate/0.0.2/templates/_secrets.tpl | 13 + .../TeslaMate/0.0.2/templates/common.yaml | 17 + .../TeslaMate/0.0.2}/values.yaml | 0 stable/ghostfolio/4.22.8/CHANGELOG.md | 100 - .../ghostfolio/4.22.8/charts/redis-13.3.5.tgz | Bin 107461 -> 0 bytes .../20.1.5 => ghostfolio/4.23.0}/.helmignore | 0 stable/ghostfolio/4.23.0/CHANGELOG.md | 3 + .../ghostfolio/{4.22.8 => 4.23.0}/Chart.yaml | 8 +- .../ghostfolio/{4.22.8 => 4.23.0}/README.md | 0 .../{4.22.8 => 4.23.0}/app-changelog.md | 6 +- .../{4.22.8 => 4.23.0}/app-readme.md | 0 .../4.23.0}/charts/common-20.3.6.tgz | Bin .../4.23.0}/charts/redis-13.3.7.tgz | Bin .../{4.22.8 => 4.23.0}/ix_values.yaml | 2 +- .../{4.22.8 => 4.23.0}/questions.yaml | 0 .../4.23.0}/templates/NOTES.txt | 0 .../{4.22.8 => 4.23.0}/templates/_secrets.tpl | 0 .../{4.22.8 => 4.23.0}/templates/common.yaml | 0 .../20.1.5 => ghostfolio/4.23.0}/values.yaml | 0 stable/jackett/20.1.5/CHANGELOG.md | 100 - .../7.10.18 => jackett/20.1.7}/.helmignore | 0 stable/jackett/20.1.7/CHANGELOG.md | 3 + stable/jackett/{20.1.5 => 20.1.7}/Chart.yaml | 6 +- stable/jackett/{20.1.5 => 20.1.7}/README.md | 0 .../{20.1.5 => 20.1.7}/app-changelog.md | 22 +- .../jackett/{20.1.5 => 20.1.7}/app-readme.md | 0 .../20.1.7}/charts/common-20.3.6.tgz | Bin .../jackett/{20.1.5 => 20.1.7}/ix_values.yaml | 2 +- .../jackett/{20.1.5 => 20.1.7}/questions.yaml | 0 .../20.1.7}/templates/NOTES.txt | 0 .../{20.1.5 => 20.1.7}/templates/common.yaml | 0 .../7.10.18 => jackett/20.1.7}/values.yaml | 0 stable/libremdb/7.10.18/CHANGELOG.md | 99 - .../9.8.3 => libremdb/7.10.20}/.helmignore | 0 stable/libremdb/7.10.20/CHANGELOG.md | 3 + .../libremdb/{7.10.18 => 7.10.20}/Chart.yaml | 2 +- .../libremdb/{7.10.18 => 7.10.20}/README.md | 0 .../{7.10.18 => 7.10.20}/app-changelog.md | 6 +- .../{7.10.18 => 7.10.20}/app-readme.md | 0 .../libremdb/7.10.20/charts/common-20.3.6.tgz | Bin 0 -> 101690 bytes .../libremdb/7.10.20/charts/redis-13.3.7.tgz | Bin 0 -> 107442 bytes .../{7.10.18 => 7.10.20}/ix_values.yaml | 2 +- .../{7.10.18 => 7.10.20}/questions.yaml | 0 .../7.10.20}/templates/NOTES.txt | 0 .../templates/common.yaml | 0 .../9.8.3 => libremdb/7.10.20}/values.yaml | 0 stable/mysql-workbench/9.8.3/CHANGELOG.md | 99 - .../9.8.3/charts/common-20.3.5.tgz | Bin 101690 -> 0 bytes stable/mysql-workbench/9.8.5/.helmignore | 30 + stable/mysql-workbench/9.8.5/CHANGELOG.md | 3 + .../{9.8.3 => 9.8.5}/Chart.yaml | 6 +- .../{9.8.3 => 9.8.5}/README.md | 0 .../{9.8.3 => 9.8.5}/app-changelog.md | 6 +- .../{9.8.3 => 9.8.5}/app-readme.md | 0 .../9.8.5/charts/common-20.3.6.tgz | Bin 0 -> 101690 bytes .../{9.8.3 => 9.8.5}/ix_values.yaml | 2 +- .../{9.8.3 => 9.8.5}/questions.yaml | 0 .../mysql-workbench/9.8.5/templates/NOTES.txt | 1 + .../{9.8.3 => 9.8.5}/templates/common.yaml | 0 stable/mysql-workbench/9.8.5/values.yaml | 0 109 files changed, 51366 insertions(+), 425 deletions(-) rename {stable/ghostfolio/4.22.8 => incubator/TeslaMate/0.0.2}/.helmignore (100%) create mode 100644 incubator/TeslaMate/0.0.2/CHANGELOG.md create mode 100644 incubator/TeslaMate/0.0.2/Chart.yaml create mode 100644 incubator/TeslaMate/0.0.2/README.md create mode 100644 incubator/TeslaMate/0.0.2/app-changelog.md create mode 100644 incubator/TeslaMate/0.0.2/app-readme.md rename {stable/ghostfolio/4.22.8 => incubator/TeslaMate/0.0.2}/charts/common-20.3.6.tgz (100%) create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health-lfp.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/charge-level.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/charges.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats-lfp.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/drive-stats.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/drives.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/efficiency.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/charge-details.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/drive-details.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate/reports/dutch-tax.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/locations.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/mileage.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview-lfp.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/projected-range.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/states.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/statistics.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/timeline.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/trip.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/updates.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/vampire-drain.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate1/visited.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/BatteryHealth.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/BrowseCharges.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCostsStats.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCurveStats.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/ContinuousTrips.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentChargeView.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentDriveView.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentState.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/DCChargingCurvesByCarrier.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/DatabaseDashboadInfo.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/IncompleteData.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/MileageStats.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/SpeedRates.json create mode 100644 incubator/TeslaMate/0.0.2/dashboards/teslamate2/TrackingDrives.json create mode 100644 incubator/TeslaMate/0.0.2/ix_values.yaml create mode 100755 incubator/TeslaMate/0.0.2/questions.yaml rename {stable/ghostfolio/4.22.8 => incubator/TeslaMate/0.0.2}/templates/NOTES.txt (100%) create mode 100644 incubator/TeslaMate/0.0.2/templates/_configmap.tpl create mode 100644 incubator/TeslaMate/0.0.2/templates/_secrets.tpl create mode 100644 incubator/TeslaMate/0.0.2/templates/common.yaml rename {stable/ghostfolio/4.22.8 => incubator/TeslaMate/0.0.2}/values.yaml (100%) delete mode 100644 stable/ghostfolio/4.22.8/CHANGELOG.md delete mode 100644 stable/ghostfolio/4.22.8/charts/redis-13.3.5.tgz rename stable/{jackett/20.1.5 => ghostfolio/4.23.0}/.helmignore (100%) create mode 100644 stable/ghostfolio/4.23.0/CHANGELOG.md rename stable/ghostfolio/{4.22.8 => 4.23.0}/Chart.yaml (94%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/README.md (100%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/app-changelog.md (89%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/app-readme.md (100%) rename stable/{jackett/20.1.5 => ghostfolio/4.23.0}/charts/common-20.3.6.tgz (100%) rename stable/{libremdb/7.10.18 => ghostfolio/4.23.0}/charts/redis-13.3.7.tgz (100%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/ix_values.yaml (94%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/questions.yaml (100%) rename stable/{jackett/20.1.5 => ghostfolio/4.23.0}/templates/NOTES.txt (100%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/templates/_secrets.tpl (100%) rename stable/ghostfolio/{4.22.8 => 4.23.0}/templates/common.yaml (100%) rename stable/{jackett/20.1.5 => ghostfolio/4.23.0}/values.yaml (100%) delete mode 100644 stable/jackett/20.1.5/CHANGELOG.md rename stable/{libremdb/7.10.18 => jackett/20.1.7}/.helmignore (100%) create mode 100644 stable/jackett/20.1.7/CHANGELOG.md rename stable/jackett/{20.1.5 => 20.1.7}/Chart.yaml (94%) rename stable/jackett/{20.1.5 => 20.1.7}/README.md (100%) rename stable/jackett/{20.1.5 => 20.1.7}/app-changelog.md (91%) rename stable/jackett/{20.1.5 => 20.1.7}/app-readme.md (100%) rename stable/{libremdb/7.10.18 => jackett/20.1.7}/charts/common-20.3.6.tgz (100%) rename stable/jackett/{20.1.5 => 20.1.7}/ix_values.yaml (85%) rename stable/jackett/{20.1.5 => 20.1.7}/questions.yaml (100%) rename stable/{libremdb/7.10.18 => jackett/20.1.7}/templates/NOTES.txt (100%) rename stable/jackett/{20.1.5 => 20.1.7}/templates/common.yaml (100%) rename stable/{libremdb/7.10.18 => jackett/20.1.7}/values.yaml (100%) delete mode 100644 stable/libremdb/7.10.18/CHANGELOG.md rename stable/{mysql-workbench/9.8.3 => libremdb/7.10.20}/.helmignore (100%) create mode 100644 stable/libremdb/7.10.20/CHANGELOG.md rename stable/libremdb/{7.10.18 => 7.10.20}/Chart.yaml (98%) rename stable/libremdb/{7.10.18 => 7.10.20}/README.md (100%) rename stable/libremdb/{7.10.18 => 7.10.20}/app-changelog.md (97%) rename stable/libremdb/{7.10.18 => 7.10.20}/app-readme.md (100%) create mode 100644 stable/libremdb/7.10.20/charts/common-20.3.6.tgz create mode 100644 stable/libremdb/7.10.20/charts/redis-13.3.7.tgz rename stable/libremdb/{7.10.18 => 7.10.20}/ix_values.yaml (92%) rename stable/libremdb/{7.10.18 => 7.10.20}/questions.yaml (100%) rename stable/{mysql-workbench/9.8.3 => libremdb/7.10.20}/templates/NOTES.txt (100%) rename stable/libremdb/{7.10.18 => 7.10.20}/templates/common.yaml (100%) rename stable/{mysql-workbench/9.8.3 => libremdb/7.10.20}/values.yaml (100%) delete mode 100644 stable/mysql-workbench/9.8.3/CHANGELOG.md delete mode 100644 stable/mysql-workbench/9.8.3/charts/common-20.3.5.tgz create mode 100644 stable/mysql-workbench/9.8.5/.helmignore create mode 100644 stable/mysql-workbench/9.8.5/CHANGELOG.md rename stable/mysql-workbench/{9.8.3 => 9.8.5}/Chart.yaml (94%) rename stable/mysql-workbench/{9.8.3 => 9.8.5}/README.md (100%) rename stable/mysql-workbench/{9.8.3 => 9.8.5}/app-changelog.md (81%) rename stable/mysql-workbench/{9.8.3 => 9.8.5}/app-readme.md (100%) create mode 100644 stable/mysql-workbench/9.8.5/charts/common-20.3.6.tgz rename stable/mysql-workbench/{9.8.3 => 9.8.5}/ix_values.yaml (85%) rename stable/mysql-workbench/{9.8.3 => 9.8.5}/questions.yaml (100%) create mode 100644 stable/mysql-workbench/9.8.5/templates/NOTES.txt rename stable/mysql-workbench/{9.8.3 => 9.8.5}/templates/common.yaml (100%) create mode 100644 stable/mysql-workbench/9.8.5/values.yaml diff --git a/stable/ghostfolio/4.22.8/.helmignore b/incubator/TeslaMate/0.0.2/.helmignore similarity index 100% rename from stable/ghostfolio/4.22.8/.helmignore rename to incubator/TeslaMate/0.0.2/.helmignore diff --git a/incubator/TeslaMate/0.0.2/CHANGELOG.md b/incubator/TeslaMate/0.0.2/CHANGELOG.md new file mode 100644 index 00000000000..941abb8a218 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/CHANGELOG.md @@ -0,0 +1,3 @@ +*for the complete changelog, please refer to the website* + +**Important:** \ No newline at end of file diff --git a/incubator/TeslaMate/0.0.2/Chart.yaml b/incubator/TeslaMate/0.0.2/Chart.yaml new file mode 100644 index 00000000000..afaa71031d2 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/Chart.yaml @@ -0,0 +1,39 @@ +annotations: + max_scale_version: 24.04.0 + min_scale_version: 23.10.0 + truecharts.org/SCALE-support: "true" + truecharts.org/category: metrics + truecharts.org/max_helm_version: "3.14" + truecharts.org/min_helm_version: "3.11" + truecharts.org/train: incubator +apiVersion: v2 +appVersion: 1.28.5 +dependencies: + - name: common + version: 20.3.6 + repository: oci://tccr.io/truecharts + condition: "" + alias: "" + tags: [] + import-values: [] +deprecated: false +description: A self-hosted data logger for your Tesla +home: https://truecharts.org/charts/incubator/teslamate +icon: https://truecharts.org/img/hotlink-ok/chart-icons/teslamate.png +keywords: + - analytics + - monitoring + - metrics + - logs +kubeVersion: ">=1.24.0-0" +maintainers: + - name: TrueCharts + email: info@truecharts.org + url: https://truecharts.org +name: TeslaMate +sources: + - https://github.com/teslamate-org/teslamate + - https://docs.teslamate.org/docs/installation/docker + - https://github.com/truecharts/charts/tree/master/charts/incubator/teslamate +type: application +version: 0.0.2 diff --git a/incubator/TeslaMate/0.0.2/README.md b/incubator/TeslaMate/0.0.2/README.md new file mode 100644 index 00000000000..85835461ff8 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/README.md @@ -0,0 +1,28 @@ +--- +title: README +--- + +## General Info + +TrueCharts can be installed as both _normal_ Helm Charts or as Apps on TrueNAS SCALE. +However only installations using the TrueNAS SCALE Apps system are supported. + +For more information about this App, please check the docs on the TrueCharts [website](https://truecharts.org/charts/incubator/teslamate) + +**This chart is not maintained by the upstream project and any issues with the chart should be raised [here](https://github.com/truecharts/charts/issues/new/choose)** + +## Support + +- Please check our [quick-start guides for TrueNAS SCALE](https://truecharts.org/manual/SCALE/guides/scale-intro). +- See the [Website](https://truecharts.org) +- Check our [Discord](https://discord.gg/tVsPTHWTtr) +- Open a [issue](https://github.com/truecharts/charts/issues/new/choose) + +--- + +## Sponsor TrueCharts + +TrueCharts can only exist due to the incredible effort of our staff. +Please consider making a [donation](https://truecharts.org/sponsor) or contributing back to the project any way you can! + +_All Rights Reserved - The TrueCharts Project_ diff --git a/incubator/TeslaMate/0.0.2/app-changelog.md b/incubator/TeslaMate/0.0.2/app-changelog.md new file mode 100644 index 00000000000..2a25fd7ded1 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/app-changelog.md @@ -0,0 +1,9 @@ + + +## [teslamate-0.0.2]teslamate-0.0.2 (2024-04-13) + +### Chore + + + +- update ignored updates to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20711](https://github.com/truecharts/charts/issues/20711)) \ No newline at end of file diff --git a/incubator/TeslaMate/0.0.2/app-readme.md b/incubator/TeslaMate/0.0.2/app-readme.md new file mode 100644 index 00000000000..eb228d07050 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/app-readme.md @@ -0,0 +1,8 @@ +A self-hosted data logger for your Tesla + +This App is supplied by TrueCharts, for more information visit the manual: [https://truecharts.org/charts/incubator/TeslaMate](https://truecharts.org/charts/incubator/TeslaMate) + +--- + +TrueCharts can only exist due to the incredible effort of our staff. +Please consider making a [donation](https://truecharts.org/sponsor) or contributing back to the project any way you can! diff --git a/stable/ghostfolio/4.22.8/charts/common-20.3.6.tgz b/incubator/TeslaMate/0.0.2/charts/common-20.3.6.tgz similarity index 100% rename from stable/ghostfolio/4.22.8/charts/common-20.3.6.tgz rename to incubator/TeslaMate/0.0.2/charts/common-20.3.6.tgz diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health-lfp.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health-lfp.json new file mode 100644 index 00000000000..539f070000c --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health-lfp.json @@ -0,0 +1,1448 @@ +{ + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.5.15" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "iteration": 1681039491922, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "**Usable (now)** is the estimated current battery capacity. \n\n**Usable (new)** is the estimated Battery Capacity since you begun to use Teslamate. That's why, the more data you have logged from your brand new car the better. ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Usable (new)\", \n ('$aux'::json -> 'CurrentCapacity')::text::float as \"Usable (now)\",\n ('$aux'::json -> 'CurrentCapacity')::text::float - CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Difference\"\n \n \n \n \n \n \n ", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*_km/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/maxrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (new)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/currentrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (now)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/range_lost.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Range lost" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END as \"maxrange_$length_unit\",\n ('$aux'::json -> 'CurrentRange')::text::float as \"currentrange_$length_unit\",\n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END - ('$aux'::json -> 'CurrentRange')::text::float as \"range_lost_$length_unit\"", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ranges", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ROUND(convert_km((max(odometer) - min(odometer))::numeric, '$length_unit'),0)|| ' $length_unit' as \"Logged\"\nfrom positions where car_id = $car_id;", + "refId": "DistanceLogged", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select ROUND(convert_km(ROUND(odometer::numeric,0), '$length_unit'),0) || ' $length_unit' as \"Odometer\"\nfrom positions \nwhere car_id = $car_id\norder by date desc \nlimit 1;", + "refId": "Odometer", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Mileage", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total energy added" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 36, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_added) as \"Total energy added\"\nFROM\n\tcharging_processes\nWHERE\n\tcar_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tround(ceil(sum(charge_energy_added) / ('$aux'::json -> 'MaxCapacity')::text::numeric),0) AS \"Estimated charging cycles\"\nFROM charging_processes WHERE car_id = $car_id;", + "refId": "B", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Stats", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to have a look of the Battery health based on the data logged in Teslamate. So, the more data you have logged from your brand new car the better.\n\n**Degradation** is just an estimated value to have a reference, measured on **usable battery level** of every charging session with enough kWh added (in order to avoid dirty data form the sample), calculated according to the rated efficiency of the car.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "red", + "value": 20 + }, + { + "color": "dark-red", + "value": 30 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 17, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "/^greatest$/", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END))\n\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Estimated Degradation", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "light-green", + "value": 90 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 12, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n LEAST(100, (100 - GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END)))) as \"Battery Health (%)\"\n \n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Health", + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "Estimated charging cycles are based on the whole energy added to the battery. So the more data you logged the better. \n", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 29, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n round(('$aux'::json -> 'LastChargekWhAdded')::text::numeric,1) || ' kWh' as \"Last Energy added\",\n round(('$aux'::json -> 'LastMileageAdded')::text::numeric,1) || ' $length_unit' as \"Last Range added\"", + "refId": "LastChanging", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charges", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 2, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 34, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": ["name", "percent", "value"], + "legend": { + "displayMode": "hidden", + "placement": "bottom" + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(charge_energy_added) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Summary AC/DC Energy Added", + "type": "piechart" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "semi-dark-green", + "value": 20 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 9 + }, + "id": 25, + "options": { + "displayMode": "lcd", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": {} + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "(SELECT usable_battery_level, date\r\nFROM positions\r\nWHERE car_id = $car_id\r\nORDER BY date DESC\r\nLIMIT 1)\r\nUNION\r\nSELECT usable_battery_level, date\r\nFROM charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id\r\nWHERE p.car_id = $car_id\r\nORDER BY date DESC\r\nLIMIT 1", + "refId": "SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current SOC", + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-green", + "value": 7.84 + }, + { + "color": "semi-dark-orange", + "value": 31.36 + }, + { + "color": "light-blue", + "value": 35.28 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 27, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^kwh$/", + "values": false + }, + "showUnfilled": true, + "text": {} + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "(SELECT usable_battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM positions\nWHERE car_id = $car_id\nORDER BY date DESC\nLIMIT 1)\nUNION\nSELECT battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current Capacity", + "type": "bargauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 6 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Median" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.show", + "value": "lines" + }, + { + "id": "custom.lineStyle", + "value": { + "fill": "solid" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 28, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "pointColor": { + "field": "kWh" + }, + "x": "odometer", + "y": "kWh" + }, + { + "pointColor": { + "fixed": "dark-red" + }, + "x": "M-Odometer", + "y": "M-kWh" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km(AVG(p.odometer)::numeric,'$length_unit') AS odometer, \r\n\tAVG(c.rated_battery_range_km) * ('$aux'::json -> 'RatedEfficiency')::text::float / AVG(c.usable_battery_level) AS \"kWh\",\r\n\tMAX(cp.id) AS id,\r\n\tto_char(cp.end_date, 'YYYY-MM-dd') AS Title\r\n\tFROM charging_processes cp\r\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\r\n\t\tINNER JOIN charges c\r\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\r\n\t\tINNER JOIN positions p ON p.id = cp.position_id\r\n\tWHERE cp.car_id = $car_id\r\n\t\tAND cp.end_date IS NOT NULL\r\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\r\n\tGROUP BY 4", + "refId": "Projected Range", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "", + "datasource": "TeslaMate", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n ROUND(MIN(convert_km(p.odometer::numeric,'$length_unit')),0) AS \"M-Odometer\",\n\tROUND(PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY c.rated_battery_range_km * ('$aux'::json -> 'RatedEfficiency')::text::float / c.usable_battery_level)::numeric,1) AS \"M-kWh\",\n\tto_char(cp.end_date, 'YYYYMM') || CASE WHEN to_char(cp.end_date, 'DD')::int <= 15 THEN '1' ELSE '2' END AS Title\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN positions p ON p.id = cp.position_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\tGROUP BY 3", + "refId": "Median", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity by Mileage", + "type": "xychart" + } + ], + "refresh": "", + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "-- CONCATENATED JOIN QUERIES TO IMPROVE PERFORMANCE\nWITH\naux\tAS\n(\n\tSELECT cp.charge_energy_added,\n\t\tcp.car_id, cp.charge_energy_added / (cp.end_rated_range_km - cp.start_rated_range_km) * 100.0 AS rated_efficiency,\n\t\t(cp.end_rated_range_km - cp.start_rated_range_km) AS added_range_km\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\tORDER BY cp.end_date DESC \n\tLIMIT 1\n), \nCurrentCapacity\t AS\n(\n\tSELECT AVG(Capacity) AS CurrentCapacity FROM\n (SELECT (100.0 * cp.charge_energy_added) / (GREATEST(1,MAX(usable_battery_level) - MIN(usable_battery_level))) AS Capacity\t\n FROM charging_processes cp\n\t INNER JOIN charges c\tON cp.id = c.charging_process_id\n INNER JOIN aux ON cp.car_id = aux.car_id\n\t WHERE cp.car_id = $car_id AND cp.charge_energy_added >= aux.rated_efficiency AND cp.end_date >= date_trunc('month', current_date - interval '1 month') \n GROUP BY cp.charge_energy_added, cp.end_date\n ) AS lastEstimatedCapacity\n), \nMaxCapacity AS\n(\n\tSELECT MAX(c.rated_battery_range_km * cars.efficiency * 100.0 / c.usable_battery_level) AS MaxCapacity\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN cars ON cp.car_id = cars.id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\t\tAND c.charge_energy_added >= cars. Efficiency\n), \nCurrentRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS timecurrent,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 1 DESC\n\tLIMIT 1\n), \nMaxRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS time,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS max_rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 2 DESC\n\tLIMIT 1\n) \nSELECT CONCAT('{\"LastChargekWhAdded\": ', aux.charge_energy_added, \n ', \"LastMileageAdded\" : ', convert_km(aux.added_range_km,'$length_unit'),\n ', \"MaxRange\": ', convert_km(MaxRange.max_rated_range_km,'$length_unit'),\n ', \"CurrentRange\": ',convert_km(CurrentRange.rated_range_km,'$length_unit'),\n ', \"MaxCapacity\": ', MaxCapacity.MaxCapacity,\n ', \"CurrentCapacity\": ',CurrentCapacity.CurrentCapacity,\n ', \"RatedEfficiency\": ',aux.rated_efficiency, '}') \nFROM MaxRange, CurrentRange, Aux, MaxCapacity, CurrentCapacity;\n-- The following query is the result of many tests and hours of work. This panel is for your own personal use. \n-- If you think you can improve it and contribute, please create a pull request and do not take it to your repository, \n-- much less upload it to another repository as if the original idea were yours, nor do you share it on social media\n-- without mentioning the author. Respect the ingenuity and work of others. Cheers!\n-- 16/04/2023\n-- By @jheredianet - Twitter: @juanheredia", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "aux", + "options": [], + "query": "-- CONCATENATED JOIN QUERIES TO IMPROVE PERFORMANCE\nWITH\naux\tAS\n(\n\tSELECT cp.charge_energy_added,\n\t\tcp.car_id, cp.charge_energy_added / (cp.end_rated_range_km - cp.start_rated_range_km) * 100.0 AS rated_efficiency,\n\t\t(cp.end_rated_range_km - cp.start_rated_range_km) AS added_range_km\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\tORDER BY cp.end_date DESC \n\tLIMIT 1\n), \nCurrentCapacity\t AS\n(\n\tSELECT AVG(Capacity) AS CurrentCapacity FROM\n (SELECT (100.0 * cp.charge_energy_added) / (GREATEST(1,MAX(usable_battery_level) - MIN(usable_battery_level))) AS Capacity\t\n FROM charging_processes cp\n\t INNER JOIN charges c\tON cp.id = c.charging_process_id\n INNER JOIN aux ON cp.car_id = aux.car_id\n\t WHERE cp.car_id = $car_id AND cp.charge_energy_added >= aux.rated_efficiency AND cp.end_date >= date_trunc('month', current_date - interval '1 month') \n GROUP BY cp.charge_energy_added, cp.end_date\n ) AS lastEstimatedCapacity\n), \nMaxCapacity AS\n(\n\tSELECT MAX(c.rated_battery_range_km * cars.efficiency * 100.0 / c.usable_battery_level) AS MaxCapacity\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN cars ON cp.car_id = cars.id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\t\tAND c.charge_energy_added >= cars. Efficiency\n), \nCurrentRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS timecurrent,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 1 DESC\n\tLIMIT 1\n), \nMaxRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS time,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS max_rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 2 DESC\n\tLIMIT 1\n) \nSELECT CONCAT('{\"LastChargekWhAdded\": ', aux.charge_energy_added, \n ', \"LastMileageAdded\" : ', convert_km(aux.added_range_km,'$length_unit'),\n ', \"MaxRange\": ', convert_km(MaxRange.max_rated_range_km,'$length_unit'),\n ', \"CurrentRange\": ',convert_km(CurrentRange.rated_range_km,'$length_unit'),\n ', \"MaxCapacity\": ', MaxCapacity.MaxCapacity,\n ', \"CurrentCapacity\": ',CurrentCapacity.CurrentCapacity,\n ', \"RatedEfficiency\": ',aux.rated_efficiency, '}') \nFROM MaxRange, CurrentRange, Aux, MaxCapacity, CurrentCapacity;\n-- The following query is the result of many tests and hours of work. This panel is for your own personal use. \n-- If you think you can improve it and contribute, please create a pull request and do not take it to your repository, \n-- much less upload it to another repository as if the original idea were yours, nor do you share it on social media\n-- without mentioning the author. Respect the ingenuity and work of others. Cheers!\n-- 16/04/2023\n-- By @jheredianet - Twitter: @juanheredia", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the capacity of your car battery when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, it will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Battery Capacity (kWh) when new", + "name": "custom_kwh_new", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the max range to 100% of your car when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, the degradation will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Max Range when new", + "name": "custom_max_range", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + + "timepicker": { + "hidden": true, + "refresh_intervals": [] + }, + "timezone": "browser", + "title": "Battery Health - LFP", + "uid": "DuertWeceu", + "version": 7, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health.json new file mode 100644 index 00000000000..9db33cbfcf4 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/battery-health.json @@ -0,0 +1,1704 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.4.0" + }, + { + "type": "datasource", + "id": "grafana-postgresql-datasource", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "xychart", + "name": "XY Chart", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "**Usable (now)** is the estimated current battery capacity. It is average of the estimated capacity reported by the last 10 charging sessions to have a better estimation.\n\nIf you see just '1.0 kWh' here, it means that you need at least a long charge session.\n\n**Usable (new)** is the estimated Battery Capacity since you begun to use Teslamate. That's why, the more data you have logged from your brand new car the better. For those who have not used Teslamate since they got their new car, or for those who have bought it second hand, it's possible to set the max range to 100% and the battery capacity of the car battery when it was new in order to get a better and accurate estimation.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + }, + { + "color": "dark-red", + "value": 1 + }, + { + "color": "super-light-blue", + "value": 2 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Usable (new)\", \n ('$aux'::json -> 'CurrentCapacity')::text::float as \"Usable (now)\",\n ('$aux'::json -> 'CurrentCapacity')::text::float - CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Difference\"\n \n \n \n \n \n \n ", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*_km/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/maxrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (new)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/currentrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (now)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/range_lost.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Range lost" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END as \"maxrange_$length_unit\",\n ('$aux'::json -> 'CurrentRange')::text::float as \"currentrange_$length_unit\",\n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END - ('$aux'::json -> 'CurrentRange')::text::float as \"range_lost_$length_unit\"", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ranges", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "\"Logged\" is the distance traveled that is saved on Teslamate database.\n\n\"Mileage\" is the distance the car has traveled since using Teslamate.\n\nSo, if there is a difference between both values, it is the distance that for some reason a drive hasn't been fully recorded, for example due to a bug or an unexpected restart and that Teslamate has not been able to record, either due to lack of connection, areas without signal, or that it has been out of service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select ROUND(convert_km(sum(distance)::numeric, '$length_unit'),0)|| ' $length_unit' as \"Logged\"\r\nfrom drives \r\nwhere car_id = $car_id;\r\n", + "refId": "Looged", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ROUND(convert_km((max(odometer) - min(odometer))::numeric, '$length_unit'),0)|| ' $length_unit' as \"Mileage\"\nfrom positions where car_id = $car_id;", + "refId": "Mileage", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select ROUND(convert_km(ROUND(odometer::numeric,0), '$length_unit'),0) || ' $length_unit' as \"Odometer\"\nfrom positions \nwhere car_id = $car_id\norder by date desc \nlimit 1;", + "refId": "Odometer", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Trips", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 2, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 34, + "maxDataPoints": 3, + "options": { + "displayLabels": ["name", "percent", "value"], + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": false, + "values": ["value"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current,\n\t\tcp.charge_energy_used\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tSUM(GREATEST(charge_energy_added, charge_energy_used)) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Summary AC/DC Energy Used", + "type": "piechart" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to have a look of the Battery health based on the data logged in Teslamate. So, the more data you have logged from your brand new car the better.\n\n**Degradation** is just an estimated value to have a reference, measured on **usable battery level** of every charging session with enough kWh added (in order to avoid dirty data from the sample), calculated according to the rated efficiency of the car.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "red", + "value": 20 + }, + { + "color": "dark-red", + "value": 30 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 17, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "/^greatest$/", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END))\n\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Estimated Degradation", + "type": "gauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "light-green", + "value": 90 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 12, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n LEAST(100, (100 - GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END)))) as \"Battery Health (%)\"\n \n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Health", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "\"Charging cycles\" are estimations based on the whole energy added to the battery.\n\n\"Charge Efficiency\" is estimated on the difference between energy used from the charger and energy added to the battery.", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total energy added" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total energy used" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Charge Efficiency" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 36, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_added) as \"Total energy added\"\nFROM\n\tcharging_processes\nWHERE\n\tcar_id = $car_id AND charge_energy_added > 0.01", + "refId": "Total energy added", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\r\n\tSUM(charge_energy_used) AS \"Total energy used\"\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\tcar_id = $car_id AND charge_energy_added > 0.01\r\n", + "refId": "Total energy used", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\r\n\tCOUNT(*) AS \"Total charges\"\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\tcar_id = $car_id AND charge_energy_added > 0.01\r\n\t", + "refId": "Total charges", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tfloor(sum(charge_energy_added) / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END) AS \"Charging cycles\"\nFROM charging_processes WHERE car_id = $car_id AND charge_energy_added > 0.01", + "refId": "Charging cycles", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\r\n\tSUM(charge_energy_added) * 100 / SUM(charge_energy_used) AS \"Charge Efficiency\"\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\tcar_id = $car_id AND charge_energy_added > 0.01\r\n", + "refId": "Charge Efficiency", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Battery Stats", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-orange", + "value": 80 + }, + { + "color": "light-blue", + "value": 100 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 9 + }, + "id": 25, + "options": { + "displayMode": "lcd", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "text": {}, + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT * FROM ((SELECT usable_battery_level, date\r\nFROM positions\r\nWHERE car_id = $car_id AND usable_battery_level IS NOT NULL\r\nORDER BY date DESC\r\nLIMIT 1)\r\nUNION\r\n(SELECT usable_battery_level, date\r\nFROM charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id\r\nWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL\r\nORDER BY date DESC\r\nLIMIT 1)) AS last_usable_battery_level LIMIT 1", + "refId": "SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current SOC", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-green", + "value": 7.84 + }, + { + "color": "semi-dark-orange", + "value": 31.36 + }, + { + "color": "light-blue", + "value": 35.28 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 27, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^kwh$/", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "text": {}, + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT * FROM ((SELECT usable_battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM positions\nWHERE car_id = $car_id AND usable_battery_level IS NOT NULL\nORDER BY date DESC\nLIMIT 1)\nUNION\n(SELECT battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL\nORDER BY date DESC\nLIMIT 1)) AS last_usable_battery_level LIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current Capacity", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-RdYlGr" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 6 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Median" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.show", + "value": "lines" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "name": "Odometer", + "pointColor": { + "field": "kWh" + }, + "pointSize": { + "fixed": 5, + "max": 100, + "min": 1 + }, + "x": "odometer", + "y": "kWh" + }, + { + "name": "Median Odometer", + "pointColor": { + "fixed": "dark-red" + }, + "x": "M-Odometer", + "y": "M-kWh" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km(AVG(p.odometer)::numeric,'$length_unit') AS odometer, \r\n\tAVG(c.rated_battery_range_km * ('$aux'::json -> 'RatedEfficiency')::text::float / c.usable_battery_level) AS \"kWh\",\r\n\tMAX(cp.id) AS id,\r\n\tto_char(cp.end_date, 'YYYY-MM-dd') AS Title\r\n\tFROM charging_processes cp\r\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges WHERE usable_battery_level > 0 GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\r\n\t\tINNER JOIN charges c\r\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\r\n\t\tINNER JOIN positions p ON p.id = cp.position_id\r\n\tWHERE cp.car_id = $car_id\r\n\t\tAND cp.end_date IS NOT NULL\r\n\t\tAND cp.charge_energy_added >= ('$aux'::json -> 'RatedEfficiency')::text::float\r\n\tGROUP BY 4", + "refId": "Projected Range", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n ROUND(MIN(convert_km(p.odometer::numeric,'$length_unit')),0) AS \"M-Odometer\",\n\tROUND(PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY c.rated_battery_range_km * ('$aux'::json -> 'RatedEfficiency')::text::float / c.usable_battery_level)::numeric,1) AS \"M-kWh\",\n\tto_char(cp.end_date, 'YYYYMM') || CASE WHEN to_char(cp.end_date, 'DD')::int <= 15 THEN '1' ELSE '2' END AS Title\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges WHERE usable_battery_level > 0 GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN positions p ON p.id = cp.position_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.charge_energy_added >= ('$aux'::json -> 'RatedEfficiency')::text::float\n\tGROUP BY 3", + "refId": "Median", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity by Mileage", + "type": "xychart" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT unit_of_length FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "SELECT unit_of_length FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT preferred_range FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "SELECT preferred_range FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT base_url FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "SELECT base_url FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "-- CONCATENATED JOIN QUERIES TO IMPROVE PERFORMANCE", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "aux", + "options": [], + "query": "WITH Aux AS\n(\n\t\tSELECT \n car_id,\n\t\tCOALESCE(efficiency, \n\t\t(SELECT efficiency\n\t\t\tFROM cars WHERE id = $car_id) * 100) AS efficiency\n\tFROM (\n\t\tSELECT ROUND((charge_energy_added / NULLIF(end_rated_range_km - start_rated_range_km, 0))::numeric, 3) * 100 as efficiency,\n\t\t\tCOUNT(*) as count, $car_id AS car_id \n\t\tFROM charging_processes\n\t\tWHERE car_id = $car_id\n\t\t\tAND duration_min > 10\n\t\t\tAND end_battery_level <= 95\n\t\t\tAND start_rated_range_km IS NOT NULL\n\t\t\tAND end_rated_range_km IS NOT NULL\n\t\t\tAND charge_energy_added > 0\n\t\tGROUP BY 1\n\t\tORDER BY 2 DESC\n\t\tLIMIT 1\n\t) AS DerivatedEfficiency\n),\nCurrentCapacity\t AS\n(\n\tSELECT AVG(Capacity) AS Capacity\nFROM (\nSELECT \n\tc.[[preferred_range]]_battery_range_km * aux.efficiency / c.usable_battery_level AS Capacity\n\tFROM charging_processes cp\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id \n INNER JOIN aux ON cp.car_id = aux.car_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.charge_energy_added >= aux.efficiency\n\t\tAND c.usable_battery_level > 0\n\t ORDER BY cp.end_date DESC LIMIT 10) AS lastCharges\n), \nMaxCapacity AS\n(\n\tSELECT \n\t\tMAX(c.[[preferred_range]]_battery_range_km * aux.efficiency / c.usable_battery_level) AS Capacity\n\tFROM charging_processes cp\n\t\tINNER JOIN (\n\t\t\tSELECT charging_process_id, MAX(date) as date FROM charges WHERE usable_battery_level > 0 GROUP BY charging_process_id) AS gcharges\t\n\t\t\tON cp.id = gcharges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = gcharges.date\n\t\tINNER JOIN aux ON cp.car_id = aux.car_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.charge_energy_added >= aux.efficiency\n), \nCurrentRange AS\n(\n SELECT (range * 100.0 / usable_battery_level) AS range\n\tFROM (\n\t\t(SELECT date, [[preferred_range]]_battery_range_km AS range, usable_battery_level AS usable_battery_level\n\t\t\tFROM positions\tWHERE car_id = $car_id AND [[preferred_range]]_battery_range_km IS NOT NULL AND usable_battery_level > 0 ORDER BY date DESC LIMIT 1)\n\t\tUNION ALL\n\t\t(SELECT date, [[preferred_range]]_battery_range_km AS range, usable_battery_level as usable_battery_level\n\t\t\tFROM charges c JOIN charging_processes p ON p.id = c.charging_process_id\n\t\t\tWHERE p.car_id = $car_id AND usable_battery_level > 0 ORDER BY date DESC LIMIT 1)\n\t) AS data\n\tORDER BY date DESC\n\tLIMIT 1\n), \nMaxRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS time,\n\t CASE WHEN sum(usable_battery_level) = 0 THEN sum([[preferred_range]]_battery_range_km) * 100\n\t\t ELSE sum([[preferred_range]]_battery_range_km) / sum(usable_battery_level) * 100\n\tEND AS range\n FROM (\n\t\tSELECT battery_level, usable_battery_level, date, [[preferred_range]]_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 2 DESC\n\tLIMIT 1\n) \nSELECT CONCAT('{\"MaxRange\": ', convert_km(MaxRange.range,'$length_unit'),\n ', \"CurrentRange\": ',convert_km(CurrentRange.range,'$length_unit'),\n ', \"MaxCapacity\": ', MaxCapacity.Capacity,\n ', \"CurrentCapacity\": ', CASE WHEN CurrentCapacity.Capacity IS NULL THEN 1 ELSE CurrentCapacity.Capacity END,\n ', \"RatedEfficiency\": ', aux.efficiency, '}') \nFROM MaxRange, CurrentRange, Aux, MaxCapacity, CurrentCapacity", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the capacity of your car battery when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, it will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Battery Capacity (kWh) when new", + "name": "custom_kwh_new", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the max range to 100% of your car when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, the degradation will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Max Range when new", + "name": "custom_max_range", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "timepicker": { + "hidden": true + }, + "timezone": "browser", + "title": "Battery Health", + "uid": "jchmRiqUfXgTM", + "version": 16, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/charge-level.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charge-level.json new file mode 100644 index 00000000000..41af0d8bc8e --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charge-level.json @@ -0,0 +1,263 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1656100496202, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Charge Level", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "transparent", + "value": 20 + }, + { + "color": "green", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": ["mean", "max", "min"], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tbattery_level AS \"Battery Level\",\n\tusable_battery_level AS \"Usable Battery Level\"\nfrom positions\n\tWHERE $__timeFilter(date) AND car_id = $car_id\n\tORDER BY Time ASC\n;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charge Level", + "type": "timeseries" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charge Level", + "uid": "WopVO_mgz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/charges.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charges.json new file mode 100644 index 00000000000..46d4456da3c --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charges.json @@ -0,0 +1,1335 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642763869363, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "View charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}&var-car_id=${__data.fields.car_id.numeric}&var-charging_process_id=${__data.fields.id.numeric:raw}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Added" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "% Start" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 65 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "% End" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 65 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "m" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_avg_c" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "celsius" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#C0D8FF", + "value": null + }, + { + "color": "#C8F2C2", + "value": 10 + }, + { + "color": "#FFA6B0", + "value": 20 + } + ] + } + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost" + }, + "properties": [ + { + "id": "displayName", + "value": "Cost" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "Set Cost", + "url": "[[base_url:raw]]/charge-cost/${__data.fields.id.numeric:raw}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + }, + { + "id": "noValue", + "value": "-" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "address" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.path:raw}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Driven" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added_per_hour" + }, + "properties": [ + { + "id": "displayName", + "value": "kW" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#96D98D", + "value": null + }, + { + "color": "#56A64B", + "value": 20 + }, + { + "color": "#37872D", + "value": 55 + } + ] + } + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_added_per_hour_km" + }, + "properties": [ + { + "id": "displayName", + "value": "km / h" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_avg_f" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Driven" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_added_per_hour_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "mi / h" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "path" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Used" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charging_efficiency" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "car_id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_date" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost_per_kwh" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "displayName", + "value": "Cost/kWh" + }, + { + "id": "custom.width", + "value": 100 + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "noValue", + "value": "-" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_km" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "displayName", + "value": "Odometer" + }, + { + "id": "unit", + "value": "km" + }, + { + "id": "decimals" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_mi" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "displayName", + "value": "Odometer" + }, + { + "id": "unit", + "value": "mi" + }, + { + "id": "decimals" + } + ] + } + ] + }, + "gridPos": { + "h": 19, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts,\n (round(extract(epoch FROM end_date) + 10) * 1000) AS end_date_ts,\n start_date,\n end_date,\n CONCAT_WS(', ', COALESCE(addresses.name, nullif(CONCAT_WS(' ', addresses.road, addresses.house_number), '')), addresses.city) AS address,\n g.name as geofence_name,\n g.id as geofence_id,\n p.latitude,\n p.longitude,\n cp.charge_energy_added,\n cp.charge_energy_used,\n duration_min,\n start_battery_level,\n end_battery_level,\n start_[[preferred_range]]_range_km,\n end_[[preferred_range]]_range_km,\n outside_temp_avg,\n cp.id,\n lag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n p.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance,\n cars.efficiency,\n cp.car_id,\n cost,\n max(c.charger_voltage) as max_charger_voltage,\n p.odometer as odometer\n FROM\n charging_processes cp\n\t LEFT JOIN charges c ON cp.id = c.charging_process_id\n LEFT JOIN positions p ON p.id = cp.position_id\n LEFT JOIN cars ON cars.id = cp.car_id\n LEFT JOIN addresses ON addresses.id = cp.address_id\n LEFT JOIN geofences g ON g.id = geofence_id\nWHERE \n cp.car_id = $car_id AND\n $__timeFilter(start_date) AND\n (cp.charge_energy_added IS NULL OR cp.charge_energy_added > 0) AND\n ('${geofence:pipe}' = '-1' OR geofence_id in ($geofence))\nGROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,21,p.odometer\nORDER BY\n start_date\n)\nSELECT\n start_date_ts,\n end_date_ts,\n CASE WHEN geofence_id IS NULL THEN CONCAT('new?lat=', latitude, '&lng=', longitude)\n WHEN geofence_id IS NOT NULL THEN CONCAT(geofence_id, '/edit')\n END as path,\n car_id,\n id,\n -- Columns\n start_date,\n end_date,\n COALESCE(geofence_name, address) as address, \n duration_min,\n cost,\n cost / NULLIF(greatest(charge_energy_added, charge_energy_used), 0) as cost_per_kwh,\n charge_energy_added,\n charge_energy_used,\n CASE WHEN charge_energy_used IS NULL THEN NULL ELSE LEAST(charge_energy_added / NULLIF(charge_energy_used, 0), 1.0) END as charging_efficiency,\n convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_avg_$temp_unit,\n charge_energy_added * 60 / NULLIF (duration_min, 0) AS charge_energy_added_per_hour,\n convert_km((end_[[preferred_range]]_range_km - start_[[preferred_range]]_range_km) * 60 / NULLIF (duration_min, 0), '$length_unit') AS range_added_per_hour_$length_unit,\n start_battery_level,\n end_battery_level,\n convert_km(distance::numeric, '$length_unit') AS distance_$length_unit,\n convert_km(odometer::numeric, '$length_unit') AS odometer_$length_unit\n FROM\n data\nWHERE\n (distance >= 0 OR distance IS NULL)\n AND max_charger_voltage >= '$voltage'\n AND duration_min >= '$min_duration_min'\nORDER BY\n start_date DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "datasource": "TeslaMate", + "title": "Charges", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT start_date as \"time\", charge_energy_added\nFROM charging_processes\nWHERE \n $__timeFilter(end_date) AND \n car_id = $car_id AND \n ('${geofence:pipe}' = '-1' OR geofence_id in ($geofence))\nORDER BY start_date;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Energy added", + "transparent": true, + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 12, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT start_date as \"time\", greatest(charge_energy_added, charge_energy_used)\nFROM charging_processes\nWHERE \n $__timeFilter(end_date) AND \n car_id = $car_id AND \n ('${geofence:pipe}' = '-1' OR geofence_id in ($geofence))\nORDER BY start_date;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Energy used", + "transparent": true, + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 13, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT start_date as \"time\", cost\nFROM charging_processes\nWHERE \n $__timeFilter(end_date) AND \n car_id = $car_id AND \n ('${geofence:pipe}' = '-1' OR geofence_id in ($geofence))\nORDER BY start_date;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Cost", + "transparent": true, + "type": "stat" + } + ], + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "-1", + "current": { + "selected": false, + "text": ["All"], + "value": ["$__all"] + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM geofences ORDER BY name COLLATE \"C\" ASC;", + "hide": 0, + "includeAll": true, + "label": "Geofence", + "multi": true, + "name": "geofence", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM geofences ORDER BY name COLLATE \"C\" ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": true, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "Enter min duration (minutes) here", + "name": "min_duration_min", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": true, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "Enter min voltage here", + "name": "voltage", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charges", + "uid": "TSmNYvRRk", + "version": 4, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats-lfp.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats-lfp.json new file mode 100644 index 00000000000..90364ab8931 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats-lfp.json @@ -0,0 +1,1900 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:75", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "iteration": 1658137661652, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 1 + }, + "id": 8, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tcount(*)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND charge_energy_added > 0.01\n\tAND car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Charges", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 5, + "y": 1 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_added)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;\n", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charged in total", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 10, + "y": 1 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(cp.cost)\nFROM\n\tcharging_processes cp\nLEFT JOIN \n\taddresses addr ON addr.id = address_id\nLEFT JOIN\n geofences geo ON geo.id = geofence_id\nWHERE\n $__timeFilter(end_date)\n AND (addr.name ILIKE '%supercharger%' OR geo.name ILIKE '%supercharger%')\n\tAND cp.cost IS NOT NULL\n\tAND cp.car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Cost at SuC", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 14, + "y": 1 + }, + "id": 27, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(cost)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Charging Cost", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d8d9da", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 1 + }, + "id": 26, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT (\n SELECT sum(cost)\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n) / (\n\tSELECT convert_km((max(odometer) - min(odometer))::numeric, '$length_unit')\n\tFROM positions\n\tWHERE $__timeFilter(date) AND car_id = $car_id\n) * 100", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Cost per 100 $length_unit", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d8d9da", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 1 + }, + "id": 31, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT (\n SELECT sum(cost)\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n) / (\n SELECT sum(greatest(charge_energy_added, charge_energy_used))\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n)", + "refId": "A", + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average Cost per kWh", + "type": "stat" + }, + { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "linear", + "colorScheme": "interpolateGreens", + "exponent": 0.5, + "min": 0, + "mode": "opacity" + }, + "dataFormat": "timeseries", + "datasource": "TeslaMate", + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 4 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 15, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(start_date),\n\tstart_battery_level,\n\tend_battery_level\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(start_date)\n\tAND duration_min > 3\n\tAND car_id = $car_id\nORDER BY\n\tstart_date;", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": "6M", + "title": "Charge Heatmap", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "yAxis": { + "format": "short", + "logBase": 1, + "max": "100", + "show": true + }, + "yBucketBound": "auto", + "yBucketSize": 10.00001 + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-green", + "value": null + }, + { + "color": "transparent", + "value": 20 + }, + { + "color": "dark-green", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Start SOC" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillBelowTo", + "value": "End SOC" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "End SOC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + }, + { + "id": "custom.fillBelowTo", + "value": "Start SOC" + }, + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charges AS (\n\tSELECT\n\t\tstart_date,\n\t\tstart_battery_level,\n\t\tend_battery_level,\n\t\tp.odometer,\n\t\tCOALESCE(\n\t\t\tLAG(p.odometer) OVER (\n\t\t\t\tORDER BY cp.start_date\n\t\t\t),\n\t\t\tp.odometer\n\t\t) as odometer_prev\n\tFROM\n\t\tcharging_processes cp\n\tJOIN positions p\n\tON p.id = cp.position_id\n\tWHERE\n\t\t$__timeFilter(cp.start_date)\n\t\tAND cp.duration_min > 3\n\t\tAND cp.car_id = $car_id\n)\nSELECT\n\tMIN(start_date) as time,\n\tMIN(start_battery_level) as \"Start SOC\",\n\tMAX(end_battery_level) as \"End SOC\"\nFROM charges\nGROUP BY\n\tCASE WHEN odometer - odometer_prev < 2 THEN odometer_prev ELSE odometer END\nORDER BY\n\ttime;", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": "6M", + "title": "Charge Delta", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 0, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 5, + "x": 0, + "y": 10 + }, + "id": 18, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": ["name"], + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "bottom", + "values": ["value", "percent"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n\t AND $__timeFilter(start_date)\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(charge_energy_added) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "AC/DC - kWh", + "type": "piechart" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-reds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pct" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "chg_total" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 14, + "x": 5, + "y": 10 + }, + "id": 24, + "maxDataPoints": 1, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "tooltip": true, + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": false, + "style": { + "color": { + "field": "pct", + "fixed": "red" + }, + "opacity": 0.4, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "field": "chg_total", + "fixed": 5, + "max": 30, + "min": 5 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "text": { + "field": "chg_total", + "fixed": "", + "mode": "field" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 15, + "offsetY": 0, + "textAlign": "left", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "Charge location", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": "TeslaMate", + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charge_data AS (\r\nSELECT COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS loc_nm\r\n, AVG(position.latitude) AS latitude\r\n, AVG(position.longitude) AS longitude\r\n, sum(charge.charge_energy_added) AS chg_total\r\n, count(*) as charges\r\nFROM charging_processes charge\r\nLEFT JOIN addresses address ON charge.address_id = address.id\r\nLEFT JOIN positions position ON charge.position_id = position.id\r\nLEFT JOIN geofences geofence ON charge.geofence_id = geofence.id\r\nWHERE $__timeFilter(charge.start_date) \r\nAND charge.car_id = $car_id\r\nGROUP BY COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city))\r\n) \r\nSELECT loc_nm\r\n\t,latitude\r\n\t,longitude\r\n\t,chg_total\r\n\t,chg_total * 1.0 / (SELECT sum(chg_total) FROM charge_data) * 100 AS pct\r\n\t,charges\r\nFROM charge_data", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging heat map by kWh", + "type": "geomap" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 1, + "mappings": [], + "unit": "dtdurations" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 5, + "x": 19, + "y": 10 + }, + "id": 20, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": ["name"], + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "bottom", + "values": ["value", "percent"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.duration_min,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n\t AND $__timeFilter(start_date)\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(duration_min) * 60 AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "AC/DC - Duration", + "type": "piechart" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-RdYlGr", + "seriesBy": "last" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 3 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Show charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date.numeric}&to=${__data.fields.end_date.numeric}&var-car_id=${car_id}&var-charging_process_id=${__data.fields.charging_process_id.numeric}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 29, + "links": [], + "options": { + "dims": { + "exclude": ["charging_process_id"], + "frame": 0 + }, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "pointColor": { + "field": "Power [kW]" + }, + "x": "SOC [%]", + "y": "Power [kW]" + }, + { + "pointColor": { + "field": "B - Avg Power [kW]" + }, + "pointSize": { + "fixed": 15, + "max": 100, + "min": 1 + }, + "x": "B - SOC [%]", + "y": "B - Avg Power [kW]" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.11", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n c.battery_level as \"SOC [%]\",\r\n round(avg(c.charger_power), 0) as \"Power [kW]\",\r\n c.charging_process_id as \"charging_process_id\",\r\n p.start_date as \"start_date\",\r\n p.end_date as \"end_date\",\r\n COALESCE(g.name, a.name) || ' ' || to_char(c.date, 'YYYY-MM-dd') as \"Charge\"\r\nFROM\r\n charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id \r\nJOIN addresses a ON a.id = p.address_id\r\nLEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n $__timeFilter(date)\r\n AND p.car_id = $car_id\r\n AND charger_power > 0\r\n AND c.fast_charger_present\r\nGROUP BY c.battery_level, c.charging_process_id, a.name, g.name, p,start_date, p.end_date, to_char(c.date, 'YYYY-MM-dd')", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n c.battery_level as \"B - SOC [%]\",\n PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY charger_power) as \"B - Avg Power [kW]\"\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND charger_power > 0\n AND c.fast_charger_present\nGROUP BY battery_level", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "DC Charging Curve", + "transformations": [], + "type": "xychart" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "soc" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + }, + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "n" + }, + "properties": [ + { + "id": "displayName", + "value": "# of Charges" + }, + { + "id": "custom.displayMode", + "value": "gradient-gauge" + }, + { + "id": "max" + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 3, + "x": 0, + "y": 39 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tROUND(end_battery_level / 5, 0) * 5 AS SOC,\n\tcount(*) AS n\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND duration_min > 3\n\tAND car_id = $car_id\nGROUP BY\n\tROUND(end_battery_level / 5, 0) * 5\nORDER BY\n\tSOC DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charge Stats", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "soc" + }, + "properties": [ + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.width", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "n" + }, + "properties": [ + { + "id": "displayName", + "value": "# of Discharges" + }, + { + "id": "custom.displayMode", + "value": "gradient-gauge" + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 3, + "x": 3, + "y": 39 + }, + "id": 13, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tROUND(start_battery_level / 5, 0) * 5 AS SOC,\n\tcount(*) AS n\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND duration_min > 3\n\tAND car_id = $car_id\nGROUP BY\n 1\nORDER BY\n\tSOC DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Discharge Stats", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Charged" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.align", + "value": "left" + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 9, + "x": 6, + "y": 39 + }, + "id": 4, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS location,\n\tCASE\n WHEN SUM(charge_energy_added) < 1000 THEN SUM(charge_energy_added)::NUMERIC(4,0)::VARCHAR || ' kWh' \n WHEN SUM(charge_energy_added) < 1000000 THEN (SUM(charge_energy_added) / 1000)::NUMERIC(9, 3)::VARCHAR || ' MWh' \n WHEN SUM(charge_energy_added) >= 1000000 THEN (SUM(charge_energy_added) / 1000000)::NUMERIC(9, 3)::VARCHAR || ' GWh' \n END as charge_energy_added\nFROM\n\tcharging_processes c\nLEFT JOIN addresses address ON c.address_id = address.id\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\nGROUP BY\n\t1\nORDER BY\n\tSUM(charge_energy_added) DESC\nLIMIT 17;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Charging Stations (Charged)", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost" + }, + "properties": [ + { + "id": "displayName", + "value": "Cost" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align", + "value": "left" + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 9, + "x": 15, + "y": 39 + }, + "id": 6, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, CONCAT_WS(' ', address.road, address.house_number)), address.city)) AS location,\n\tsum(cost) as cost\nFROM\n\tcharging_processes c\n\tLEFT JOIN addresses address ON c.address_id = address.id\n\tLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n $__timeFilter(end_date) AND\n\tcar_id = $car_id AND\n\tCOST IS NOT NULL\nGROUP BY\n\t1\nORDER BY\n\t2 DESC NULLS LAST\nLIMIT 17;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Charging Stations (Cost)", + "type": "table" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-10y", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charging Stats - LFP", + "uid": "UcjFKmUtpt", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats.json new file mode 100644 index 00000000000..3b176f386ad --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/charging-stats.json @@ -0,0 +1,1920 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:75", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "iteration": 1658137661652, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 1 + }, + "id": 8, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tcount(*)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND charge_energy_added > 0.01\n\tAND car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Charges", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 5, + "y": 1 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_added)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;\n", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charged in total", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 10, + "y": 1 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(cp.cost)\nFROM\n\tcharging_processes cp\nLEFT JOIN \n\taddresses addr ON addr.id = address_id\nLEFT JOIN\n geofences geo ON geo.id = geofence_id\nWHERE\n $__timeFilter(end_date)\n AND (addr.name ILIKE '%supercharger%' OR geo.name ILIKE '%supercharger%')\n\tAND cp.cost IS NOT NULL\n\tAND cp.car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Cost at SuC", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 14, + "y": 1 + }, + "id": 27, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(cost)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Charging Cost", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d8d9da", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 1 + }, + "id": 26, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT (\n SELECT sum(cost)\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n) / (\n\tSELECT convert_km((max(odometer) - min(odometer))::numeric, '$length_unit')\n\tFROM positions\n\tWHERE $__timeFilter(date) AND car_id = $car_id\n) * 100", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Cost per 100 $length_unit", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d8d9da", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 1 + }, + "id": 31, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT (\n SELECT sum(cost)\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n) / (\n SELECT sum(greatest(charge_energy_added, charge_energy_used))\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n)", + "refId": "A", + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average Cost per kWh", + "type": "stat" + }, + { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "linear", + "colorScheme": "interpolateGreens", + "exponent": 0.5, + "min": 0, + "mode": "opacity" + }, + "dataFormat": "timeseries", + "datasource": "TeslaMate", + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 4 + }, + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 15, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(start_date),\n\tstart_battery_level,\n\tend_battery_level\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(start_date)\n\tAND duration_min > 3\n\tAND car_id = $car_id\nORDER BY\n\tstart_date;", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": "6M", + "title": "Charge Heatmap", + "tooltip": { + "show": true, + "showHistogram": false + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "yAxis": { + "format": "short", + "logBase": 1, + "max": "100", + "show": true + }, + "yBucketBound": "auto", + "yBucketSize": 10.00001 + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-green", + "value": null + }, + { + "color": "transparent", + "value": 20 + }, + { + "color": "dark-green", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Start SOC" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillBelowTo", + "value": "End SOC" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "End SOC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + }, + { + "id": "custom.fillBelowTo", + "value": "Start SOC" + }, + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charges AS (\n\tSELECT\n\t\tstart_date,\n\t\tstart_battery_level,\n\t\tend_battery_level,\n\t\tp.odometer,\n\t\tCOALESCE(\n\t\t\tLAG(p.odometer) OVER (\n\t\t\t\tORDER BY cp.start_date\n\t\t\t),\n\t\t\tp.odometer\n\t\t) as odometer_prev\n\tFROM\n\t\tcharging_processes cp\n\tJOIN positions p\n\tON p.id = cp.position_id\n\tWHERE\n\t\t$__timeFilter(cp.start_date)\n\t\tAND cp.duration_min > 3\n\t\tAND cp.car_id = $car_id\n)\nSELECT\n\tMIN(start_date) as time,\n\tMIN(start_battery_level) as \"Start SOC\",\n\tMAX(end_battery_level) as \"End SOC\"\nFROM charges\nGROUP BY\n\tCASE WHEN odometer - odometer_prev < 2 THEN odometer_prev ELSE odometer END\nORDER BY\n\ttime;", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": "6M", + "title": "Charge Delta", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 0, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 5, + "x": 0, + "y": 10 + }, + "id": 18, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": ["name"], + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "bottom", + "values": ["value", "percent"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n\t AND $__timeFilter(start_date)\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(charge_energy_added) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "AC/DC - kWh", + "type": "piechart" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-reds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "pct" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "chg_total" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 14, + "x": 5, + "y": 10 + }, + "id": 24, + "maxDataPoints": 1, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "tooltip": true, + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": false, + "style": { + "color": { + "field": "pct", + "fixed": "red" + }, + "opacity": 0.4, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "field": "chg_total", + "fixed": 5, + "max": 30, + "min": 5 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "text": { + "field": "chg_total", + "fixed": "", + "mode": "field" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 15, + "offsetY": 0, + "textAlign": "left", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "Charge location", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": "TeslaMate", + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charge_data AS (\r\nSELECT COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS loc_nm\r\n, AVG(position.latitude) AS latitude\r\n, AVG(position.longitude) AS longitude\r\n, sum(charge.charge_energy_added) AS chg_total\r\n, count(*) as charges\r\nFROM charging_processes charge\r\nLEFT JOIN addresses address ON charge.address_id = address.id\r\nLEFT JOIN positions position ON charge.position_id = position.id\r\nLEFT JOIN geofences geofence ON charge.geofence_id = geofence.id\r\nWHERE $__timeFilter(charge.start_date) \r\nAND charge.car_id = $car_id\r\nGROUP BY COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city))\r\n) \r\nSELECT loc_nm\r\n\t,latitude\r\n\t,longitude\r\n\t,chg_total\r\n\t,chg_total * 1.0 / (SELECT sum(chg_total) FROM charge_data) * 100 AS pct\r\n\t,charges\r\nFROM charge_data", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging heat map by kWh", + "type": "geomap" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 1, + "mappings": [], + "unit": "dtdurations" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 5, + "x": 19, + "y": 10 + }, + "id": 20, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": ["name"], + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "bottom", + "values": ["value", "percent"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.duration_min,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n\t AND $__timeFilter(start_date)\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(duration_min) * 60 AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "AC/DC - Duration", + "type": "piechart" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-RdYlGr", + "seriesBy": "last" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 3 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Show charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date.numeric}&to=${__data.fields.end_date.numeric}&var-car_id=${car_id}&var-charging_process_id=${__data.fields.charging_process_id.numeric}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 29, + "links": [], + "options": { + "dims": { + "exclude": ["charging_process_id"], + "frame": 0 + }, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "pointColor": { + "field": "Power [kW]" + }, + "x": "SOC [%]", + "y": "Power [kW]" + }, + { + "pointColor": { + "field": "B - Avg Power [kW]" + }, + "pointSize": { + "fixed": 15, + "max": 100, + "min": 1 + }, + "x": "B - SOC [%]", + "y": "B - Avg Power [kW]" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.11", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n c.battery_level as \"SOC [%]\",\r\n round(avg(c.charger_power), 0) as \"Power [kW]\",\r\n c.charging_process_id as \"charging_process_id\",\r\n p.start_date as \"start_date\",\r\n p.end_date as \"end_date\",\r\n COALESCE(g.name, a.name) || ' ' || to_char(c.date, 'YYYY-MM-dd') as \"Charge\"\r\nFROM\r\n charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id \r\nJOIN addresses a ON a.id = p.address_id\r\nLEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n $__timeFilter(date)\r\n AND p.car_id = $car_id\r\n AND charger_power > 0\r\n AND c.fast_charger_present\r\nGROUP BY c.battery_level, c.charging_process_id, a.name, g.name, p,start_date, p.end_date, to_char(c.date, 'YYYY-MM-dd')", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n c.battery_level as \"B - SOC [%]\",\n PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY charger_power) as \"B - Avg Power [kW]\"\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND charger_power > 0\n AND c.fast_charger_present\nGROUP BY battery_level", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "DC Charging Curve", + "transformations": [], + "type": "xychart" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "soc" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + }, + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 80 + }, + { + "color": "red", + "value": 91 + } + ] + } + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "n" + }, + "properties": [ + { + "id": "displayName", + "value": "# of Charges" + }, + { + "id": "custom.displayMode", + "value": "gradient-gauge" + }, + { + "id": "max" + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 3, + "x": 0, + "y": 39 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tROUND(end_battery_level / 5, 0) * 5 AS SOC,\n\tcount(*) AS n\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND duration_min > 3\n\tAND car_id = $car_id\nGROUP BY\n\tROUND(end_battery_level / 5, 0) * 5\nORDER BY\n\tSOC DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charge Stats", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "soc" + }, + "properties": [ + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.width", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "n" + }, + "properties": [ + { + "id": "displayName", + "value": "# of Discharges" + }, + { + "id": "custom.displayMode", + "value": "gradient-gauge" + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 3, + "x": 3, + "y": 39 + }, + "id": 13, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tROUND(start_battery_level / 5, 0) * 5 AS SOC,\n\tcount(*) AS n\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND duration_min > 3\n\tAND car_id = $car_id\nGROUP BY\n 1\nORDER BY\n\tSOC DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Discharge Stats", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Charged" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.align", + "value": "left" + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 9, + "x": 6, + "y": 39 + }, + "id": 4, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS location,\n\tCASE\n WHEN SUM(charge_energy_added) < 1000 THEN SUM(charge_energy_added)::NUMERIC(4,0)::VARCHAR || ' kWh' \n WHEN SUM(charge_energy_added) < 1000000 THEN (SUM(charge_energy_added) / 1000)::NUMERIC(9, 3)::VARCHAR || ' MWh' \n WHEN SUM(charge_energy_added) >= 1000000 THEN (SUM(charge_energy_added) / 1000000)::NUMERIC(9, 3)::VARCHAR || ' GWh' \n END as charge_energy_added\nFROM\n\tcharging_processes c\nLEFT JOIN addresses address ON c.address_id = address.id\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\nGROUP BY\n\t1\nORDER BY\n\tSUM(charge_energy_added) DESC\nLIMIT 17;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Charging Stations (Charged)", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost" + }, + "properties": [ + { + "id": "displayName", + "value": "Cost" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align", + "value": "left" + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 9, + "x": 15, + "y": 39 + }, + "id": 6, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, CONCAT_WS(' ', address.road, address.house_number)), address.city)) AS location,\n\tsum(cost) as cost\nFROM\n\tcharging_processes c\n\tLEFT JOIN addresses address ON c.address_id = address.id\n\tLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n $__timeFilter(end_date) AND\n\tcar_id = $car_id AND\n\tCOST IS NOT NULL\nGROUP BY\n\t1\nORDER BY\n\t2 DESC NULLS LAST\nLIMIT 17;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Charging Stations (Cost)", + "type": "table" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-10y", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charging Stats", + "uid": "-pkIkhmRz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/drive-stats.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/drive-stats.json new file mode 100644 index 00000000000..ce134792864 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/drive-stats.json @@ -0,0 +1,1148 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1644505954964, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [], + "repeat": "car_id", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "title": "$car_id", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 20, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n date_trunc('day', start_date) as \"time\",\n count(*)\nFROM drives\nWHERE $__timeFilter(start_date) AND car_id = $car_id\nGROUP BY 1\nORDER BY 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of drives", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 16, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH since as (\n\tSELECT date FROM positions\n\tWHERE car_id = $car_id\n\tORDER BY date ASC\n\tLIMIT 1\n),\nactual AS (\n\tSELECT\n\t\tdate_trunc('day', date)::date AS date,\n\t\tmax(odometer) - min(odometer) AS distance\n\tFROM positions\n\tWHERE car_id = $car_id\n\tGROUP BY 1\n),\nbase_line AS (\n\tSELECT date_trunc('day', dd)::date AS date\n FROM generate_series((select date from since) , now(), '1 day'::interval) dd\n)\nSELECT \n $__time(base_line.date), \n convert_km(COALESCE(distance, 0)::numeric, '$length_unit') as \"distance_$length_unit\"\nFROM base_line\nLEFT JOIN actual ON actual.date = base_line.date\nWHERE $__timeFilter(base_line.date)\nORDER BY 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$length_unit driven", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-yellow", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 22, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(start_date),\n NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency AS energy\nFROM drives\nJOIN cars car ON car.id = car_id\nWHERE $__timeFilter(start_date) AND car_id = $car_id\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "kWh used", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 5 + }, + "id": 26, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km((percentile_disc(0.5) WITHIN GROUP (ORDER BY distance))::numeric, '$length_unit') as \"distance_$length_unit\"\nFROM drives\nWHERE car_id = $car_id AND $__timeFilter(start_date);", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Average distance of a drive", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 8, + "y": 5 + }, + "id": 8, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH since as (\n\tSELECT date FROM positions\n\tWHERE car_id = $car_id\n\tORDER BY date ASC\n\tLIMIT 1\n),\nactual AS (\n\tSELECT\n\t\tdate_trunc('day', start_date)::date AS date,\n\t\tsum(distance) AS distance\n\tFROM drives\n\tWHERE car_id = $car_id\n\tGROUP BY 1\n),\nbase_line AS (\n\tSELECT date_trunc('day', dd)::date AS date\n FROM generate_series((select date from since), NOW(), '1 day'::interval) dd\n),\ncombined as (\n SELECT base_line.date, COALESCE(actual.distance, 0) as distance\n FROM base_line\n LEFT JOIN actual ON actual.date = base_line.date\n WHERE $__timeFilter(base_line.date)\n)\nSELECT convert_km((percentile_disc(0.5) WITHIN GROUP (ORDER BY distance))::numeric, '$length_unit') AS \"distance_$length_unit\"\nFROM combined;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Average distance driven per day", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 16, + "y": 5 + }, + "id": 14, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH since as (\n\tSELECT date FROM positions\n\tWHERE car_id = $car_id\n\tORDER BY date ASC\n\tLIMIT 1\n),\nactual AS (\n\tSELECT\n\t\tdate_trunc('day', start_date)::date AS date,\n\t\tsum(NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency) AS energy\n\tFROM drives\n\tJOIN cars car ON car.id = car_id\n\tWHERE car_id = $car_id\n\tGROUP BY 1\n),\nbase_line AS (\n\tSELECT date_trunc('day', dd)::date AS date\n FROM generate_series((select date from since), NOW(), '1 day'::interval) dd\n),\ncombined as (\n SELECT base_line.date, COALESCE(actual.energy, 0) as energy\n FROM base_line\n LEFT JOIN actual ON actual.date = base_line.date\n WHERE $__timeFilter(base_line.date)\n)\nSELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY energy) AS energy\nFROM combined;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Average kWh used per day", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "mileage_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "mileage_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 32, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH first_position AS (\n\tSELECT date, odometer\n\tFROM positions\n\tWHERE car_id = $car_id AND $__timeFilter(date)\n\tORDER BY date ASC\n\tLIMIT 1\n),\nlast_position AS (\n\tSELECT date, odometer\n\tFROM positions\n\tWHERE car_id = $car_id AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1\n)\nSELECT\n\tconvert_km((((SELECT odometer FROM last_position) - (SELECT odometer\tFROM first_position)) /\n\tEXTRACT(days FROM (SELECT date FROM last_position) - (SELECT date\tFROM first_position)) * \n\t(365/12))::numeric, '$length_unit') AS \"mileage_$length_unit\";", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Extrapolated monthly mileage", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "mileage_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "mileage_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 30, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH first_position AS (\n\tSELECT date, odometer\n\tFROM positions\n\tWHERE car_id = $car_id AND $__timeFilter(date)\n\tORDER BY date ASC\n\tLIMIT 1\n),\nlast_position AS (\n\tSELECT date, odometer\n\tFROM positions\n\tWHERE car_id = $car_id AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1\n)\nSELECT\n\tconvert_km(((lp.odometer - fp.odometer) /\n\tEXTRACT(days FROM lp.date - fp.date) * \n\t365)::numeric, '$length_unit') AS \"mileage_$length_unit\" from first_position as fp, last_position as lp;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Extrapolated annual mileage", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": {}, + "displayName": "$__cell_0", + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + }, + { + "color": "light-red", + "value": 50 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 24, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.4", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(g.name, array_to_string(((string_to_array(a.display_name, ', ', ''))[0:3]), ', ')) as name,\n\tcount(*) AS visited\nFROM drives t\nINNER JOIN addresses a ON end_address_id = a.id\nLEFT JOIN geofences g ON end_geofence_id = g.id\nWHERE t.car_id = $car_id AND $__timeFilter(t.start_date)\nGROUP BY 1\nORDER BY visited DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Top Destinations", + "type": "bargauge" + } + ], + "refresh": false, + "schemaVersion": 26, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1y", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Drive Stats", + "uid": "_7WkNSyWk", + "version": 1 +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/drives.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/drives.json new file mode 100644 index 00000000000..8113735f987 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/drives.json @@ -0,0 +1,1006 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:24", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642770916740, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "View drive details", + "url": "d/zm7wN6Zgz?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}&var-car_id=${__data.fields.car_id.numeric}&var-drive_id=${__data.fields.drive_id.numeric}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 110 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 110 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "km" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kWh" + }, + "properties": [ + { + "id": "displayName", + "value": "kWh" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_address" + }, + "properties": [ + { + "id": "displayName", + "value": "Start" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.start_path}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_address" + }, + "properties": [ + { + "id": "displayName", + "value": "Destination" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.end_path}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_c" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "celsius" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "m" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "${__data.fields.duration_str}", + "url": "" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#FFA6B0", + "value": null + }, + { + "color": "#FFCB7D", + "value": 0.65 + }, + { + "color": "#C8F2C2", + "value": 0.99 + } + ] + } + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_avg_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed" + }, + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "mi" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_f" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_avg_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed" + }, + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/(start|end)_path/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_str" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "car_id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "% Start" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "% End" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "has_reduced_range" + }, + "properties": [ + { + "id": "displayName", + "value": "❄" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "false": { + "color": "transparent", + "index": 1, + "text": "." + }, + "true": { + "color": "dark-blue", + "index": 0, + "text": "❄" + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.width", + "value": 5 + }, + { + "id": "links", + "value": [ + { + "title": "In cold weather, the estimated consumption may be incorrect and is therefore sometimes hidden.", + "url": "" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "drive_id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "power_max" + }, + "properties": [ + { + "id": "displayName", + "value": "max Power" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + } + ] + }, + "gridPos": { + "h": 24, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n round(extract(epoch FROM start_date)) * 1000 AS start_date_ts,\n round(extract(epoch FROM end_date)) * 1000 AS end_date_ts,\n car.id as car_id,\n CASE WHEN start_geofence.id IS NULL THEN CONCAT('new?lat=', start_position.latitude, '&lng=', start_position.longitude)\n WHEN start_geofence.id IS NOT NULL THEN CONCAT(start_geofence.id, '/edit')\n END as start_path,\n CASE WHEN end_geofence.id IS NULL THEN CONCAT('new?lat=', end_position.latitude, '&lng=', end_position.longitude)\n WHEN end_geofence.id IS NOT NULL THEN CONCAT(end_geofence.id, '/edit')\n END as end_path,\n TO_CHAR((duration_min * INTERVAL '1 minute'), 'HH24:MI') as duration_str,\n drives.id as drive_id,\n -- Columns\n start_date,\n COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS start_address,\n COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS end_address,\n duration_min,\n distance,\n start_position.usable_battery_level as start_usable_battery_level,\n start_position.battery_level as start_battery_level,\n end_position.usable_battery_level as end_usable_battery_level,\n end_position.battery_level as end_battery_level,\n case when (start_position.battery_level != start_position.usable_battery_level OR end_position.battery_level != end_position.usable_battery_level) = true then true else false end as reduced_range,\n duration_min > 1 AND distance > 1 AND ( \n start_position.usable_battery_level IS NULL OR end_position.usable_battery_level IS NULL\tOR\n (end_position.battery_level - end_position.usable_battery_level) = 0 \n ) as is_sufficiently_precise,\n NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) as range_diff,\n car.efficiency as car_efficiency,\n outside_temp_avg,\n distance / NULLIF(duration_min, 0) * 60 AS avg_speed,\n power_max\n FROM drives\n LEFT JOIN addresses start_address ON start_address_id = start_address.id\n LEFT JOIN addresses end_address ON end_address_id = end_address.id\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id\n LEFT JOIN geofences start_geofence ON start_geofence_id = start_geofence.id\n LEFT JOIN geofences end_geofence ON end_geofence_id = end_geofence.id\n LEFT JOIN cars car ON car.id = drives.car_id\n WHERE $__timeFilter(start_date) AND drives.car_id = $car_id AND convert_km(distance::numeric, '$length_unit') >= $min_dist AND convert_km(distance::numeric, '$length_unit') / NULLIF(duration_min, 0) * 60 >= $min_speed\n ORDER BY start_date DESC\n)\nSELECT\n start_date_ts,\n end_date_ts,\n car_id,\n start_path,\n end_path,\n duration_str,\n drive_id,\n -- Columns\n start_date,\n start_address,\n end_address,\n duration_min,\n convert_km(distance::numeric, '$length_unit') AS distance_$length_unit,\n start_battery_level as \"% Start\",\n end_battery_level as \"% End\",\n convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_$temp_unit,\n convert_km(avg_speed::numeric, '$length_unit') AS speed_avg_$length_unit,\n power_max,\n reduced_range as has_reduced_range,\n range_diff * car_efficiency as \"consumption_kWh\",\n CASE WHEN is_sufficiently_precise THEN range_diff * car_efficiency / distance * 1000 * CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END\n END AS consumption_kWh_$length_unit,\n CASE WHEN is_sufficiently_precise THEN distance / range_diff\n ELSE NULL\n END AS efficiency\nFROM data;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "datasource": "TeslaMate", + "title": "Drive", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + } + ], + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "temperature unit", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "length unit", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "includeAll": false, + "label": "Enter min distance here", + "name": "min_dist", + "options": [], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "includeAll": false, + "label": "Enter min speed here", + "name": "min_speed", + "options": [], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Drives", + "uid": "Y8upc6ZRk", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/efficiency.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/efficiency.json new file mode 100644 index 00000000000..3a2b3439a65 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/efficiency.json @@ -0,0 +1,1227 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1598013087999, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 10, + "panels": [], + "repeat": "car_id", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "title": "$car_id", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 4, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n sum((start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km) * cars.efficiency) / sum(distance) * 1000 * \n CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END AS \"consumption_$length_unit\"\nfrom drives \ninner join cars on cars.id = car_id\nwhere \n distance is not null and\n start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km >= 0.1 and\n car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Consumption (net)", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 8, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d1 AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM\n\t\tcharging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id\n\tORDER BY\n\t\tstart_date\n),\nd2 AS (\nSELECT\n\tcar_id,\n\tsum(range_loss) AS range_loss,\n\tsum(distance) AS distance\nFROM\n\td1\nWHERE\n\tdistance >= 0 AND range_loss >= 0\nGROUP BY\n\tcar_id\n)\nSELECT\nrange_loss * c.efficiency / distance * 1000 *\n CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END AS \"consumption_$length_unit\"\nFROM\n\td2\n\tLEFT JOIN cars c ON c.id = car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Consumption (gross) ", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 6, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select convert_km(sum(distance)::numeric, '$length_unit') as \"distance_$length_unit\" \nfrom drives \nwhere car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Logged Distance", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "outside_temp_c" + }, + "properties": [ + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "unit", + "value": "celsius" + }, + { + "id": "custom.width", + "value": 125 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_f" + }, + "properties": [ + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "custom.width", + "value": 125 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "lcd-gauge" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-orange", + "value": null + }, + { + "color": "light-orange", + "value": 0.65 + }, + { + "color": "light-green", + "value": 0.99 + } + ] + } + }, + { + "id": "max", + "value": 1.15 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "total_distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "$length_unit" + }, + { + "id": "unit", + "value": "km" + }, + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "total_distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "$length_unit" + }, + { + "id": "unit", + "value": "mi" + }, + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_speed_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed" + }, + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_speed_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed" + }, + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "custom.width", + "value": 200 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 2, + "links": [], + "options": { + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Temperature" + } + ] + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH t AS (\n\tSELECT\n\t CASE WHEN '$temp_unit' = 'C' THEN ROUND(cast(outside_temp_avg AS numeric) / 5, 0) * 5 \n\t\t\t WHEN '$temp_unit' = 'F' THEN ROUND(cast(convert_celsius(outside_temp_avg, '$temp_unit') AS numeric) / 10, 0) * 10\n\t\tEND AS outside_temp,\n\t\tsum(start_ideal_range_km - end_ideal_range_km) AS total_ideal_range,\n\t\tsum(start_rated_range_km - end_rated_range_km) AS total_rated_range,\n\t\tsum(distance) AS total_distance,\n\t\tsum(duration_min) as duration,\n\t\tcar_id\n\tFROM\n\t\tdrives\n\tWHERE\n\t\tdistance IS NOT NULL\n\t\tAND car_id = $car_id\n\t\tAND convert_km(distance::numeric, '$length_unit') >= $min_distance \n\t\tAND start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km > 0.1\n\tGROUP BY\n\t\t1,\n\t\tcar_id\n)\n\nSELECT\n\toutside_temp as outside_temp_$temp_unit,\n total_distance / total_[[preferred_range]]_range AS efficiency,\n\ttotal_[[preferred_range]]_range / total_distance * c.efficiency * 1000 * \n CASE \n WHEN '$length_unit' = 'km' THEN 1 \n WHEN '$length_unit' = 'mi' THEN 1.60934 \n END AS consumption_$length_unit,\n convert_km(total_distance::numeric, '$length_unit') as total_distance_$length_unit,\n\t(total_distance / duration) * 60 / (CASE \n WHEN '$length_unit' = 'km' THEN 1 \n WHEN '$length_unit' = 'mi' THEN 1.60934 \n END) avg_speed_$length_unit\nFROM\n\tt\nJOIN cars c ON t.car_id = c.id\nWHERE outside_temp IS NOT NULL\norder by 1 desc\n", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature – Efficiency", + "type": "table" + }, + { + "cacheTimeout": null, + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "efficiency_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 2, + "x": 0, + "y": 16 + }, + "id": 14, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCASE WHEN '$length_unit' = 'km' THEN efficiency\n\t WHEN '$length_unit' = 'mi' THEN efficiency * 1.60934\n\tEND * 1000 as \"efficiency_$length_unit\"\nFROM\n\tcars\nWHERE\n\tid = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Current $preferred_range efficiency", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "efficiency_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 11, + "x": 2, + "y": 16 + }, + "id": 12, + "options": { + "showHeader": true + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n round((charge_energy_added / NULLIF(end_ideal_range_km - start_ideal_range_km, 0))::numeric *\n\t CASE WHEN '$length_unit' = 'km' THEN 1.0\n\t WHEN '$length_unit' = 'mi' THEN 1.60934\n\t END, 3) * 1000 as \"efficiency_$length_unit\",\n count(*) as count\nFROM\n charging_processes\nWHERE \n car_id = $car_id\n AND duration_min > 10\n AND end_battery_level <= 95\n AND start_ideal_range_km IS NOT NULL\n AND end_ideal_range_km IS NOT NULL\n AND charge_energy_added > 0\nGROUP BY\n 1\nORDER BY\n 2 DESC\nLIMIT 3", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Derived ideal efficiencies", + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "efficiency_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "displayName", + "value": "Efficiency" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 11, + "x": 13, + "y": 16 + }, + "id": 15, + "options": { + "showHeader": true + }, + "pluginVersion": "7.2.1", + "scopedVars": { + "car_id": { + "selected": true, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n round((charge_energy_added / NULLIF(end_rated_range_km - start_rated_range_km, 0))::numeric *\n\t CASE WHEN '$length_unit' = 'km' THEN 1.0\n\t WHEN '$length_unit' = 'mi' THEN 1.60934\n\t END, 3) * 1000 as \"efficiency_$length_unit\",\n\tcount(*) as count\nFROM\n charging_processes\nWHERE \n car_id = $car_id\n AND duration_min > 10\n AND end_battery_level <= 95\n AND start_rated_range_km IS NOT NULL\n AND end_rated_range_km IS NOT NULL\n AND charge_energy_added > 0\nGROUP BY\n 1\nORDER BY\n 2 DESC\nLIMIT 3", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Derived rated efficiencies", + "type": "table" + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": true, + "text": "1", + "value": "1" + }, + "hide": 0, + "includeAll": false, + "label": "min. distance per drive", + "multi": false, + "name": "min_distance", + "options": [ + { + "selected": true, + "text": "1", + "value": "1" + }, + { + "selected": false, + "text": "5", + "value": "5" + }, + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "25", + "value": "25" + }, + { + "selected": false, + "text": "50", + "value": "50" + } + ], + "query": "1, 5, 10, 25, 50", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "hidden": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Efficiency", + "uid": "fu4SiQgWz", + "version": 1 +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/charge-details.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/charge-details.json new file mode 100644 index 00000000000..8706c5e162b --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/charge-details.json @@ -0,0 +1,1238 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "geomap", + "name": "Geomap", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + }, + { + "type": "panel", + "id": "xychart", + "name": "XY Chart", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1656106965302, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMax": 100, + "axisSoftMin": 0, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "charger_voltage" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "displayName", + "value": "Charging Voltage" + }, + { + "id": "unit", + "value": "volt" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_power" + }, + "properties": [ + { + "id": "displayName", + "value": "Power" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "battery_heater" + }, + "properties": [ + { + "id": "displayName", + "value": "Battery heater" + }, + { + "id": "unit", + "value": "bool_on_off" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_km$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "^range_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Range" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_actual_current" + }, + "properties": [ + { + "id": "displayName", + "value": "Current" + }, + { + "id": "unit", + "value": "amp" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_pilot_current" + }, + "properties": [ + { + "id": "displayName", + "value": "Current (pilot)" + }, + { + "id": "unit", + "value": "amp" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_c$" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_f$" + }, + "properties": [ + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "^outside_temp_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Outdoor Temperature" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_phases" + }, + "properties": [ + { + "id": "displayName", + "value": "Phases" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 20, + "w": 17, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": ["min", "max"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n battery_level,\n charger_power,\n (case when battery_heater_on then 10 when battery_heater then 10 else 0 end) as battery_heater,\n convert_km([[preferred_range]]_battery_range_km, '$length_unit') as range_$length_unit,\n charger_voltage,\n (case when charger_phases = 2 then 3 when charger_phases = 1 then 1 else 0 end) as charger_phases,\n charger_actual_current,\n charger_pilot_current,\n convert_celsius(outside_temp, '$temp_unit') outside_temp_$temp_unit\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\nORDER BY\n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charge Details", + "type": "timeseries" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 1, + "displayName": "Added", + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-yellow", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 17, + "y": 0 + }, + "id": 8, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select coalesce(cp.charge_energy_added, c.charge_energy_added)\r\nfrom charging_processes cp\r\njoin charges c\r\n\ton cp.id = c.charging_process_id\r\nwhere car_id = $car_id\r\nAND cp.id = $charging_process_id\r\nORDER BY c.date desc\r\nfetch first row only", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ], + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "Cost", + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 6, + "links": [ + { + "title": "Set cost", + "url": "[[base_url:raw]]/charge-cost/${charging_process_id}" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT cost from charging_processes where id = $charging_process_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ], + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 7, + "x": 17, + "y": 3 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n COALESCE(g.name, CONCAT_WS(', ', COALESCE(addresses.name, CONCAT_WS(' ', addresses.road, addresses.house_number)), addresses.city))\nFROM\n\tcharging_processes c\n\tLEFT JOIN addresses ON addresses.id = c.address_id\n\tLEFT JOIN geofences g ON g.id = geofence_id\nWHERE\n\tc.id = $charging_process_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ], + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + } + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 15, + "w": 7, + "x": 17, + "y": 5 + }, + "id": 4, + "links": [], + "maxDataPoints": 500, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": false, + "style": { + "color": { + "fixed": "dark-blue" + }, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 7, + "max": 15, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "filterData": { + "id": "byRefId", + "options": "A" + }, + "location": { + "latitude": "latitude", + "longitude": "longitude", + "mode": "auto" + }, + "name": "Layer 1", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tunnest(ARRAY[latitude, latitude]) AS latitude,\n\tunnest(ARRAY[longitude, longitude]) AS longitude\nFROM\n\tcharging_processes c\n\tJOIN positions p ON c.position_id = p.id\nWHERE\n\t$__timeFilter(date)\n\tAND c.car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "geomap" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 5 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.show", + "value": "lines" + }, + { + "id": "custom.lineStyle", + "value": { + "fill": "solid" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + } + ] + } + ] + }, + "gridPos": { + "h": 19, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 11, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "pointColor": {}, + "x": "SOC [%]", + "y": "Power [kW]" + }, + { + "pointColor": { + "fixed": "blue" + }, + "x": "avg SOC [%]", + "y": "avg Power [kW]" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.11", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n battery_level as \"SOC [%]\",\n charger_power as \"Power [kW]\"\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND charger_power > 0\nORDER BY\n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n battery_level as \"avg SOC [%]\",\n avg(charger_power) as \"avg Power [kW]\"\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND charger_power > 0\nGROUP BY\n battery_level, fast_charger_present\nORDER BY\n battery_level ASC ", + "refId": "B", + "select": [ + [ + { + "params": ["odometer"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging curve", + "type": "xychart" + } + ], + "refresh": false, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "NULL", + "value": "NULL" + }, + "hide": 2, + "label": "", + "name": "charging_process_id", + "options": [ + { + "selected": false, + "text": "NULL", + "value": "NULL" + } + ], + "query": "NULL", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-12h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charge Details", + "uid": "BHhxFeZRz", + "version": 2, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/drive-details.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/drive-details.json new file mode 100644 index 00000000000..b0b8f9a01c5 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/internal/drive-details.json @@ -0,0 +1,2059 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:31", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "iteration": 1658136653681, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "icon": "", + "tags": [], + "title": "GpxExport", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]/drive/$drive_id/gpx" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 5, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_kmh$" + }, + "properties": [ + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mph$" + }, + "properties": [ + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_km$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "speed_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "power" + }, + "properties": [ + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "custom.axisPlacement", + "value": "left" + }, + { + "id": "displayName", + "value": "Power" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "battery_heater" + }, + "properties": [ + { + "id": "displayName", + "value": "Battery heater" + }, + { + "id": "unit", + "value": "bool_on_off" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "range_ideal_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Range (ideal)" + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "range_rated_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Range (rated)" + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "battery_level" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "usable_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "usable SOC" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "range_estimated_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Range (est.)" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 17, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": ["mean", "max", "min"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tconvert_km(speed::numeric, '$length_unit') AS speed_[[length_unit]]h,\n\tpower,\n\tbattery_heater::integer,\n\tconvert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range_[[preferred_range]]_[[length_unit]],\n\tconvert_km(est_battery_range_km, '$length_unit') AS range_estimated_[[length_unit]],\n\tbattery_level,\n\tusable_battery_level\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nORDER BY\n\tdate ASC", + "refId": "A", + "select": [ + [ + { + "params": ["id"], + "type": "column" + } + ] + ], + "table": "charging", + "timeColumn": "Datum", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Drive", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "Distance", + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + } + ] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select convert_km(distance::numeric, '$length_unit') as \"$length_unit\" from drives where id = $drive_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + }, + "unit": "dtdurations" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 3, + "x": 18, + "y": 0 + }, + "id": 34, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "datasource": "TeslaMate", + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "SELECT ${__to:date:seconds} - ${__from:date:seconds}", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Selected duration", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + } + ] + }, + "unit": "dtdurations" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ((DATE_PART('day', end_date - start_date) * 24 + \n DATE_PART('hour', end_date - start_date)) * 60 +\n DATE_PART('minute', end_date - start_date)) * 60 +\n DATE_PART('second', end_date - start_date) as sec_diff\nFROM drives\nWHERE drives.id = $drive_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Drive duration", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "Energy used", + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 12, + "y": 2 + }, + "id": 12, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t(NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency)\nFROM\n\tdrives d\nJOIN cars car ON car.id = car_id\nWHERE\n\td.id = $drive_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "displayName": "Consumption", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 200 + }, + { + "color": "red", + "value": 250 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 18, + "y": 2 + }, + "id": 18, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\t(NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency) *1000 /\n\t convert_km(distance::numeric, '$length_unit') as \"$length_unit\"\nfrom drives d\nJOIN cars car ON car.id = car_id\nwhere d.id = $drive_id;", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 27, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 4, + "links": [], + "maxDataPoints": 50000, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 3, + "max": 15, + "min": 2 + }, + "symbol": { + "field": "", + "fixed": "", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "route", + "opacity": 1, + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "editorMode": "code", + "format": "time_series", + "group": [ + { + "params": ["$__interval", "none"], + "type": "time" + } + ], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n latitude,\n longitude\nFROM positions\nWHERE \n car_id = $car_id AND \n $__timeFilter(date)\nORDER BY \n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["lat"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ], + [ + { + "params": ["lng"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ] + }, + "table": "pos", + "timeColumn": "Datum", + "timeColumnType": "datetime", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Map", + "type": "geomap" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 5, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_front_left_bar" + }, + "properties": [ + { + "id": "unit", + "value": "pressurebar" + }, + { + "id": "displayName", + "value": "front left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_front_right_bar" + }, + "properties": [ + { + "id": "unit", + "value": "pressurebar" + }, + { + "id": "displayName", + "value": "front right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_rear_left_bar" + }, + "properties": [ + { + "id": "unit", + "value": "pressurebar" + }, + { + "id": "displayName", + "value": "rear left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_rear_right_bar" + }, + "properties": [ + { + "id": "unit", + "value": "pressurebar" + }, + { + "id": "displayName", + "value": "rear right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_front_left_psi" + }, + "properties": [ + { + "id": "unit", + "value": "pressurepsi" + }, + { + "id": "displayName", + "value": "front left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_front_right_psi" + }, + "properties": [ + { + "id": "unit", + "value": "pressurepsi" + }, + { + "id": "displayName", + "value": "front right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_rear_left_psi" + }, + "properties": [ + { + "id": "unit", + "value": "pressurepsi" + }, + { + "id": "displayName", + "value": "rear left" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tpms_pressure_rear_right_psi" + }, + "properties": [ + { + "id": "unit", + "value": "pressurepsi" + }, + { + "id": "displayName", + "value": "rear right" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 32, + "links": [], + "options": { + "legend": { + "calcs": ["logmin", "max"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n $__time(date),\r\n convert_tire_pressure(tpms_pressure_fl,'$pressure_unit') AS tpms_pressure_front_left_$pressure_unit,\r\n convert_tire_pressure(tpms_pressure_fr,'$pressure_unit') AS tpms_pressure_front_right_$pressure_unit,\r\n convert_tire_pressure(tpms_pressure_rl,'$pressure_unit') AS tpms_pressure_rear_left_$pressure_unit,\r\n convert_tire_pressure(tpms_pressure_rr,'$pressure_unit') AS tpms_pressure_rear_right_$pressure_unit\r\nFROM\r\n positions\r\nWHERE\r\n car_id = $car_id AND\r\n $__timeFilter(date) AND\r\n tpms_pressure_fl is not null\r\nORDER BY\r\n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["id"], + "type": "column" + } + ] + ], + "table": "pos", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Tire Pressure", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 5, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_m$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_ft$" + }, + "properties": [ + { + "id": "unit", + "value": "feet" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "elevation_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Elevation" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tROUND(convert_m(elevation, '$alternative_length_unit')) AS elevation_[[alternative_length_unit]]\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nORDER BY\n\tdate ASC", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Elevation", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 5, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "is_climate_on" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(210, 203, 203)", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "fan_status" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#96D98D", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_c$" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_f$" + }, + "properties": [ + { + "id": "unit", + "value": "fahrenheit" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "outside_temp_.*" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + }, + { + "id": "displayName", + "value": "Outside Temperature" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "inside_temp_.*" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2CC0C", + "mode": "fixed" + } + }, + { + "id": "displayName", + "value": "Inside Temperature" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "driver_temp_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Driver Temperature" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "passenger_temp_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Passenger Temperature" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "is_climate_on" + }, + "properties": [ + { + "id": "unit", + "value": "bool_on_off" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + }, + { + "id": "displayName", + "value": "Climate" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "fan_status" + }, + "properties": [ + { + "id": "displayName", + "value": "Fan status" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tconvert_celsius(outside_temp, '$temp_unit') AS outside_temp_$temp_unit,\n\tconvert_celsius(inside_temp, '$temp_unit') AS inside_temp_$temp_unit,\n\tconvert_celsius(driver_temp_setting, '$temp_unit') as driver_temp_$temp_unit,\n\tconvert_celsius(passenger_temp_setting, '$temp_unit') as passenger_temp_$temp_unit,\n is_climate_on::integer,\n\tfan_status\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nORDER BY\n\tdate ASC", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Temperatures", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 12, + "x": 12, + "y": 31 + }, + "id": 16, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT CONCAT_WS(' - ', round(convert_km(start_km::numeric, '$length_unit')), round(convert_km(end_km::numeric, '$length_unit'))) ||' $length_unit' as \"Odometer\"\nFROM drives d\nWHERE d.id = $drive_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 12, + "x": 0, + "y": 39 + }, + "id": 20, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "vertical", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "value_and_name" + }, + "targets": [ + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH height as (SELECT\n\televation-LAG(elevation,1) over ( order BY\n\tdate ASC ) as diff\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nORDER BY\n\tdate ASC\n\t)\n\t\n\nselect convert_m(sum(diff), '$alternative_length_unit') || ' $alternative_length_unit' as \"UP\" from height where diff > 0", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH height as (SELECT\n\televation-LAG(elevation,1) over ( order BY\n\tdate ASC ) as diff\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nORDER BY\n\tdate ASC\n\t)\n\t\n\t\nselect convert_m(sum(diff), '$alternative_length_unit') || ' $alternative_length_unit' as \"DOWN\" from height where diff < 0", + "refId": "B", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Elevation Summary", + "type": "stat" + } + ], + "refresh": false, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "NULL", + "value": "NULL" + }, + "hide": 2, + "name": "drive_id", + "options": [ + { + "selected": true, + "text": "NULL", + "value": "NULL" + } + ], + "query": "3217", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "1", + "value": "1" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "m", + "value": "m" + }, + "datasource": "TeslaMate", + "definition": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "alternative_length_unit", + "options": [], + "query": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "bar", + "value": "bar" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_pressure from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "pressure_unit", + "options": [], + "query": "select unit_of_pressure from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-12h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Drive Details", + "uid": "zm7wN6Zgz", + "version": 2, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate/reports/dutch-tax.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate/reports/dutch-tax.json new file mode 100644 index 00000000000..b242b5da143 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate/reports/dutch-tax.json @@ -0,0 +1,515 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:24", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1602596446244, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "scopedVars": { + "car_id": { + "selected": false, + "text": "1", + "value": "1" + } + }, + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "drive_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 75 + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "displayName", + "value": "ID" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_ts" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.width", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_date_ts" + }, + "properties": [ + { + "id": "displayName", + "value": "Start Time" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "start_(km|mi)" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "displayName", + "value": "Start Odometer" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "end_(km|mi)" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "displayName", + "value": "End Odometer" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_date_ts" + }, + "properties": [ + { + "id": "displayName", + "value": "End Time" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "(start|end)_address" + }, + "properties": [ + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "unit", + "value": "m" + }, + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "custom.width", + "value": 85 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + }, + { + "id": "displayName", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "custom.width", + "value": 90 + }, + { + "id": "displayName", + "value": "mi" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_address" + }, + "properties": [ + { + "id": "displayName", + "value": "Start Address" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_address" + }, + "properties": [ + { + "id": "displayName", + "value": "End Address" + } + ] + } + ] + }, + "gridPos": { + "h": 24, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "options": { + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Start Time" + } + ] + }, + "pluginVersion": "7.2.2", + "repeat": "car_id", + "scopedVars": { + "car_id": { + "selected": false, + "text": "1", + "value": "1" + } + }, + "targets": [ + { + "alias": "", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n drives.id as drive_id,\n round(extract(epoch FROM start_date)) * 1000 AS start_date_ts,\n round(extract(epoch FROM end_date)) * 1000 AS end_date_ts,\n start_km,\n end_km,\n CONCAT_WS(', ', CONCAT_WS(' ', start_address.road, start_address.house_number), start_address.city) AS start_address,\n CONCAT_WS(', ', CONCAT_WS(' ', end_address.road, end_address.house_number), end_address.city) AS end_address,\n duration_min,\n distance\n FROM drives\n LEFT JOIN addresses start_address ON start_address_id = start_address.id\n LEFT JOIN addresses end_address ON end_address_id = end_address.id\n LEFT JOIN cars car ON car.id = drives.car_id\n WHERE $__timeFilter(start_date) AND drives.car_id = $car_id\n ORDER BY drive_id DESC\n)\nSELECT\n drive_id,\n start_date_ts,\n convert_km(start_km::numeric, '$length_unit') as start_$length_unit,\n start_address,\n end_date_ts,\n convert_km(end_km::numeric, '$length_unit') as end_$length_unit,\n end_address,\n duration_min,\n convert_km(distance::numeric, '$length_unit') AS distance_$length_unit\nFROM data;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Drive", + "type": "table" + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "temperature unit", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "length unit", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "rated", + "value": "rated" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "value": null + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/y", + "to": "now/y" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Drives - Dutch tax", + "uid": "lBIoQIggk", + "version": 1 +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/locations.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/locations.json new file mode 100644 index 00000000000..05c61277df3 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/locations.json @@ -0,0 +1,1120 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642771806943, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 12, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select count(*) from addresses;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total addresses", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 7, + "x": 7, + "y": 0 + }, + "id": 20, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOUNT(DISTINCT city)\nFROM\n\taddresses;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Cities", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 14, + "y": 0 + }, + "id": 18, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOUNT(DISTINCT state)\nFROM\n\taddresses;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "States", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 19, + "y": 0 + }, + "id": 16, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOUNT(DISTINCT country)\nFROM\n\taddresses;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Countries", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "displayName": "$__cell_0", + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + }, + { + "color": "super-light-green", + "value": 50 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 3 + }, + "id": 10, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "showUnfilled": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tcity,\n\tcount(*) as \"# addresses\"\nFROM\n\taddresses\nWHERE\n\tcity IS NOT NULL\nGROUP BY\n\t1\nORDER BY\n\t2 DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Cities", + "type": "bargauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "displayName": "$__cell_0", + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-orange", + "value": null + }, + { + "color": "super-light-orange", + "value": 50 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 3 + }, + "id": 14, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "showUnfilled": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tstate,\n\tcount(*) as \"# addresses\"\nFROM\n\taddresses\nWHERE\n\tstate IS NOT NULL\nGROUP BY\n\t1\nORDER BY\n\t2 DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "States", + "type": "bargauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "displayMode": "auto", + "filterable": false + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-blue", + "value": null + }, + { + "color": "light-red", + "value": 50 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Date" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "City" + }, + "properties": [ + { + "id": "custom.width" + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 22, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n max(end_date) as \"Date\",\n count(*) as visited,\n COALESCE(g.name, array_to_string(((string_to_array(a.display_name, ', ', ''))[0:2]), ', ')) AS \"Address\",\n\tCOALESCE(city, neighbourhood) as \"City\"\nFROM drives t\nINNER JOIN addresses a ON end_address_id = a.id\nLEFT JOIN geofences g ON end_geofence_id = g.id\nWHERE a.display_name ilike '%$address_filter%' or g.name ilike '%$address_filter%'\nGROUP BY 3,4\nORDER BY visited DESC\nLIMIT 100", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Last visited", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "visited": true + }, + "indexByName": {}, + "renameByName": {} + } + } + ], + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "displayMode": "auto" + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "updated_at" + }, + "properties": [ + { + "id": "displayName", + "value": "Updated at" + }, + { + "id": "unit", + "value": "time: YYYY-MM-DD HH:mm:ss" + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "name" + }, + "properties": [ + { + "id": "displayName", + "value": "Name" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.path}" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "neighbourhood" + }, + "properties": [ + { + "id": "displayName", + "value": "Neighbourhood" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "city" + }, + "properties": [ + { + "id": "displayName", + "value": "City" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "state" + }, + "properties": [ + { + "id": "displayName", + "value": "State" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "country" + }, + "properties": [ + { + "id": "displayName", + "value": "Country" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "path" + }, + "properties": [ + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 18, + "x": 0, + "y": 22 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n CONCAT('new?lat=', latitude, '&lng=', longitude) as path,\n\tCOALESCE(name, CONCAT(road, ' ', house_number)) AS name,\n\tneighbourhood,\n\tcity,\n\tstate,\n\tcountry\nFROM addresses\nWHERE display_name ilike '%$address_filter%'\nORDER BY inserted_at DESC\nLIMIT 100;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Addresses", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "displayMode": "auto" + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "displayName", + "value": "Time" + }, + { + "id": "unit", + "value": "time: YYYY-MM-DD HH:mm:ss" + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "name" + }, + "properties": [ + { + "id": "displayName", + "value": "Name" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.id.numeric:raw}/edit" + } + ] + }, + { + "id": "custom.align" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "id" + }, + "properties": [ + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 18, + "y": 22 + }, + "id": 6, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT id, name \nFROM geofences \nORDER BY inserted_at DESC\nLIMIT 512;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Geo-fences", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + } + ], + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": ["All"], + "value": ["$__all"] + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 1, + "includeAll": true, + "label": "Car", + "multi": true, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "hide": 0, + "label": "Address", + "name": "address_filter", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": { + "hidden": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Locations", + "uid": "ZzhF-aRWz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/mileage.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/mileage.json new file mode 100644 index 00000000000..16b27614c75 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/mileage.json @@ -0,0 +1,317 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1656100778202, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_km$" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi$" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "mileage_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Mileage" + } + ] + } + ] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": ["min", "max"], + "displayMode": "table", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH o AS (SELECT\n start_date AS time,\n car_id,\n start_km AS \"odometer\"\nFROM drives\nUNION ALL\nSELECT\n end_date,\n car_id,\n end_km AS \"odometer\"\nFROM drives)\n\nSELECT\n time, \n convert_km(odometer::numeric, '$length_unit') as mileage_$length_unit\nFROM o\nWHERE\n\tcar_id = $car_id AND\n\t$__timeFilter(time)\norder by 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Mileage", + "type": "timeseries" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Mileage", + "uid": "NjtMTFggz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview-lfp.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview-lfp.json new file mode 100644 index 00000000000..2c5f42578b5 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview-lfp.json @@ -0,0 +1,1631 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:286", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "A high level overview of your car", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "iteration": 1656103268002, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 18, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "displayName": "", + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 10 + }, + { + "color": "semi-dark-green", + "value": 20 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 4, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "(SELECT battery_level, date\nFROM positions\nWHERE car_id = $car_id\nORDER BY date DESC\nLIMIT 1)\nUNION\nSELECT battery_level, date\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE $__timeFilter(date) AND p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "A", + "select": [ + [ + { + "params": ["battery_level"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [] + } + ], + "title": "Battery Level", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 260, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "volt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 10, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charging_process AS (\n SELECT id, end_date\n FROM charging_processes\n WHERE car_id = $car_id\n ORDER BY start_date DESC\n LIMIT 1\n)\nSELECT\n $__time(date),\n CASE WHEN charging_process.end_date IS NULL THEN charger_voltage\n ELSE 0\n END AS \"Charging Voltage [V]\"\nFROM charges, charging_process\nWHERE charging_process.id = charging_process_id\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Voltage", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 170, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "kwatt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 11, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charging_process AS (\n SELECT id, end_date\n FROM charging_processes\n WHERE car_id = $car_id\n ORDER BY start_date DESC\n LIMIT 1\n)\nSELECT\n $__time(date),\n CASE WHEN charging_process.end_date IS NULL THEN charger_power\n ELSE 0\n END AS \"Power [kW]\"\nFROM charges, charging_process\nWHERE charging_process.id = charging_process_id\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging kW", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 15, + "x": 9, + "y": 1 + }, + "id": 13, + "links": [ + { + "targetBlank": true, + "title": "Drive details", + "url": "/d/zm7wN6Zgz/drive-details?orgId=1" + } + ], + "options": { + "legend": { + "calcs": ["max", "min"], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), battery_level AS \"SOC\"\nFROM (\n\tSELECT battery_level, date\n\tFROM positions\n\tWHERE car_id = $car_id AND $__timeFilter(date)\n\tUNION ALL\n\tSELECT battery_level, date\n\tFROM charges c \n JOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE $__timeFilter(date) AND p.car_id = $car_id) AS data\nORDER BY date ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charge Level", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "range_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 5 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), range as \"range_$length_unit\"\nFROM (\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM positions\n\tWHERE car_id = $car_id AND [[preferred_range]]_battery_range_km IS NOT NULL\n ORDER BY date DESC\n\tLIMIT 1)\n\tUNION ALL\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM charges c\n\tJOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE p.car_id = $car_id\n\tORDER BY date DESC\n\tLIMIT 1)\n) AS data\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Range", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 5 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n sum(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0) * car.efficiency * 1000) / \n convert_km(sum(distance)::numeric, '$length_unit') as \"consumption_$length_unit\"\nFROM drives\nJOIN cars car ON car.id = car_id\nWHERE $__timeFilter(start_date) AND car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Net", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 5 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM charging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id AND\n\t $__timeFilter(start_date)\n\tORDER BY start_date\n),\n\nrange_loss_between_charges AS (\n SELECT sum(range_loss) AS range_loss\n FROM d\n WHERE distance >= 0 AND range_loss >= 0\n GROUP BY car_id\n),\n\ncharge_dates AS (\n\tSELECT\n\t\tmin(start_date) as first_charge,\n\t\tmax(end_date) as last_charge\n\tFROM\n\t\tcharging_processes\n\tWHERE\n\t\tend_date IS NOT NULL\n\t\tAND car_id = $car_id\n\t\tAND $__timeFilter(start_date)\n),\n\nrange_loss_before_first_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND ((select first_charge from charge_dates) is null OR date < (select first_charge from charge_dates))\n),\n\nrange_loss_after_last_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND date > (select last_charge from charge_dates)\t\n),\n\ntotal_range_loss AS (\n SELECT sum(range_loss) as range_loss\n FROM (\n SELECT range_loss FROM range_loss_between_charges\n UNION ALL\n SELECT range_loss FROM range_loss_before_first_charge\n UNION ALL\n SELECT range_loss FROM range_loss_after_last_charge\n ) r\n),\n\ndistance AS (\n SELECT max(odometer) - min(odometer) as distance\n FROM positions\n WHERE car_id = $car_id AND $__timeFilter(date)\n)\n\nSELECT \n NULLIF(range_loss, 0) * (c.efficiency * 1000) / convert_km(NULLIF(distance::numeric, 0), '$length_unit') as \"consumption_$length_unit\"\nFROM total_range_loss, distance\nLEFT JOIN cars c ON c.id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Gross", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "version" + }, + "properties": [ + { + "id": "unit", + "value": "string" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 8 + }, + "id": 2, + "links": [ + { + "targetBlank": true, + "title": "Updates", + "url": "/d/IiC07mgWz/updates?orgId=1" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^version$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select split_part(version, ' ', 1) as version \nfrom updates \nwhere car_id = $car_id \norder by start_date desc \nlimit 1", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Firmware", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "odometer_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 8 + }, + "id": 6, + "links": [ + { + "targetBlank": true, + "title": "Mileage", + "url": "/d/NjtMTFggz/mileage?orgId=1" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(date), convert_km(odometer::numeric, '$length_unit') as \"odometer_$length_unit\"\nfrom positions \nwhere car_id = $car_id \norder by date desc \nlimit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Odometer", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Charging Voltage [V]" + }, + "properties": [ + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 250 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_power" + }, + "properties": [ + { + "id": "displayName", + "value": "Power" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "battery_heater" + }, + "properties": [ + { + "id": "displayName", + "value": "Battery heater" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + }, + { + "id": "unit", + "value": "bool_on_off" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_actual_current" + }, + "properties": [ + { + "id": "displayName", + "value": "Current" + }, + { + "id": "unit", + "value": "amp" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Energy added" + }, + { + "id": "unit", + "value": "kwatth" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 15, + "x": 9, + "y": 8 + }, + "id": 15, + "links": [ + { + "targetBlank": true, + "title": "Charging Details", + "url": "/d/BHhxFeZRz/charge-details?orgId=1" + } + ], + "options": { + "legend": { + "calcs": ["max", "min"], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n charger_power,\n (case when battery_heater_on then 1 else 0 end) as battery_heater,\n charger_actual_current,\n c.charge_energy_added\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date) and\n p.car_id = $car_id\nORDER BY\n date ASC", + "refId": "B", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n charger_voltage as \"Charging Voltage [V]\"\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date) and\n p.car_id = $car_id\nORDER BY\n date ASC", + "refId": "C", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Details", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 11 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tconvert_celsius(driver_temp_setting, '$temp_unit') as \"Driver Temperature [°$temp_unit]\"\nFROM positions\nWHERE driver_temp_setting IS NOT NULL AND car_id = $car_id AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Driver Temp", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 11 + }, + "id": 8, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH last_position AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM positions\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\n\tORDER BY date DESC\n\tLIMIT 1\n),\nlast_charge AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM charges\n\tJOIN charging_processes ON charges.charging_process_id = charging_processes.id\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\n\tORDER BY date DESC\n\tLIMIT 1\n)\nSELECT * FROM last_position\nUNION ALL\nSELECT * FROM last_charge\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Outside Temp", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 11 + }, + "id": 9, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n date,\n convert_celsius(inside_temp, '$temp_unit') AS \"Inside Temperature [°$temp_unit]\"\nFROM positions\nWHERE\n car_id = $car_id\n and inside_temp is not null AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\norder by date desc\nlimit 1 ", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Inside Temp", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 100, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "color": "#6ED0E0", + "index": 0, + "text": "online" + }, + "1": { + "color": "#8F3BB8", + "index": 1, + "text": "driving" + }, + "2": { + "color": "#F2CC0C", + "index": 2, + "text": "charging" + }, + "3": { + "color": "#FFB357", + "index": 3, + "text": "offline" + }, + "4": { + "color": "#56A64B", + "index": 4, + "text": "asleep" + }, + "5": { + "color": "#6ED0E0", + "index": 5, + "text": "online" + }, + "6": { + "color": "#E02F44", + "index": 6, + "text": "updating" + }, + "null": { + "index": 7, + "text": "N/A" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 20, + "links": [ + { + "title": "States", + "url": "/d/xo4BNRkZz/states" + } + ], + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH states AS (\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [2, 0]) AS state\n FROM charging_processes\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [1, 0]) AS state\n FROM drives\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n start_date AS date,\n CASE\n WHEN state = 'offline' THEN 3\n WHEN state = 'asleep' THEN 4\n WHEN state = 'online' THEN 5\n END AS state\n FROM states\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [6, 0]) AS state\n FROM updates\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n)\nSELECT date AS \"time\", state\nFROM states\nWHERE \n date IS NOT NULL AND\n ($__timeFrom() :: timestamp - interval '30 day') < date AND \n date < ($__timeTo() :: timestamp + interval '30 day') \nORDER BY date ASC, state ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "geofences", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "States", + "type": "state-timeline" + } + ], + "refresh": "30s", + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Overview - LFP", + "uid": "EVzVGnwSq", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview.json new file mode 100644 index 00000000000..0848c5211d5 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/overview.json @@ -0,0 +1,1640 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:286", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "A high level overview of your car", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "iteration": 1656103268002, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 18, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "displayName": "", + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 10 + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-yellow", + "value": 81 + }, + { + "color": "light-red", + "value": 91 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 4, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "(SELECT battery_level, date\nFROM positions\nWHERE car_id = $car_id\nORDER BY date DESC\nLIMIT 1)\nUNION\nSELECT battery_level, date\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE $__timeFilter(date) AND p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "A", + "select": [ + [ + { + "params": ["battery_level"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [] + } + ], + "title": "Battery Level", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 260, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "volt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 10, + "links": [], + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charging_process AS (\n SELECT id, end_date\n FROM charging_processes\n WHERE car_id = $car_id\n ORDER BY start_date DESC\n LIMIT 1\n)\nSELECT\n $__time(date),\n CASE WHEN charging_process.end_date IS NULL THEN charger_voltage\n ELSE 0\n END AS \"Charging Voltage [V]\"\nFROM charges, charging_process\nWHERE charging_process.id = charging_process_id\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Voltage", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 250, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "kwatt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 11, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charging_process AS (\n SELECT id, end_date\n FROM charging_processes\n WHERE car_id = $car_id\n ORDER BY start_date DESC\n LIMIT 1\n)\nSELECT\n $__time(date),\n CASE WHEN charging_process.end_date IS NULL THEN charger_power\n ELSE 0\n END AS \"Power [kW]\"\nFROM charges, charging_process\nWHERE charging_process.id = charging_process_id\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging kW", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 15, + "x": 9, + "y": 1 + }, + "id": 13, + "links": [ + { + "targetBlank": true, + "title": "Charge Level", + "url": "/d/WopVO_mgz/charge-level?${__url_time_range}" + } + ], + "options": { + "legend": { + "calcs": ["max", "min"], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), battery_level AS \"SOC\"\nFROM (\n\tSELECT battery_level, date\n\tFROM positions\n\tWHERE car_id = $car_id AND $__timeFilter(date)\n\tUNION ALL\n\tSELECT battery_level, date\n\tFROM charges c \n JOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE $__timeFilter(date) AND p.car_id = $car_id) AS data\nORDER BY date ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charge Level", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "range_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 5 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), range as \"range_$length_unit\"\nFROM (\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM positions\n\tWHERE car_id = $car_id AND [[preferred_range]]_battery_range_km IS NOT NULL\n ORDER BY date DESC\n\tLIMIT 1)\n\tUNION ALL\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM charges c\n\tJOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE p.car_id = $car_id\n\tORDER BY date DESC\n\tLIMIT 1)\n) AS data\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Range", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 5 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n sum(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0) * car.efficiency * 1000) / \n convert_km(sum(distance)::numeric, '$length_unit') as \"consumption_$length_unit\"\nFROM drives\nJOIN cars car ON car.id = car_id\nWHERE $__timeFilter(start_date) AND car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Net", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 5 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM charging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id AND\n\t $__timeFilter(start_date)\n\tORDER BY start_date\n),\n\nrange_loss_between_charges AS (\n SELECT sum(range_loss) AS range_loss\n FROM d\n WHERE distance >= 0 AND range_loss >= 0\n GROUP BY car_id\n),\n\ncharge_dates AS (\n\tSELECT\n\t\tmin(start_date) as first_charge,\n\t\tmax(end_date) as last_charge\n\tFROM\n\t\tcharging_processes\n\tWHERE\n\t\tend_date IS NOT NULL\n\t\tAND car_id = $car_id\n\t\tAND $__timeFilter(start_date)\n),\n\nrange_loss_before_first_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND ((select first_charge from charge_dates) is null OR date < (select first_charge from charge_dates))\n),\n\nrange_loss_after_last_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND date > (select last_charge from charge_dates)\t\n),\n\ntotal_range_loss AS (\n SELECT sum(range_loss) as range_loss\n FROM (\n SELECT range_loss FROM range_loss_between_charges\n UNION ALL\n SELECT range_loss FROM range_loss_before_first_charge\n UNION ALL\n SELECT range_loss FROM range_loss_after_last_charge\n ) r\n),\n\ndistance AS (\n SELECT max(odometer) - min(odometer) as distance\n FROM positions\n WHERE car_id = $car_id AND $__timeFilter(date)\n)\n\nSELECT \n NULLIF(range_loss, 0) * (c.efficiency * 1000) / convert_km(NULLIF(distance::numeric, 0), '$length_unit') as \"consumption_$length_unit\"\nFROM total_range_loss, distance\nLEFT JOIN cars c ON c.id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Gross", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "version" + }, + "properties": [ + { + "id": "unit", + "value": "string" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 8 + }, + "id": 2, + "links": [ + { + "targetBlank": true, + "title": "Updates", + "url": "/d/IiC07mgWz/updates" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^version$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select split_part(version, ' ', 1) as version \nfrom updates \nwhere car_id = $car_id \norder by start_date desc \nlimit 1", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Firmware", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "odometer_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 8 + }, + "id": 6, + "links": [ + { + "targetBlank": true, + "title": "Mileage", + "url": "/d/NjtMTFggz/mileage" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(date), convert_km(odometer::numeric, '$length_unit') as \"odometer_$length_unit\"\nfrom positions \nwhere car_id = $car_id \norder by date desc \nlimit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Odometer", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Charging Voltage [V]" + }, + "properties": [ + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 250 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_power" + }, + "properties": [ + { + "id": "displayName", + "value": "Power" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "battery_heater" + }, + "properties": [ + { + "id": "displayName", + "value": "Battery heater" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + }, + { + "id": "unit", + "value": "bool_on_off" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charger_actual_current" + }, + "properties": [ + { + "id": "displayName", + "value": "Current" + }, + { + "id": "unit", + "value": "amp" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Energy added" + }, + { + "id": "unit", + "value": "kwatth" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 15, + "x": 9, + "y": 8 + }, + "id": 15, + "links": [ + { + "targetBlank": true, + "title": "Charging Stats", + "url": "/d/-pkIkhmRz/charging-stats?${__url_time_range}" + } + ], + "options": { + "legend": { + "calcs": ["max", "min"], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n charger_power,\n (case when battery_heater_on then 1 else 0 end) as battery_heater,\n charger_actual_current,\n c.charge_energy_added\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date) and\n p.car_id = $car_id\nORDER BY\n date ASC", + "refId": "B", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n charger_voltage as \"Charging Voltage [V]\"\nFROM\n charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date) and\n p.car_id = $car_id\nORDER BY\n date ASC", + "refId": "C", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Details", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 11 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tconvert_celsius(driver_temp_setting, '$temp_unit') as \"Driver Temperature [°$temp_unit]\"\nFROM positions\nWHERE driver_temp_setting IS NOT NULL AND car_id = $car_id AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Driver Temp", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 11 + }, + "id": 8, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH last_position AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM positions\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\n\tORDER BY date DESC\n\tLIMIT 1\n),\nlast_charge AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM charges\n\tJOIN charging_processes ON charges.charging_process_id = charging_processes.id\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\n\tORDER BY date DESC\n\tLIMIT 1\n)\nSELECT * FROM last_position\nUNION ALL\nSELECT * FROM last_charge\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Outside Temp", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 11 + }, + "id": 9, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n date,\n convert_celsius(inside_temp, '$temp_unit') AS \"Inside Temperature [°$temp_unit]\"\nFROM positions\nWHERE\n car_id = $car_id\n and inside_temp is not null AND date AT TIME ZONE 'Etc/UTC' >= (NOW() - interval '60m')\norder by date desc\nlimit 1 ", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Inside Temp", + "type": "gauge" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 100, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "color": "#6ED0E0", + "index": 0, + "text": "online" + }, + "1": { + "color": "#8F3BB8", + "index": 1, + "text": "driving" + }, + "2": { + "color": "#F2CC0C", + "index": 2, + "text": "charging" + }, + "3": { + "color": "#FFB357", + "index": 3, + "text": "offline" + }, + "4": { + "color": "#56A64B", + "index": 4, + "text": "asleep" + }, + "5": { + "color": "#6ED0E0", + "index": 5, + "text": "online" + }, + "6": { + "color": "#E02F44", + "index": 6, + "text": "updating" + }, + "null": { + "index": 7, + "text": "N/A" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 20, + "links": [ + { + "targetBlank": true, + "title": "States", + "url": "/d/xo4BNRkZz/states?orgId=1&${__url_time_range}" + } + ], + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH states AS (\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [2, 0]) AS state\n FROM charging_processes\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [1, 0]) AS state\n FROM drives\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n start_date AS date,\n CASE\n WHEN state = 'offline' THEN 3\n WHEN state = 'asleep' THEN 4\n WHEN state = 'online' THEN 5\n END AS state\n FROM states\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [6, 0]) AS state\n FROM updates\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n)\nSELECT date AS \"time\", state\nFROM states\nWHERE \n date IS NOT NULL AND\n ($__timeFrom() :: timestamp - interval '30 day') < date AND \n date < ($__timeTo() :: timestamp + interval '30 day') \nORDER BY date ASC, state ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "geofences", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "States", + "type": "state-timeline" + } + ], + "refresh": "30s", + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Overview", + "uid": "kOuP_Fggz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/projected-range.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/projected-range.json new file mode 100644 index 00000000000..e2032ed2dd9 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/projected-range.json @@ -0,0 +1,772 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "TeslaMate", + "enable": false, + "hide": false, + "iconColor": "rgba(255, 96, 96, 1)", + "limit": 100, + "name": "Charged", + "rawQuery": "SELECT\n$__time(start_date),\nend_date as timeend,\nconcat('Charged: ',round(cast(charge_energy_added as numeric),2),' kWh') AS text\nFROM charging_processes\nWHERE\n$__timeFilter(start_date) AND duration_min > 5\nORDER BY start_date DESC", + "showIn": 0, + "tags": [], + "type": "tags" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "targets": [ + { + "datasource": "TeslaMate", + "refId": "A" + } + ], + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Projected Range", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 200, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/Mileage.*/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.axisLabel", + "value": "Mileage" + }, + { + "id": "min" + } + ] + } + ] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": ["mean", "max", "min"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.2.1", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date, [[interval]]) AS time,\n\tconvert_km((sum([[preferred_range]]_battery_range_km) / nullif(sum(coalesce(usable_battery_level,battery_level)),0) * 100)::numeric, '$length_unit') AS \"Projected [[preferred_range]] range [$length_unit]\"\nFROM\n\t(\n select battery_level, usable_battery_level, date,\n rated_battery_range_km, ideal_battery_range_km, outside_temp\n from positions\n where\n car_id = $car_id and $__timeFilter(date) and ideal_battery_range_km is not null\n union all\n select battery_level, coalesce(usable_battery_level,battery_level) as usable_battery_level, date,\n rated_battery_range_km, ideal_battery_range_km, outside_temp\n from charges c\n join\n charging_processes p ON p.id = c.charging_process_id \n where\n $__timeFilter(date) and p.car_id = $car_id\n ) as data\n\nGROUP BY\n\t1\nhaving convert_km((sum([[preferred_range]]_battery_range_km) / nullif(sum(coalesce(usable_battery_level,battery_level)),0) * 100)::numeric, '$length_unit') is not null\nORDER BY\n\t1,2 DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date,[[interval]]) AS time,\n\tconvert_km(avg(odometer)::numeric, '$length_unit') AS \"Mileage [$length_unit]\"\nFROM\n\tpositions\nWHERE\n\t$__timeFilter(date) and\n\tcar_id = $car_id and ideal_battery_range_km is not null\nGROUP BY\n\t1\nORDER BY\n\t1,2 DESC;", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Projected Range - Mileage", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Projected Range", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 200, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/Battery.*/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "max", + "value": 100 + }, + { + "id": "custom.axisLabel", + "value": "Battery Level" + } + ] + } + ] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 6, + "links": [], + "options": { + "legend": { + "calcs": ["mean", "max", "min"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.2.1", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date,[[interval]]) AS time,\n\tconvert_km(sum([[preferred_range]]_battery_range_km) / sum(coalesce(usable_battery_level,battery_level)) * 100, '$length_unit') AS \"Projected Range (using usable_battery_level) [$length_unit]\",\n\tconvert_km(sum([[preferred_range]]_battery_range_km) / sum(battery_level) * 100, '$length_unit') AS \"Projected Range (using battery_level)[$length_unit]\"\nFROM\n\t(\n select battery_level, usable_battery_level, date,\n rated_battery_range_km, ideal_battery_range_km, outside_temp\n from positions\n where\n car_id = $car_id and $__timeFilter(date) and ideal_battery_range_km is not null\n union all\n select battery_level, coalesce(usable_battery_level,battery_level) as usable_battery_level, date,\n rated_battery_range_km, ideal_battery_range_km, outside_temp\n from charges c\n join\n charging_processes p ON p.id = c.charging_process_id \n where\n $__timeFilter(date) and p.car_id = $car_id\n ) as data\n\nGROUP BY\n\t1\nORDER BY\n\t1,2 DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n\t$__timeGroup(date,[[interval]]) AS time,\n avg(battery_level) AS \"Battery Level [%]\", avg(coalesce(usable_battery_level, battery_level)) as \"Usable Battery Level [%]\"\nfrom\n (SELECT\n battery_level, usable_battery_level\n , date\n FROM\n positions\n WHERE\n car_id = $car_id AND\n $__timeFilter(date) and ideal_battery_range_km is not null\n UNION ALL\n select\n battery_level, null as usable_battery_level\n , date\n from charges c\njoin\n charging_processes p ON p.id = c.charging_process_id \nWHERE\n $__timeFilter(date) and\n p.car_id = $car_id) as data\n\nGROUP BY\n 1\nORDER BY\n 1 ASC", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Projected Range - Battery Level", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Projected Range", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "links": [], + "mappings": [], + "min": 200, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/Temp.*/" + }, + "properties": [ + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.axisLabel", + "value": "Temp" + }, + { + "id": "min" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*using usable_battery_level.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#56A64B", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*using battery_level.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C8F2C2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 5, + "links": [], + "options": { + "legend": { + "calcs": ["mean", "max", "min"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.2.1", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date,[[interval]]) AS time,\n\tconvert_km(sum([[preferred_range]]_battery_range_km) / sum(coalesce(usable_battery_level,battery_level)) * 100, '$length_unit') AS \"Projected Range (using usable_battery_level) [$length_unit]\",\n\tconvert_km(sum([[preferred_range]]_battery_range_km) / sum(battery_level) * 100, '$length_unit') AS \"Projected Range (using battery_level) [$length_unit]\"\nFROM\n\t(\n select battery_level, usable_battery_level, date,\n rated_battery_range_km, ideal_battery_range_km, outside_temp\n from positions\n where\n car_id = $car_id and $__timeFilter(date) and ideal_battery_range_km is not null\n union all\n select battery_level, coalesce(usable_battery_level,battery_level) as usable_battery_level, date,\n rated_battery_range_km, ideal_battery_range_km, outside_temp\n from charges c\n join\n charging_processes p ON p.id = c.charging_process_id \n where\n $__timeFilter(date) and p.car_id = $car_id\n ) as data\n\nGROUP BY\n\t1\nORDER BY\n\t1,2 DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "", + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date,[[interval]]) AS time,\n\tavg(convert_celsius(outside_temp, '$temp_unit')) as \"Outdoor Temperature [°$temp_unit]\"\n\nFROM\n\tpositions\nWHERE\n\t$__timeFilter(date) and\n\tcar_id = $car_id and ideal_battery_range_km is not null\nGROUP BY\n\t1\nORDER BY\n\t1,2 DESC", + "refId": "B", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Projected Range - Outdoor Temp", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 36, + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": {}, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "6h", + "value": "6h" + }, + "hide": 1, + "label": "Time Resolution", + "name": "interval", + "options": [ + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "15m", + "value": "15m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "3h", + "value": "3h" + }, + { + "selected": true, + "text": "6h", + "value": "6h" + } + ], + "query": "5m,15m,30m,1h,3h,6h", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Projected Range", + "uid": "riqUfXgRz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/states.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/states.json new file mode 100644 index 00000000000..95e38b0635c --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/states.json @@ -0,0 +1,508 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:427", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642780620514, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 16, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "description": "Only distinguishes between online, offline and asleep.", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "dateTimeAsLocal" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^time$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(start_date), state from states where car_id = $car_id order by start_date desc limit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Last state change", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "Only distinguishes between online, offline and asleep.", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 6, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^state$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(start_date), state from states where car_id = $car_id order by start_date desc limit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current State", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "based on any data ever recorded.", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 8, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select 1 - sum(duration_min) / (EXTRACT(EPOCH FROM (max(end_date) - min(start_date))) / 60), 1 as time from drives where car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "parked (%)", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 100, + "lineWidth": 0 + }, + "mappings": [ + { + "options": { + "0": { + "color": "#6ED0E0", + "index": 0, + "text": "online" + }, + "1": { + "color": "#8F3BB8", + "index": 1, + "text": "driving" + }, + "2": { + "color": "#F2CC0C", + "index": 2, + "text": "charging" + }, + "3": { + "color": "#FFB357", + "index": 3, + "text": "offline" + }, + "4": { + "color": "#56A64B", + "index": 4, + "text": "asleep" + }, + "5": { + "color": "#6ED0E0", + "index": 5, + "text": "online" + }, + "6": { + "color": "#E02F44", + "index": 6, + "text": "updating" + }, + "null": { + "index": 7, + "text": "N/A" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 14, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH states AS (\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [2, 0]) AS state\n FROM charging_processes\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [1, 0]) AS state\n FROM drives\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n start_date AS date,\n CASE\n WHEN state = 'offline' THEN 3\n WHEN state = 'asleep' THEN 4\n WHEN state = 'online' THEN 5\n END AS state\n FROM states\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [6, 0]) AS state\n FROM updates\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n)\nSELECT date AS \"time\", state\nFROM states\nWHERE \n date IS NOT NULL AND\n ($__timeFrom() :: timestamp - interval '30 day') < date AND \n date < ($__timeTo() :: timestamp + interval '30 day') \nORDER BY date ASC, state ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "States", + "type": "state-timeline" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "States", + "uid": "xo4BNRkZz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/statistics.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/statistics.json new file mode 100644 index 00000000000..d3dd8f2d54e --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/statistics.json @@ -0,0 +1,971 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642773094879, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "displayMode": "auto", + "filterable": false, + "width": 120 + }, + "mappings": [], + "noValue": "--", + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 50 + }, + { + "color": "green", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time driven" + }, + "properties": [ + { + "id": "unit", + "value": "clocks" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Period" + }, + "properties": [ + { + "id": "custom.width", + "value": 195 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Trip", + "url": "d/FkUpJpQZk/trip?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Efficiency" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "thresholds", + "value": { + "mode": "percentage", + "steps": [ + { + "color": "super-light-orange", + "value": null + }, + { + "color": "light-orange", + "value": 65 + }, + { + "color": "light-green", + "value": 99 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Energy charged" + }, + "properties": [ + { + "id": "decimals", + "value": 1 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Charging stats", + "url": "d/-pkIkhmRz/charging-stats?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + }, + { + "id": "unit", + "value": "kwatth" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg charged" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Costs" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "# charges" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Charges", + "url": "d/TSmNYvRRk/charges?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "# drives" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Drives", + "url": "d/Y8upc6ZRk/drives?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_km/" + }, + "properties": [ + { + "id": "unit", + "value": "km" + }, + { + "id": "displayName", + "value": "Distance" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/avg_outside_temp_c/" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + }, + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + }, + { + "color": "super-light-green", + "value": 10 + }, + { + "color": "super-light-red", + "value": 20 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "unit", + "value": "mi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_net_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (drives)" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_charged_net_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (charges)" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.* at/" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_net_km/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (drives)" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_charged_net_km/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (charges)" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/avg_outside_temp_f/" + }, + "properties": [ + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "unit", + "value": "fahrenheit" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "date_from" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "date_to" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg cost per kWh" + }, + "properties": [ + { + "id": "custom.width", + "value": 137 + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "maxPerRow": 2, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "frameIndex": 1, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Starting at" + } + ] + }, + "pluginVersion": "8.3.4", + "repeatDirection": "h", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\nSELECT\n duration_min > 1 AND\n distance > 1 AND\n ( \n start_position.usable_battery_level IS NULL OR\n (end_position.battery_level - end_position.usable_battery_level) = 0 \n ) AS is_sufficiently_precise,\n NULLIF(GREATEST(start_ideal_range_km - end_ideal_range_km, 0), 0) AS range_diff,\n -- with Postgres 12:\n -- date_trunc('$period', start_date::TIMESTAMP WITHOUT TIME ZONE, '$timezone') as local_period,\n date_trunc('$period', (start_date::TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE '$timezone') as local_period,\n drives.*\nFROM drives\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('$period', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('$period', local_period + ('1 ' || '$period')::INTERVAL))*1000 AS date_to,\n CASE '$period'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n sum(duration_min)*60 AS sum_duration_h, \n convert_km(max(end_km)::integer - min(start_km)::integer, '$length_unit') AS sum_distance_$length_unit,\n convert_celsius(avg(outside_temp_avg), '$temp_unit') AS avg_outside_temp_$temp_unit,\n count(*) AS cnt,\n sum(distance)/sum(range_diff) AS efficiency\nFROM data WHERE\n car_id = $car_id AND\n $__timeFilter(start_date)\nGROUP BY date\nORDER BY date", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n charging_processes.*,\n -- with Postgres 12:\n -- date_trunc('$period', start_date::TIMESTAMP WITHOUT TIME ZONE, '$timezone') as local_period\n date_trunc('$period', (start_date::TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE '$timezone') as local_period\n FROM charging_processes)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('$period', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('$period', local_period + ('1 ' || '$period')::INTERVAL))*1000 AS date_to,\n CASE '$period'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n sum(greatest(charge_energy_added,charge_energy_used)) AS sum_consumption_kwh,\n sum(greatest(charge_energy_added,charge_energy_used)) / count(*) AS avg_consumption_kwh,\n sum(cost) AS cost_charges,\n count(*) AS cnt_charges\nFROM data WHERE\n car_id = $car_id AND\n $__timeFilter(start_date) AND\n (charge_energy_added IS NULL OR charge_energy_added > 0.1)\nGROUP BY date\nORDER BY date", + "refId": "B", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n drives.*,\n -- with Postgres 12:\n -- date_trunc('$period', start_date::TIMESTAMP WITHOUT TIME ZONE, '$timezone') as local_period\n date_trunc('$period', (start_date::TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE '$timezone') as local_period\n FROM drives)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('$period', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('$period', local_period + ('1 ' || '$period')::INTERVAL))*1000 AS date_to,\n CASE '$period'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n sum(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0) * car.efficiency * 1000) / \n convert_km(sum(distance)::numeric, '$length_unit') as efficiency_net_$length_unit\nFROM data\nJOIN cars car ON car.id = car_id\nWHERE\n car_id = $car_id AND\n $__timeFilter(start_date)\nGROUP BY date\nORDER BY date", + "refId": "C", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "per ${period}", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "seriesToColumns", + "options": { + "byField": "date" + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_km_temp", + "binary": { + "left": "sum_consumption_kwh", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_km" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": false + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_km", + "binary": { + "left": "efficiency_charged_net_km_temp", + "operator": "*", + "reducer": "sum", + "right": "1000" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_mi_temp", + "binary": { + "left": "sum_consumption_kwh", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_mi" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": false + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_mi", + "binary": { + "left": "efficiency_charged_net_mi_temp", + "operator": "*", + "reducer": "sum", + "right": "1000" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "avg_cost_kwh", + "binary": { + "left": "cost_charges", + "operator": "/", + "reducer": "sum", + "right": "sum_consumption_kwh" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "avg_cost_km", + "binary": { + "left": "cost_charges", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_km" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "avg_cost_mi", + "binary": { + "left": "cost_charges", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_mi" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "date": false, + "date_from": false, + "date_to": false, + "efficiency_charged_net_km_temp": true, + "efficiency_charged_net_mi_temp": true, + "timezone": true + }, + "indexByName": { + "avg_consumption_kwh": 9, + "avg_cost_km": 19, + "avg_cost_mi": 20, + "avg_cost_kwh": 11, + "avg_outside_temp_c": 5, + "cnt": 6, + "cnt_charges": 11, + "cost_charges": 10, + "date": 1, + "date_from": 17, + "date_to": 18, + "display": 0, + "efficiency": 7, + "efficiency_charged_net_km": 15, + "efficiency_charged_net_mi": 16, + "efficiency_net_km": 13, + "efficiency_net_mi": 14, + "sum_consumption_kwh": 8, + "sum_distance_km": 3, + "sum_distance_mi": 4, + "sum_duration_h": 2 + }, + "renameByName": { + "avg_consumption_kwh": "Avg charged", + "avg_cost_km": "Avg cost per km", + "avg_cost_mi": "Avg cost per mi", + "avg_cost_kwh": "Avg cost per kWh", + "avg_outside_temp_c": "", + "cnt": "# drives", + "cnt_charges": "# charges", + "cost_charges": "Costs", + "date": "Starting at", + "date_from": "", + "date_to": "", + "display": "Period", + "efficiency": "Efficiency", + "efficiency_net_km": "", + "sum_consumption_kwh": "Energy charged", + "sum_distance_km": "", + "sum_duration_h": "Time driven" + } + } + } + ], + "type": "table" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "length unit", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "temperature unit", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": true, + "text": "month", + "value": "month" + }, + "hide": 0, + "includeAll": false, + "label": "Period", + "multi": false, + "name": "period", + "options": [ + { + "selected": false, + "text": "day", + "value": "day" + }, + { + "selected": false, + "text": "week", + "value": "week" + }, + { + "selected": true, + "text": "month", + "value": "month" + }, + { + "selected": false, + "text": "year", + "value": "year" + } + ], + "query": "day,week,month,year", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "Europe/Berlin", + "value": "Europe/Berlin" + }, + "datasource": "TeslaMate", + "definition": "select current_setting('TIMEZONE'), name from pg_timezone_names where abbrev ~ '^[a-zA-Z]{3,4}$' and name not like 'posix%' order by 2;", + "hide": 0, + "includeAll": false, + "label": "Time zone", + "multi": false, + "name": "timezone", + "options": [], + "query": "select current_setting('TIMEZONE'), name from pg_timezone_names where abbrev ~ '^[a-zA-Z]{3,4}$' and name not like 'posix%' order by 2;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-10y", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "browser", + "title": "Statistics", + "uid": "1EZnXszMk", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/timeline.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/timeline.json new file mode 100644 index 00000000000..7c19e598087 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/timeline.json @@ -0,0 +1,824 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642862616523, + "links": [ + { + "asDropdown": false, + "icon": "dashboard", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["tesla"], + "targetBlank": false, + "title": "Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Start" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.width", + "value": 180 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "", + "url": "d/FkUpJpQZk/trip?from=${__data.fields.start_date_ts}&to=${__data.fields.end_date_ts}&var-car_id=$car_id" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SoC" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SoC Diff" + }, + "properties": [ + { + "id": "custom.width", + "value": 70 + }, + { + "id": "unit", + "value": "percent" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_path" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_path" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Action" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + }, + { + "id": "custom.filterable", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "kWh" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "End" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.width", + "value": 152 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Duration" + }, + "properties": [ + { + "id": "unit", + "value": "m" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Start Address" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.start_path:raw}" + } + ] + }, + { + "id": "custom.filterable", + "value": true + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "End Address" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.end_path:raw}" + } + ] + }, + { + "id": "custom.filterable", + "value": true + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_date_ts" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_date_ts" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_km" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_km/" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_c/" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_f/" + }, + "properties": [ + { + "id": "unit", + "value": "fahrenheit" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/odometer_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Odometer" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/distance_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "custom.width", + "value": 100 + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/range_diff_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Range Diff" + }, + { + "id": "custom.width", + "value": 100 + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/outside_temp_avg_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "custom.width", + "value": 100 + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/end_range_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Range" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Range" + }, + "properties": [ + { + "id": "custom.width", + "value": 118 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Action" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Slot details", + "url": "${__data.fields.slotlink:raw}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "slotlink" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 22, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Start" + } + ] + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n start_date AS \"Start\",\r\n end_date AS \"End\",\r\n ROUND(EXTRACT(EPOCH FROM start_date))*1000 AS start_date_ts,\r\n ROUND(EXTRACT(EPOCH FROM end_date))*1000 AS end_date_ts,\r\n '🚗 Driving' AS \"Action\",\r\n drives.duration_min AS \"Duration\",\r\n CASE WHEN start_geofence_id IS NULL THEN CONCAT('new?lat=', TP1.latitude, '&lng=', TP1.longitude)\r\n WHEN start_geofence_id IS NOT NULL THEN CONCAT(start_geofence_id, '/edit')\r\n END AS start_path,\r\n CASE WHEN end_geofence_id IS NULL THEN CONCAT('new?lat=', TP2.latitude, '&lng=', TP2.longitude)\r\n WHEN start_geofence_id IS NOT NULL THEN CONCAT(end_geofence_id, '/edit')\r\n END AS end_path,\r\n COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS \"Start Address\",\r\n COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS \"End Address\",\r\n convert_km(end_km::NUMERIC, '$length_unit') AS odometer_$length_unit,\r\n convert_km(distance::NUMERIC, '$length_unit') AS distance_$length_unit,\r\n convert_km(end_[[preferred_range]]_range_km::NUMERIC, '$length_unit') AS end_range_$length_unit,\r\n convert_km((end_[[preferred_range]]_range_km - start_[[preferred_range]]_range_km)::NUMERIC, '$length_unit') * efficiency AS \"kWh\",\r\n convert_km((end_[[preferred_range]]_range_km - start_[[preferred_range]]_range_km)::NUMERIC, '$length_unit') AS range_diff_$length_unit,\r\n TP2.battery_level AS \"SoC\",\r\n TP2.battery_level-TP1.battery_level AS \"SoC Diff\",\r\n convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_avg_$temp_unit,\r\n CONCAT('d/zm7wN6Zgz/drive-details?from=', ROUND(EXTRACT(EPOCH FROM start_date))*1000, '&to=', ROUND(EXTRACT(EPOCH FROM end_date))*1000, '&var-car_id=', drives.car_id, '&var-drive_id=', drives.id) AS slotlink\r\nFROM drives\r\n LEFT OUTER JOIN positions AS TP1 on drives.start_position_id = TP1.id\r\n LEFT OUTER JOIN positions AS TP2 on drives.end_position_id = TP2.id\r\n LEFT JOIN addresses start_address ON start_address_id = start_address.id\r\n LEFT JOIN addresses end_address ON end_address_id = end_address.id\r\n LEFT JOIN geofences start_geofence ON start_geofence_id = start_geofence.id\r\n LEFT JOIN geofences end_geofence ON end_geofence_id = end_geofence.id\r\n JOIN cars ON cars.id = drives.car_id\r\nWHERE \r\n $__timeFilter(drives.start_date)\r\n AND drives.car_id = $car_id\r\n AND '🚗 Driving' in ($action_filter)\r\n AND\r\n (COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city))::TEXT like '%$text_filter%' or\r\n COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city))::TEXT like '%$text_filter%')\r\n\r\nUNION\r\nSELECT\r\n start_date AS \"Start\",\r\n end_date AS \"End\",\r\n ROUND(EXTRACT(EPOCH FROM start_date))*1000 AS start_date_ts,\r\n ROUND(EXTRACT(EPOCH FROM end_date))*1000 AS end_date_ts,\r\n '🔋 Charging' AS \"Action\",\r\n charging_processes.duration_min AS \"Duration\",\r\n CASE WHEN geofence_id IS NULL THEN CONCAT('new?lat=', address.latitude, '&lng=', address.longitude)\r\n WHEN geofence_id IS NOT NULL THEN CONCAT(geofence_id, '/edit')\r\n END AS start_path,\r\n NULL AS end_path,\r\n COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS \"Start Address\",\r\n '' AS \"End Address\",\r\n convert_km(position.odometer::NUMERIC, '$length_unit') AS odometer_$length_unit,\r\n NULL AS distance_$length_unit,\r\n convert_km(end_[[preferred_range]]_range_km::NUMERIC, '$length_unit') AS end_range_$length_unit,\r\n charging_processes.charge_energy_added AS \"kWh\",\r\n convert_km((end_[[preferred_range]]_range_km - start_[[preferred_range]]_range_km)::NUMERIC, '$length_unit') AS range_diff_$length_unit, \r\n end_battery_level AS \"SoC\",\r\n end_battery_level - start_battery_level AS \"SoC Diff\",\r\n convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_avg_$temp_unit,\r\n CONCAT('d/BHhxFeZRz/charge-details?from=', ROUND(EXTRACT(EPOCH FROM start_date)-10)*1000, '&to=', ROUND(EXTRACT(EPOCH FROM end_date)+10)*1000, '&var-car_id=', charging_processes.car_id, '&var-charging_process_id=', charging_processes.id) AS slotlink\r\nFROM charging_processes\r\n INNER JOIN positions AS position ON position_id = position.id\r\n LEFT JOIN addresses address ON address_id = address.id\r\n LEFT JOIN geofences geofence ON geofence_id = geofence.id\r\nWHERE\r\n $__timeFilter(charging_processes.start_date)\r\n AND charging_processes.charge_energy_added > 0\r\n AND charging_processes.car_id = $car_id\r\n AND '🔋 Charging' in ($action_filter)\r\n AND COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city))::TEXT like '%$text_filter%'\r\nUNION\r\nSELECT\r\n d.end_date AS \"Start\",\r\n LEAD(d.start_date) over w AS \"End\",\r\n ROUND(EXTRACT(EPOCH FROM d.end_date)) * 1000 AS start_date_ts,\r\n ROUND(EXTRACT(EPOCH FROM LEAD(d.start_date) over w))*1000 AS end_date_ts,\r\n '🅿️ Parking' AS \"Action\",\r\n EXTRACT(EPOCH FROM LEAD(d.start_date) over w - d.end_date)/60 AS \"Duration\",\r\n CASE WHEN d.end_geofence_id IS NULL THEN CONCAT('new?lat=', end_position.latitude, '&lng=', end_position.longitude)\r\n WHEN d.end_geofence_id IS NOT NULL THEN CONCAT(d.end_geofence_id, '/edit')\r\n END AS start_path,\r\n NULL AS end_path,\r\n COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS \"Start Address\",\r\n '' AS \"End Address\",\r\n convert_km(end_position.odometer::NUMERIC, '$length_unit') AS odometer_$length_unit,\r\n NULL AS distance_$length_unit,\r\n convert_km(LEAD(d.start_[[preferred_range]]_range_km) over w::NUMERIC, '$length_unit') AS end_range_$length_unit,\r\n convert_km(((LEAD(d.start_[[preferred_range]]_range_km) over w + (LEAD(d.start_km) over w - d.end_km)) - d.end_[[preferred_range]]_range_km)::NUMERIC, '$length_unit') * efficiency AS \"kWh\",\r\n convert_km(((LEAD(d.start_[[preferred_range]]_range_km) over w + (LEAD(d.start_km) over w - d.end_km)) - d.end_[[preferred_range]]_range_km)::NUMERIC, '$length_unit') AS range_diff_$length_unit,\r\n LEAD(start_position.battery_level) over w AS \"SoC\",\r\n LEAD(start_position.battery_level) over w - end_position.battery_level AS \"SoC Diff\",\r\n convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_avg_$temp_unit,\r\n CONCAT('d/FkUpJpQZk/trip?from=', ROUND(EXTRACT(EPOCH FROM d.end_date))*1000, '&to=', ROUND(EXTRACT(EPOCH FROM LEAD(d.start_date) over w))*1000, '&var-car_id=', d.car_id) AS slotlink\r\nFROM\r\n drives AS d\r\n LEFT OUTER JOIN positions start_position on d.start_position_id = start_position.id\r\n LEFT OUTER JOIN positions end_position on d.end_position_id = end_position.id\r\n LEFT JOIN addresses address ON d.end_address_id = address.id\r\n LEFT JOIN geofences geofence ON d.end_geofence_id = geofence.id\r\n JOIN cars ON cars.id = d.car_id\r\nWHERE\r\n $__timeFilter(d.end_date)\r\n AND d.car_id=$car_id\r\n AND '🅿️ Parking' in ($action_filter)\r\n AND COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city))::TEXT like '%$text_filter%'\r\nWINDOW w as (ORDER BY d.id ASC)\r\n\r\nUNION\r\nSELECT\r\n\tT1.end_date +(1 * interval '1 second') AS \"Start\", -- added 1 sec to get it after the corresponding Parking row\r\n\tT2.start_date AS \"End\",\r\n\tROUND(EXTRACT(EPOCH FROM T2.start_date)) * 1000 - 1 AS start_date_ts,\r\n\tROUND(EXTRACT(EPOCH FROM T2.start_date)) * 1000 - 1 AS end_date_ts,\r\n\t'❓ Missing' AS \"Action\",\r\n\t-- EXTRACT(EPOCH FROM T2.start_date - T1.end_date)/60 AS \"Duration\",\r\n\tNULL AS \"Duration\",\r\n\tCASE WHEN T1.end_geofence_id IS NULL THEN CONCAT('new?lat=', TP1.latitude, '&lng=', TP1.longitude)\r\n\t\tWHEN T1.end_geofence_id IS NOT NULL THEN CONCAT(T1.end_geofence_id, '/edit')\r\n\tEND AS start_path,\r\n\tCASE WHEN T2.start_geofence_id IS NULL THEN CONCAT('new?lat=', TP2.latitude, '&lng=', TP2.longitude)\r\n\t\tWHEN T2.start_geofence_id IS NOT NULL THEN CONCAT(T2.start_geofence_id, '/edit')\r\n\tEND AS end_path,\r\n\tCOALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS \"Start Address\",\r\n\tCOALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS \"End Address\",\r\n\tconvert_km(TP2.odometer::INTEGER, '$length_unit') AS odometer_$length_unit,\r\n\tconvert_km((TP2.odometer - TP1.odometer)::INTEGER, '$length_unit') AS distance_$length_unit,\r\n convert_km(T2.end_[[preferred_range]]_range_km::NUMERIC, '$length_unit') AS end_range_$length_unit,\r\n\tconvert_km(((TP2.[[preferred_range]]_battery_range_km + (TP2.odometer - TP1.odometer)) - TP1.[[preferred_range]]_battery_range_km)::INTEGER, '$length_unit')::INTEGER * efficiency AS \"kWh\",\r\n\tconvert_km(((TP2.[[preferred_range]]_battery_range_km + (TP2.odometer - TP1.odometer)) - TP1.[[preferred_range]]_battery_range_km)::INTEGER, '$length_unit') AS range_diff_$length_unit,\r\n\tNULL AS \"SoC\",\r\n\tNULL AS \"SoC Diff\",\r\n\tNULL AS outside_temp_avg_$temp_unit,\r\n\tNULL AS slotlink\r\n\t-- TP2.battery_level AS \"SoC\",\r\n\t-- TP2.battery_level-TP1.battery_level AS \"SoC Diff\",\r\n\t-- (T1.outside_temp_avg+T2.outside_temp_avg)/2 AS outside_temp_avg_$temp_unit\r\nFROM\r\n\t(SELECT row_number() over(ORDER BY start_date) AS time_id, * FROM drives) AS T1\r\n\tLEFT OUTER JOIN (SELECT row_number() over(ORDER BY start_date) AS time_id, * FROM drives ) AS T2 on T1.time_id + 1 = T2.time_id\r\n\tLEFT OUTER JOIN positions AS TP1 on T1.end_position_id = TP1.id\r\n\tLEFT OUTER JOIN positions AS TP2 on T2.start_position_id = TP2.id\r\n\tLEFT JOIN addresses start_address ON T1.end_address_id = start_address.id\r\n\tLEFT JOIN addresses end_address ON T2.start_address_id = end_address.id\r\n\tLEFT JOIN geofences start_geofence ON T1.end_geofence_id = start_geofence.id\r\n\tLEFT JOIN geofences end_geofence ON T2.start_geofence_id = end_geofence.id\r\n\tJOIN cars ON cars.id = T2.car_id\r\nWHERE\r\n\t$__timeFilter(T1.end_date)\r\n\tAND T1.car_id=$car_id \r\n\tAND T2.car_id=$car_id \r\n\tAND TP2.car_id=$car_id \r\n\tAND TP1.car_id=$car_id \r\n\tAND TP2.odometer - TP1.odometer > 0.5\r\n\tAND T1.end_address_id <> T2.start_address_id AND ((T1.end_geofence_id IS NOT NULL OR T2.end_geofence_id IS NOT NULL) OR T1.end_geofence_id <> T2.start_geofence_id)\r\n\tAND '❓ Missing' in ($action_filter)\r\n\tAND (\r\n\t (COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city))::TEXT like '%$text_filter%') or\r\n\t (COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)))::TEXT like '%$text_filter%')\r\nUNION\r\nSELECT\r\n start_date AS \"Start\",\r\n end_date AS \"End\",\r\n ROUND(EXTRACT(EPOCH FROM start_date))*1000 AS start_date_ts, \r\n ROUND(EXTRACT(EPOCH FROM end_date))*1000 AS end_date_ts, \r\n '💾 Updating' AS \"Action\",\r\n\tEXTRACT(EPOCH FROM end_date - start_date)/60 AS \"Duration\",\r\n NULL AS start_path,\r\n NULL AS end_path,\r\n version AS \"Start Address\",\r\n '' AS \"End Address\",\r\n NULL AS odometer_$length_unit,\r\n NULL AS distance_$length_unit,\r\n NULL AS end_range_$length_unit,\r\n NULL AS \"kWh\",\r\n NULL AS range_diff_$length_unit,\r\n NULL AS \"SoC\",\r\n NULL AS \"SoC Diff\",\r\n NULL AS outside_temp_avg_$temp_unit,\r\n CONCAT('https://www.notateslaapp.com/software-updates/version/', split_part(version, ' ', 1), '/release-notes') AS slotlink\r\nFROM updates\r\nWHERE \r\n $__timeFilter(start_date)\r\n AND car_id = $car_id \r\n AND '💾 Updating' in ($action_filter)\r\n AND version::TEXT like '%$text_filter%'\r\n\r\nORDER BY \"Start\" DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["id"], + "type": "column" + } + ] + ], + "table": "candata", + "timeColumn": "datum", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Timeline", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "End": true, + "start_date_ts": false + }, + "indexByName": { + "Action": 2, + "Duration": 7, + "End": 1, + "End Address": 4, + "SoC": 15, + "SoC Diff": 16, + "Start": 0, + "Start Address": 3, + "distance_km": 8, + "distance_mi": 9, + "end_date_ts": 22, + "end_path": 20, + "end_range_km": 10, + "end_range_mi": 11, + "kWh": 13, + "odometer_km": 5, + "odometer_mi": 6, + "outside_temp_avg_c": 17, + "outside_temp_avg_f": 18, + "range_diff_km": 12, + "range_diff_mi": 13, + "start_date_ts": 21, + "start_path": 19 + }, + "renameByName": { + "action": "", + "end_address": "End", + "km_diff": "Km", + "kwh": "", + "minutediff": "Time", + "odometer": "", + "outside_temp_avg": "Temperature", + "rangediff": "Range Difference", + "soc": "", + "soc_diff": "SoC Difference", + "start_address": "Start", + "start_date": "Date", + "start_date_ts": "" + } + } + } + ], + "type": "table" + } + ], + "refresh": "1h", + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": ["All"], + "value": ["$__all"] + }, + "hide": 0, + "includeAll": true, + "label": "Action", + "multi": true, + "name": "action_filter", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "🚗 Driving", + "value": "🚗 Driving" + }, + { + "selected": false, + "text": "🔋 Charging", + "value": "🔋 Charging" + }, + { + "selected": false, + "text": "🅿️ Parking", + "value": "🅿️ Parking" + }, + { + "selected": false, + "text": "❓ Missing", + "value": "❓ Missing" + }, + { + "selected": false, + "text": "💾 Updating", + "value": "💾 Updating" + } + ], + "query": "🚗 Driving,🔋 Charging,🅿️ Parking,❓ Missing,💾 Updating", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "hide": 0, + "label": "Text Filter", + "name": "text_filter", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "length unit", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "temperature unit", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-14d", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Timeline", + "uid": "SUBgwtigz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/trip.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/trip.json new file mode 100644 index 00000000000..e057c567268 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/trip.json @@ -0,0 +1,2643 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:30", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "iteration": 1656104359102, + "links": [ + { + "icon": "doc", + "tags": [], + "targetBlank": true, + "title": "Select last three drives", + "type": "link", + "url": "/d/FkUpJpQZk?from=$from" + }, + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 13, + "x": 0, + "y": 1 + }, + "id": 6, + "maxDataPoints": 500, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 3, + "max": 15, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "name": "Layer 1", + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": "TeslaMate", + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date, '5s') AS time,\n\tavg(latitude) AS latitude,\n\tavg(longitude) AS longitude\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n\t$__timeFilter(date)\nGROUP BY\n\t1\nORDER BY\n\t1 ASC", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "transformations": [], + "transparent": true, + "type": "geomap" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + }, + { + "id": "displayName", + "value": "Distance" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + }, + { + "id": "displayName", + "value": "Distance" + } + ] + } + ] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 13, + "y": 1 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km((max(odometer) - min(odometer))::numeric, '$length_unit') as \"distance_$length_unit\"\nFROM positions\nWHERE car_id = $car_id AND $__timeFilter(date)\nORDER BY 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 1, + "mappings": [], + "unit": "dtdurations" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "charging (AC)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charging (DC)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "driving" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5794F2", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 19, + "y": 1 + }, + "id": 38, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": ["name", "percent"], + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "values": ["value"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tnow() AS time,\n\tsum(extract(epoch FROM end_position.date - start_position.date)) as duration_sec,\n\t'driving' as metric\nFROM\n\tdrives\n\tJOIN positions start_position ON start_position_id = start_position.id\n\tJOIN positions end_position ON end_position_id = end_position.id\nWHERE\n\tdrives.car_id = $car_id\n\tAND $__timeFilter(start_date);", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charges_current AS (\n SELECT\n\t\tcp.id,\n \textract(epoch FROM LEAST(end_date, $__timeTo()) - GREATEST(start_date, $__timeFrom())) as duration_sec,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'charging (DC)'\n\t\t\t\t ELSE 'charging (AC)'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0\n \tAND ($__timeFilter(start_date) OR $__timeFilter(end_date))\n GROUP BY 1,2\n),\n\ncharges_total AS (\n SELECT\n \tsum(duration_sec) AS duration_sec,\n \tcurrent AS metric\n FROM charges_current\n GROUP BY 2\n ORDER BY metric\n)\n\nSELECT\n\tnow() AS time,\n\tcoalesce(duration_sec, 0) as duration_sec,\n metric\nFROM\n\tcharges_total;", + "refId": "B", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "piechart" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "speed_km" + }, + "properties": [ + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "displayName", + "value": "excl. breaks" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_mi" + }, + "properties": [ + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "displayName", + "value": "excl. breaks" + } + ] + } + ] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 13, + "y": 3 + }, + "id": 26, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n convert_km(sum(end_position.odometer - start_position.odometer)::numeric, '$length_unit') / (sum(extract(epoch FROM end_position.date - start_position.date)) / 3600) as \"speed_$length_unit\"\nFROM\n\tdrives\n\tJOIN positions start_position ON start_position_id = start_position.id\n\tJOIN positions end_position ON end_position_id = end_position.id\nWHERE\n\tdrives.car_id = $car_id\n\tAND $__timeFilter(start_date)", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "speed_km" + }, + "properties": [ + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "displayName", + "value": "incl. DC charging" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_mi" + }, + "properties": [ + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "displayName", + "value": "incl. DC charging" + } + ] + } + ] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 13, + "y": 5 + }, + "id": 28, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH dc_charges AS (\n SELECT\n\t\tcp.id,\n extract(epoch FROM cp.end_date - cp.start_date) as duration_sec,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0\n AND ($__timeFilter(start_date) OR $__timeFilter(end_date))\n GROUP BY 1,2\n),\n\ndata AS (\n (\n SELECT\n sum(end_position.odometer - start_position.odometer) as distance, \n sum(extract(epoch FROM end_position.date - start_position.date)) as duration_sec\n FROM\n drives\n JOIN positions start_position ON start_position_id = start_position.id\n JOIN positions end_position ON end_position_id = end_position.id\n WHERE\n drives.car_id = $car_id\n AND $__timeFilter(start_date)\n ) UNION ALL (\n SELECT\n NULL as distance,\n sum(duration_sec)\n FROM\n dc_charges\n WHERE\n current = 'DC'\n )\n)\n\nSELECT convert_km(sum(distance)::numeric, '$length_unit') / (sum(duration_sec) / 3600) as \"speed_$length_unit\"\nfrom data", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "displayName", + "value": "net" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "displayName", + "value": "net" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 13, + "y": 7 + }, + "id": 30, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n sum(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0) * car.efficiency * 1000) / \n convert_km(sum(distance)::numeric, '$length_unit') as \"consumption_$length_unit\"\nFROM drives\nJOIN cars car ON car.id = car_id\nWHERE $__timeFilter(start_date) AND car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "displayName", + "value": "gross" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "displayName", + "value": "gross" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 16, + "y": 7 + }, + "id": 32, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM charging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id AND\n\t $__timeFilter(start_date)\n\tORDER BY start_date\n),\n\nrange_loss_between_charges AS (\n SELECT sum(range_loss) AS range_loss\n FROM d\n WHERE distance >= 0 AND range_loss >= 0\n GROUP BY car_id\n),\n\ncharge_dates AS (\n\tSELECT\n\t\tmin(start_date) as first_charge,\n\t\tmax(end_date) as last_charge\n\tFROM\n\t\tcharging_processes\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(start_date)\n),\n\nrange_loss_before_first_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND ((select first_charge from charge_dates) is null OR date < (select first_charge from charge_dates))\n),\n\nrange_loss_after_last_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND date > (select last_charge from charge_dates)\t\n),\n\ntotal_range_loss AS (\n SELECT sum(range_loss) as range_loss\n FROM (\n SELECT range_loss FROM range_loss_between_charges\n UNION ALL\n SELECT range_loss FROM range_loss_before_first_charge\n UNION ALL\n SELECT range_loss FROM range_loss_after_last_charge\n ) r\n),\n\ndistance AS (\n SELECT max(odometer) - min(odometer) as distance\n FROM positions\n WHERE car_id = $car_id AND $__timeFilter(date)\n)\n\nSELECT \n NULLIF(range_loss, 0) * (c.efficiency * 1000) / convert_km(NULLIF(distance::numeric, 0), '$length_unit') as \"consumption_$length_unit\"\nFROM total_range_loss, distance\nLEFT JOIN cars c ON c.id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "displayName": "Cost", + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 5, + "x": 19, + "y": 9 + }, + "id": 22, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select sum(cost) as \"Cost\" from charging_processes where $__timeFilter(start_date) AND car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 1, + "displayName": "${__cell_0}", + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 10 + }, + { + "color": "semi-dark-orange", + "value": 100 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 11, + "x": 13, + "y": 11 + }, + "id": 40, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "showUnfilled": false, + "valueMode": "color" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM charging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id AND\n\t $__timeFilter(start_date)\n\tORDER BY start_date\n),\n\nrange_loss_between_charges AS (\n SELECT sum(range_loss) AS range_loss\n FROM d\n WHERE distance >= 0 AND range_loss >= 0\n GROUP BY car_id\n),\n\ncharge_dates AS (\n\tSELECT\n\t\tmin(start_date) as first_charge,\n\t\tmax(end_date) as last_charge\n\tFROM\n\t\tcharging_processes\n\tWHERE\n\t\tend_date IS NOT NULL\n\t\tAND car_id = $car_id\n\t\tAND $__timeFilter(start_date)\n),\n\nrange_loss_before_first_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND ((select first_charge from charge_dates) is null OR date < (select first_charge from charge_dates))\n),\n\nrange_loss_after_last_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND date > (select last_charge from charge_dates)\t\n),\n\ntotal_range_loss AS (\n\tSELECT range_loss FROM range_loss_between_charges\n\tUNION ALL\n\tSELECT range_loss FROM range_loss_before_first_charge\n\tUNION ALL\n\tSELECT range_loss FROM range_loss_after_last_charge\n)\n\nSELECT 'used' as metric, sum(range_loss * c.efficiency) AS value\nFROM total_range_loss\nLEFT JOIN cars c ON c.id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charges_current AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added as energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'added (DC)'\n\t\t\t\t ELSE 'added (AC)'\n\t\tEND AS metric\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0\n \tAND ($__timeFilter(start_date) OR $__timeFilter(end_date))\n GROUP BY 1,2\n)\n\nSELECT metric, sum(energy_added) AS energy_added\nFROM charges_current\nGROUP BY 1\nORDER BY 1 DESC;", + "refId": "B", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "bargauge" + }, + { + "datasource": "TeslaMate", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 100, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "color": "#6ED0E0", + "index": 0, + "text": "online" + }, + "1": { + "color": "#8F3BB8", + "index": 1, + "text": "driving" + }, + "2": { + "color": "#F2CC0C", + "index": 2, + "text": "charging" + }, + "3": { + "color": "#FFB357", + "index": 3, + "text": "offline" + }, + "4": { + "color": "#56A64B", + "index": 4, + "text": "asleep" + }, + "5": { + "color": "#6ED0E0", + "index": 5, + "text": "online" + }, + "6": { + "color": "#E02F44", + "index": 6, + "text": "updating" + }, + "null": { + "index": 7, + "text": "N/A" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 20, + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "mergeValues": true, + "rowHeight": 1, + "showValue": "never", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH states AS (\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [2, 0]) AS state\n FROM charging_processes\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [1, 0]) AS state\n FROM drives\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n start_date AS date,\n CASE\n WHEN state = 'offline' THEN 3\n WHEN state = 'asleep' THEN 4\n WHEN state = 'online' THEN 5\n END AS state\n FROM states\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [6, 0]) AS state\n FROM updates\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n)\nSELECT date AS \"time\", state\nFROM states\nWHERE \n date IS NOT NULL AND\n ($__timeFrom() :: timestamp - interval '30 day') < date AND \n date < ($__timeTo() :: timestamp + interval '30 day') \nORDER BY date ASC, state ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "transparent": true, + "type": "state-timeline" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "View drive details", + "url": "d/zm7wN6Zgz?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}&var-car_id=${__data.fields.car_id.numeric}&var-drive_id=${__data.fields.drive_id.numeric}" + } + ] + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "km" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_address" + }, + "properties": [ + { + "id": "displayName", + "value": "Start" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.start_path}" + } + ] + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_address" + }, + "properties": [ + { + "id": "displayName", + "value": "Destination" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.end_path}" + } + ] + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "m" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "links", + "value": [ + { + "title": "${__data.fields.duration_str}", + "url": "" + } + ] + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "mi" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "% Start" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "% End" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "(start_path|end_path|duration_str|car_id|drive_id)" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 2, + "links": [], + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n round(extract(epoch FROM start_date)) * 1000 AS start_date_ts,\n round(extract(epoch FROM end_date)) * 1000 AS end_date_ts,\n car.id as car_id,\n CASE WHEN start_geofence.id IS NULL THEN CONCAT('new?lat=', start_position.latitude, '&lng=', start_position.longitude)\n WHEN start_geofence.id IS NOT NULL THEN CONCAT(start_geofence.id, '/edit')\n END as start_path,\n CASE WHEN end_geofence.id IS NULL THEN CONCAT('new?lat=', end_position.latitude, '&lng=', end_position.longitude)\n WHEN end_geofence.id IS NOT NULL THEN CONCAT(end_geofence.id, '/edit')\n END as end_path,\n TO_CHAR((duration_min * INTERVAL '1 minute'), 'HH24:MI') as duration_str,\n drives.id as drive_id,\n -- Columns\n start_date,\n COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS start_address,\n COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS end_address,\n duration_min,\n distance,\n start_position.usable_battery_level as start_usable_battery_level,\n start_position.battery_level as start_battery_level,\n end_position.usable_battery_level as end_usable_battery_level,\n end_position.battery_level as end_battery_level,\n start_position.battery_level != start_position.usable_battery_level OR end_position.battery_level != end_position.usable_battery_level as reduced_range,\n duration_min > 1 AND distance > 1 AND ( \n start_position.usable_battery_level IS NULL OR end_position.usable_battery_level IS NULL\tOR\n (end_position.battery_level - end_position.usable_battery_level) = 0 \n ) as is_sufficiently_precise,\n NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) as range_diff,\n car.efficiency as car_efficiency,\n outside_temp_avg,\n distance / NULLIF(duration_min, 0) * 60 AS avg_speed\n FROM drives\n LEFT JOIN addresses start_address ON start_address_id = start_address.id\n LEFT JOIN addresses end_address ON end_address_id = end_address.id\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id\n LEFT JOIN geofences start_geofence ON start_geofence_id = start_geofence.id\n LEFT JOIN geofences end_geofence ON end_geofence_id = end_geofence.id\n LEFT JOIN cars car ON car.id = drives.car_id\n WHERE $__timeFilter(start_date) AND drives.car_id = $car_id\n ORDER BY start_date DESC\n)\nSELECT\n start_date_ts,\n end_date_ts,\n car_id,\n start_path,\n end_path,\n duration_str,\n drive_id,\n -- Columns\n start_date,\n start_address,\n end_address,\n duration_min,\n convert_km(distance::numeric, '$length_unit') AS distance_$length_unit,\n start_battery_level as \"% Start\",\n end_battery_level as \"% End\",\n CASE WHEN is_sufficiently_precise THEN range_diff * car_efficiency / distance * 1000 * CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END\n END AS consumption_kWh_$length_unit\nFROM data;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Drives", + "transformations": [], + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "View charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}&var-car_id=${__data.fields.car_id.numeric}&var-charging_process_id=${__data.fields.id.numeric:raw}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Added" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "% Start" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "% End" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "m" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost" + }, + "properties": [ + { + "id": "displayName", + "value": "Cost" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "Set Cost", + "url": "[[base_url:raw]]/charge-cost/${__data.fields.id.numeric:raw}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "id" + }, + "properties": [ + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "address" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.path}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Driven" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added_per_hour" + }, + "properties": [ + { + "id": "displayName", + "value": "kW" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#96D98D" + }, + { + "color": "#56A64B", + "value": 20 + }, + { + "color": "#37872D", + "value": 55 + } + ] + } + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Driven" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "path" + }, + "properties": [ + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Used" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "car_id" + }, + "properties": [ + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 36, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts,\n (round(extract(epoch FROM end_date) + 10) * 1000) AS end_date_ts,\n start_date,\n end_date,\n CONCAT_WS(', ', COALESCE(addresses.name, CONCAT_WS(' ', addresses.road, addresses.house_number)), addresses.city) AS address,\n g.name as geofence_name,\n g.id as geofence_id,\n p.latitude,\n p.longitude,\n charge_energy_added,\n charge_energy_used,\n duration_min,\n start_battery_level,\n end_battery_level,\n start_[[preferred_range]]_range_km,\n end_[[preferred_range]]_range_km,\n outside_temp_avg,\n c.id,\n lag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n p.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance,\n cars.efficiency,\n c.car_id,\n cost\n FROM\n charging_processes c\n LEFT JOIN positions p ON p.id = c.position_id\n LEFT JOIN cars ON cars.id = c.car_id\n LEFT JOIN addresses ON addresses.id = c.address_id\n LEFT JOIN geofences g ON g.id = geofence_id\nWHERE \n (charge_energy_added IS NULL OR charge_energy_added > 0) AND\n c.car_id = $car_id AND\n $__timeFilter(start_date)\nORDER BY\n start_date\n)\nSELECT\n start_date_ts,\n end_date_ts,\n CASE WHEN geofence_id IS NULL THEN CONCAT('new?lat=', latitude, '&lng=', longitude)\n WHEN geofence_id IS NOT NULL THEN CONCAT(geofence_id, '/edit')\n END as path,\n car_id,\n id,\n -- Columns\n start_date,\n COALESCE(geofence_name, address) as address, \n duration_min,\n cost,\n charge_energy_added,\n charge_energy_used,\n charge_energy_added * 60 / NULLIF (duration_min, 0) AS charge_energy_added_per_hour,\n start_battery_level,\n end_battery_level,\n convert_km(distance::numeric, '$length_unit') AS distance_$length_unit\n FROM\n data\nWHERE\n (distance >= 0 OR distance IS NULL)\nORDER BY\n start_date DESC;\n ", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charges", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "battery_level" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "displayName", + "value": "SOC" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_km$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "range_ideal_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Range (ideal)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "range_rated_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Range (rated)" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 42, + "options": { + "legend": { + "calcs": ["min", "max", "lastNotNull"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "(\n SELECT $__timeGroup(date, '5s'), avg(battery_level) as battery_level, convert_km(avg([[preferred_range]]_battery_range_km), '$length_unit') as range_[[preferred_range]]_[[length_unit]]\n FROM positions\n WHERE date BETWEEN ($__timeFrom()::timestamp - interval '1 day') AND ($__timeTo()::timestamp + interval '1 day') AND car_id = $car_id\n GROUP BY 1\n) UNION ALL (\n SELECT $__timeGroup(date, '5s'), avg(battery_level) as battery_level, convert_km(avg([[preferred_range]]_battery_range_km), '$length_unit') as range_[[preferred_range]]_[[length_unit]]\n FROM charges c\n LEFT JOIN charging_processes p ON c.charging_process_id = p.id\n WHERE date BETWEEN ($__timeFrom()::timestamp - interval '1 day') AND ($__timeTo()::timestamp + interval '1 day') AND p.car_id = $car_id\n GROUP BY 1\n)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Level & Range", + "type": "timeseries" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_m$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_ft$" + }, + "properties": [ + { + "id": "unit", + "value": "lengthft" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "elevation_.*" + }, + "properties": [ + { + "id": "displayName", + "value": "Elevation" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 8, + "options": { + "legend": { + "calcs": ["min", "max", "lastNotNull"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "datasource": "TeslaMate", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__timeGroup(date, '5s'),\n\tROUND(convert_m(avg(elevation), '$alternative_length_unit')) AS elevation_[[alternative_length_unit]]\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n date BETWEEN ($__timeFrom()::timestamp - interval '1 day') AND ($__timeTo()::timestamp + interval '1 day')\nGROUP BY\n 1\nORDER BY\n 1 ASC", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Elevation", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "C", + "value": "C" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "temperature unit", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "length unit", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "m", + "value": "m" + }, + "datasource": "TeslaMate", + "definition": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "alternative_length_unit", + "options": [], + "query": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "1642593521525", + "value": "1642593521525" + }, + "datasource": "TeslaMate", + "definition": "with last_drives as (select start_date from drives order by start_date desc limit 3)\nselect extract(epoch from min(start_date)) * 1000 from last_drives;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "from", + "options": [], + "query": "with last_drives as (select start_date from drives order by start_date desc limit 3)\nselect extract(epoch from min(start_date)) * 1000 from last_drives;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Trip", + "uid": "FkUpJpQZk", + "version": 2, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/updates.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/updates.json new file mode 100644 index 00000000000..c63eedfb66f --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/updates.json @@ -0,0 +1,723 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:15", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1643273221821, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["count"], + "fields": "", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT count(*)\nFROM updates\nWHERE $__timeFilter(start_date) AND car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Updates", + "type": "stat" + }, + { + "datasource": "TeslaMate", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "dtdurations" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 16, + "x": 8, + "y": 1 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY since_last_update) FROM (\n\tSELECT extract(EPOCH FROM start_date - lag(start_date) OVER (ORDER BY start_date)) AS since_last_update\n\tFROM updates\n\tWHERE $__timeFilter(start_date) AND car_id = $car_id\n) d;", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median time between updates", + "type": "stat" + }, + { + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "time" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "displayName", + "value": "Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "update_duration" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "dtdurations" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "since_last_update" + }, + "properties": [ + { + "id": "custom.width", + "value": 160 + }, + { + "id": "displayName", + "value": "Since Previous Update" + }, + { + "id": "unit", + "value": "dtdurations" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "version" + }, + "properties": [ + { + "id": "displayName", + "value": "Installed Version" + }, + { + "id": "custom.align", + "value": "right" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "${__data.fields[version]} release notes", + "url": "https://www.notateslaapp.com/software-updates/version/${__data.fields[version]}/release-notes" + } + ] + }, + { + "id": "unit", + "value": "string" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "chg_ct" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "displayName", + "value": "# of Charges" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_ideal_range_km" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "displayName", + "value": "Avg ideal range" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_rated_range_km" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "displayName", + "value": "Avg rated range" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_ideal_range_mi" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "displayName", + "value": "Avg ideal range" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_rated_range_mi" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "displayName", + "value": "Avg rated range" + } + ] + } + ] + }, + "gridPos": { + "h": 28, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "8.3.4", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "$$hashKey": "object:68", + "alias": "Date", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "start_date", + "type": "date" + }, + { + "$$hashKey": "object:69", + "alias": "End Date", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "end_date", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "$$hashKey": "object:70", + "alias": "Installed Version", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": true, + "linkTooltip": "${__cell} release info", + "linkUrl": "https://www.notateslaapp.com/software-updates/version/${__cell}/release-notes", + "mappingType": 1, + "pattern": "version", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "$$hashKey": "object:202", + "alias": "Duration", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "update_duration", + "thresholds": [], + "type": "number", + "unit": "dtdurations" + }, + { + "$$hashKey": "object:392", + "alias": "Since Previous Update", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "mappingType": 1, + "pattern": "since_last_update", + "thresholds": [], + "type": "number", + "unit": "dtdurations" + }, + { + "$$hashKey": "object:71", + "alias": "# of Charges", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "pattern": "chg_ct", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with u as (\r\n select *, coalesce(lag(start_date) over(order by start_date desc), now()) as next_start_date \r\n from updates\r\n where car_id = $car_id and $__timeFilter(start_date)\r\n),\r\nrng as (\r\n SELECT\r\n\t to_timestamp(floor(extract(epoch from date)/21600)*21600) AS date,\r\n\t (sum([[preferred_range]]_battery_range_km) / nullif(sum(coalesce(usable_battery_level,battery_level)),0) * 100 ) AS \"battery_rng\"\r\n FROM (\r\n select battery_level, usable_battery_level, date, rated_battery_range_km, ideal_battery_range_km\r\n from positions\r\n where car_id = $car_id and $__timeFilter(date) and ideal_battery_range_km is not null\r\n union all\r\n select battery_level, coalesce(usable_battery_level,battery_level) as usable_battery_level, date, rated_battery_range_km, ideal_battery_range_km\r\n from charges c\r\n join charging_processes p ON p.id = c.charging_process_id \r\n where $__timeFilter(date) and p.car_id = $car_id\r\n ) as data\r\n GROUP BY 1\r\n)\r\n\r\nselect\t\r\n u.start_date as time,\r\n\textract(EPOCH FROM u.end_date - u.start_date) AS update_duration,\r\n\textract(EPOCH FROM u.start_date - lag(u.start_date) OVER (ORDER BY u.start_date)) AS since_last_update,\r\n\tsplit_part(u.version, ' ', 1) as version,\r\n\tcount(distinct cp.id) as chg_ct,\r\n\tconvert_km(avg(r.battery_rng), '$length_unit')::numeric(6,2) AS avg_[[preferred_range]]_range_[[length_unit]]\r\nfrom u u\r\nleft join charging_processes cp\r\n\tON u.car_id = cp.car_id\r\n \tand cp.start_date between u.start_date and u.next_start_date\r\nleft join rng r\r\n\tON r.date between u.start_date and u.next_start_date\r\ngroup by u.car_id,\r\n\tu.start_date,\r\n\tu.end_date,\r\n\tnext_start_date,\r\n\tsplit_part(u.version, ' ', 1)", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "datasource": "TeslaMate", + "title": "Updates", + "type": "table" + } + ], + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-10y", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Updates", + "uid": "IiC07mgWz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/vampire-drain.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/vampire-drain.json new file mode 100644 index 00000000000..033b382c37a --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/vampire-drain.json @@ -0,0 +1,744 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "iteration": 1642779900099, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Start" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "", + "url": "d/zm7wN6Zgz?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_date" + }, + "properties": [ + { + "id": "displayName", + "value": "End" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_diff_km" + }, + "properties": [ + { + "id": "displayName", + "value": "TR Loss" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration" + }, + "properties": [ + { + "id": "displayName", + "value": "Period" + }, + { + "id": "unit", + "value": "s" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "rgb(133, 142, 133)", + "value": null + }, + { + "color": "#56A64B", + "value": 43200 + } + ] + } + }, + { + "id": "custom.minWidth", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_lost_per_hour_km" + }, + "properties": [ + { + "id": "displayName", + "value": "TR Loss / h" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "standby" + }, + "properties": [ + { + "id": "displayName", + "value": "Standby" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#FF7383", + "value": null + }, + { + "color": "#FFB357", + "value": 0.3 + }, + { + "color": "#56A64B", + "value": 0.85 + } + ] + } + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.width", + "value": 75 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption" + }, + "properties": [ + { + "id": "displayName", + "value": "kWh" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_power" + }, + "properties": [ + { + "id": "displayName", + "value": "Ø-Power" + }, + { + "id": "unit", + "value": "watt" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_lost_per_hour_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "TR Loss / h" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_diff_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "TR Loss" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "soc_diff" + }, + "properties": [ + { + "id": "displayName", + "value": "SOC" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "custom.width", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "has_reduced_range" + }, + "properties": [ + { + "id": "displayName", + "value": " " + }, + { + "id": "custom.align", + "value": "center" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "0": { + "color": "transparent", + "index": 1, + "text": " " + }, + "1": { + "color": "dark-blue", + "index": 0, + "text": "❄" + } + }, + "type": "value" + } + ] + }, + { + "id": "links", + "value": [ + { + "title": "In cold weather, the estimated range loss cannot be estimated correctly and is therefore hidden.", + "url": "" + } + ] + }, + { + "id": "custom.width", + "value": 5 + } + ] + } + ] + }, + "gridPos": { + "h": 23, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.3.4", + "targets": [ + { + "alias": "", + "datasource": "TeslaMate", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with merge as (\n SELECT \n c.start_date AS start_date,\n c.end_date AS end_date,\n c.start_ideal_range_km AS start_ideal_range_km,\n c.end_ideal_range_km AS end_ideal_range_km,\n c.start_rated_range_km AS start_rated_range_km,\n c.end_rated_range_km AS end_rated_range_km,\n start_battery_level,\n end_battery_level,\n p.usable_battery_level AS start_usable_battery_level,\n NULL AS end_usable_battery_level,\n p.odometer AS start_km,\n p.odometer AS end_km\n FROM charging_processes c\n JOIN positions p ON c.position_id = p.id\n WHERE c.car_id = $car_id AND $__timeFilter(start_date)\n UNION\n SELECT \n d.start_date AS start_date,\n d.end_date AS end_date,\n d.start_ideal_range_km AS start_ideal_range_km,\n d.end_ideal_range_km AS end_ideal_range_km,\n d.start_rated_range_km AS start_rated_range_km,\n d.end_rated_range_km AS end_rated_range_km,\n start_position.battery_level AS start_battery_level,\n end_position.battery_level AS end_battery_level,\n start_position.usable_battery_level AS start_usable_battery_level,\n end_position.usable_battery_level AS end_usable_battery_level,\n d.start_km AS start_km,\n d.end_km AS end_km\n FROM drives d\n JOIN positions start_position ON d.start_position_id = start_position.id\n JOIN positions end_position ON d.end_position_id = end_position.id\n WHERE d.car_id = $car_id AND $__timeFilter(start_date)\n), \nv as (\n SELECT\n lag(t.end_date) OVER w AS start_date,\n t.start_date AS end_date,\n lag(t.end_[[preferred_range]]_range_km) OVER w AS start_range,\n t.start_[[preferred_range]]_range_km AS end_range,\n lag(t.end_km) OVER w AS start_km,\n t.start_km AS end_km,\n EXTRACT(EPOCH FROM age(t.start_date, lag(t.end_date) OVER w)) AS duration,\n lag(t.end_battery_level) OVER w AS start_battery_level,\n lag(t.end_usable_battery_level) OVER w AS start_usable_battery_level,\n\t\tstart_battery_level AS end_battery_level,\n\t\tstart_usable_battery_level AS end_usable_battery_level,\n\t\tstart_battery_level > COALESCE(start_usable_battery_level, start_battery_level) AS has_reduced_range\n FROM merge t\n WINDOW w AS (ORDER BY t.start_date ASC)\n ORDER BY start_date DESC\n)\n\nSELECT\n round(extract(epoch FROM v.start_date)) * 1000 AS start_date_ts,\n round(extract(epoch FROM v.end_date)) * 1000 AS end_date_ts,\n -- Columns\n v.start_date,\n v.end_date,\n v.duration,\n (coalesce(s_asleep.sleep, 0) + coalesce(s_offline.sleep, 0)) / v.duration as standby,\n\t-greatest(v.start_battery_level - v.end_battery_level, 0) as soc_diff,\n\tCASE WHEN has_reduced_range THEN 1 ELSE 0 END as has_reduced_range,\n\tconvert_km(CASE WHEN has_reduced_range THEN NULL ELSE (v.start_range - v.end_range)::numeric END, '$length_unit') AS range_diff_$length_unit,\n CASE WHEN has_reduced_range THEN NULL ELSE (v.start_range - v.end_range) * c.efficiency END AS consumption,\n CASE WHEN has_reduced_range THEN NULL ELSE ((v.start_range - v.end_range) * c.efficiency) / (v.duration / 3600) * 1000 END as avg_power,\n convert_km(CASE WHEN has_reduced_range THEN NULL ELSE ((v.start_range - v.end_range) / (v.duration / 3600))::numeric END, '$length_unit') AS range_lost_per_hour_[[length_unit]]\nFROM v,\n LATERAL (\n SELECT EXTRACT(EPOCH FROM sum(age(s.end_date, s.start_date))) as sleep\n FROM states s\n WHERE\n state = 'asleep' AND\n v.start_date <= s.start_date AND s.end_date <= v.end_date AND\n s.car_id = $car_id\n ) s_asleep,\n LATERAL (\n SELECT EXTRACT(EPOCH FROM sum(age(s.end_date, s.start_date))) as sleep\n FROM states s\n WHERE\n state = 'offline' AND\n v.start_date <= s.start_date AND s.end_date <= v.end_date AND\n s.car_id = $car_id\n ) s_offline\nJOIN cars c ON c.id = $car_id\nWHERE\n v.duration > ($duration * 60 * 60)\n AND v.start_range - v.end_range >= 0\n AND v.end_km - v.start_km < 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "datasource": "TeslaMate", + "title": "Vampire Drain", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + } + ], + "schemaVersion": 36, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "TeslaMate", + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "tags": [], + "text": "6", + "value": "6" + }, + "hide": 0, + "includeAll": false, + "label": "min. Idle Time (h)", + "multi": false, + "name": "duration", + "options": [ + { + "selected": false, + "text": "0", + "value": "0" + }, + { + "selected": false, + "text": "1", + "value": "1" + }, + { + "selected": false, + "text": "3", + "value": "3" + }, + { + "selected": true, + "text": "6", + "value": "6" + }, + { + "selected": false, + "text": "12", + "value": "12" + }, + { + "selected": false, + "text": "18", + "value": "18" + }, + { + "selected": false, + "text": "24", + "value": "24" + } + ], + "query": "0,1,3,6,12,18,24", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": false, + "text": "km", + "value": "km" + }, + "datasource": "TeslaMate", + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "ideal", + "value": "ideal" + }, + "datasource": "TeslaMate", + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-90d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Vampire Drain", + "uid": "zhHx2Fggk", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate1/visited.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/visited.json new file mode 100644 index 00000000000..08ff417b4e1 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate1/visited.json @@ -0,0 +1,318 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "geomap", + "name": "Geomap", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "targets": [ + { + "datasource": "TeslaMate", + "refId": "A" + } + ], + "title": "$car_id", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 2, + "links": [], + "maxDataPoints": 10000000, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 3, + "max": 15, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "latitude": "lat", + "longitude": "long", + "mode": "auto" + }, + "name": "Layer 1", + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\n to_timestamp(floor((extract('epoch' FROM date) / 60)) * 60) AT TIME ZONE 'UTC' AS time,\n avg(latitude) as latitude,\n avg(longitude) as longitude\nFROM\n positions\nWHERE\n car_id = $car_id\nAND\n $__timeFilter(date)\nGROUP BY\n 1\nORDER BY\n 1\nASC", + "refId": "Positions", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ] + } + } + ], + "title": "MAP", + "type": "geomap" + } + ], + "refresh": false, + "schemaVersion": 38, + "style": "dark", + "tags": ["tesla"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "http://localhost:4000", + "value": "http://localhost:4000" + }, + "datasource": "TeslaMate", + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-90d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Visited", + "uid": "RG_DxSmgk", + "version": 11, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/BatteryHealth.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/BatteryHealth.json new file mode 100644 index 00000000000..2ad8139b02f --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/BatteryHealth.json @@ -0,0 +1,1841 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.4.0" + }, + { + "type": "datasource", + "id": "grafana-postgresql-datasource", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "xychart", + "name": "XY Chart", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "**Usable (now)** is the estimated current battery capacity. It is average of the estimated capacity reported by the last 10 charging sessions to have a better estimation.\n\nIf you see just '1.0 kWh' here, it means that you need at least a long charge session.\n\n**Usable (new)** is the estimated Battery Capacity since you begun to use Teslamate. That's why, the more data you have logged from your brand new car the better. For those who have not used Teslamate since they got their new car, or for those who have bought it second hand, it's possible to set the max range to 100% and the battery capacity of the car battery when it was new in order to get a better and accurate estimation.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + }, + { + "color": "dark-red", + "value": 1 + }, + { + "color": "super-light-blue", + "value": 2 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Usable (new)\", \n ('$aux'::json -> 'CurrentCapacity')::text::float as \"Usable (now)\",\n ('$aux'::json -> 'CurrentCapacity')::text::float - CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Difference\"\n \n \n \n \n \n \n ", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*_km/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/maxrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (new)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/currentrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (now)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/range_lost.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Range lost" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END as \"maxrange_$length_unit\",\n ('$aux'::json -> 'CurrentRange')::text::float as \"currentrange_$length_unit\",\n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END - ('$aux'::json -> 'CurrentRange')::text::float as \"range_lost_$length_unit\"", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ranges", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "\"Logged\" is the distance traveled that is saved on Teslamate database.\n\n\"Mileage\" is the distance the car has traveled since using Teslamate.\n\nSo, if there is a difference between both values, it is the distance that for some reason a drive hasn't been fully recorded, for example due to a bug or an unexpected restart and that Teslamate has not been able to record, either due to lack of connection, areas without signal, or that it has been out of service.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 37, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select ROUND(convert_km(sum(distance)::numeric, '$length_unit'),0)|| ' $length_unit' as \"Logged\"\r\nfrom drives \r\nwhere car_id = $car_id;\r\n", + "refId": "Looged", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ROUND(convert_km((max(odometer) - min(odometer))::numeric, '$length_unit'),0)|| ' $length_unit' as \"Mileage\"\nfrom positions where car_id = $car_id;", + "refId": "Mileage", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ROUND(convert_km(max(odometer)::numeric, '$length_unit'),0) || ' $length_unit' as \"Odometer\"\nfrom positions where car_id = $car_id;", + "refId": "Odometer", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Trips", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 2, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 34, + "maxDataPoints": 3, + "options": { + "displayLabels": ["name", "percent", "value"], + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": false, + "values": ["value"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current,\n\t\tcp.charge_energy_used\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tSUM(GREATEST(charge_energy_added, charge_energy_used)) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Summary AC/DC Energy Used", + "type": "piechart" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to have a look of the Battery health based on the data logged in Teslamate. So, the more data you have logged from your brand new car the better.\n\n**Degradation** is just an estimated value to have a reference, measured on **usable battery level** of every charging session with enough kWh added (in order to avoid dirty data from the sample), calculated according to the rated efficiency of the car.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "red", + "value": 20 + }, + { + "color": "dark-red", + "value": 30 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 17, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "/^greatest$/", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END))\n\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Estimated Degradation", + "type": "gauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "light-green", + "value": 90 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 12, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n LEAST(100, (100 - GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END)))) as \"Battery Health (%)\"\n \n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Health", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "\"Charging cycles\" are estimations based on the whole energy added to the battery.\n\n\"Charge Efficiency\" is estimated on the difference between energy used from the charger and energy added to the battery.", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total energy added" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Total energy used" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Charge Efficiency" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 36, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\r\n\tCOUNT(*) AS \"Total charges\"\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\tcar_id = $car_id AND charge_energy_added > 0.01\r\n\t", + "refId": "Total charges", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tfloor(sum(charge_energy_added) / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END) AS \"Charging cycles\"\nFROM charging_processes WHERE car_id = $car_id AND charge_energy_added > 0.01", + "refId": "Charging cycles", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_added) as \"Total energy added\"\nFROM\n\tcharging_processes\nWHERE\n\tcar_id = $car_id AND charge_energy_added > 0.01", + "refId": "Total energy added", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\r\n\tSUM(charge_energy_used) AS \"Total energy used\"\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\tcar_id = $car_id AND charge_energy_added > 0.01\r\n", + "refId": "Total energy used", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT\r\n\tSUM(charge_energy_added) * 100 / SUM(charge_energy_used) AS \"Charge Efficiency\"\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\tcar_id = $car_id AND charge_energy_added > 0.01\r\n", + "refId": "Charge Efficiency", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Battery Stats", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-orange", + "value": 80 + }, + { + "color": "light-blue", + "value": 100 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 6, + "y": 9 + }, + "id": 25, + "options": { + "displayMode": "lcd", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "text": {}, + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT * FROM ((SELECT usable_battery_level, date\r\nFROM positions\r\nWHERE car_id = $car_id AND usable_battery_level IS NOT NULL\r\nORDER BY date DESC\r\nLIMIT 1)\r\nUNION\r\n(SELECT usable_battery_level, date\r\nFROM charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id\r\nWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL\r\nORDER BY date DESC\r\nLIMIT 1)) AS last_usable_battery_level LIMIT 1", + "refId": "SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current SOC", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "This is the Derived Rated Efficiency that TeslaMate calculates based on battery charges. \nThis information can be seen in more detail on the \"Efficiency\" dashboard.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*_km/" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 9 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT ('$aux'::json -> 'RatedEfficiency')::text::float * \r\n CASE \r\n WHEN '$length_unit' = 'km' THEN 10\r\n WHEN '$length_unit' = 'mi' THEN 16.0934 \r\n END AS efficiency_$length_unit", + "refId": "Looged", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Efficiency", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-green", + "value": 7.84 + }, + { + "color": "semi-dark-orange", + "value": 31.36 + }, + { + "color": "light-blue", + "value": 35.28 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 4, + "x": 6, + "y": 11 + }, + "id": 27, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^kwh$/", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "text": {}, + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT * FROM ((SELECT usable_battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM positions\nWHERE car_id = $car_id AND usable_battery_level IS NOT NULL\nORDER BY date DESC\nLIMIT 1)\nUNION\n(SELECT battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL\nORDER BY date DESC\nLIMIT 1)) AS last_usable_battery_level LIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current Capacity", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-RdYlGr" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 6 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "Median" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 2 + }, + { + "id": "custom.show", + "value": "lines" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "name": "Odometer", + "pointColor": { + "field": "kWh" + }, + "pointSize": { + "fixed": 5, + "max": 100, + "min": 1 + }, + "x": "odometer", + "y": "kWh" + }, + { + "name": "Median Odometer", + "pointColor": { + "fixed": "dark-red" + }, + "x": "M-Odometer", + "y": "M-kWh" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km(AVG(p.odometer)::numeric,'$length_unit') AS odometer, \r\n\tAVG(c.rated_battery_range_km * ('$aux'::json -> 'RatedEfficiency')::text::float / c.usable_battery_level) AS \"kWh\",\r\n\tMAX(cp.id) AS id,\r\n\tto_char(cp.end_date, 'YYYY-MM-dd') AS Title\r\n\tFROM charging_processes cp\r\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges WHERE usable_battery_level > 0 GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\r\n\t\tINNER JOIN charges c\r\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\r\n\t\tINNER JOIN positions p ON p.id = cp.position_id\r\n\tWHERE cp.car_id = $car_id\r\n\t\tAND cp.end_date IS NOT NULL\r\n\t\tAND cp.charge_energy_added >= ('$aux'::json -> 'RatedEfficiency')::text::float\r\n\tGROUP BY 4", + "refId": "Projected Range", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n ROUND(MIN(convert_km(p.odometer::numeric,'$length_unit')),0) AS \"M-Odometer\",\n\tROUND(PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY c.rated_battery_range_km * ('$aux'::json -> 'RatedEfficiency')::text::float / c.usable_battery_level)::numeric,1) AS \"M-kWh\",\n\tto_char(cp.end_date, 'YYYYMM') || CASE WHEN to_char(cp.end_date, 'DD')::int <= 15 THEN '1' ELSE '2' END AS Title\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges WHERE usable_battery_level > 0 GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN positions p ON p.id = cp.position_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.charge_energy_added >= ('$aux'::json -> 'RatedEfficiency')::text::float\n\tGROUP BY 3", + "refId": "Median", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity by Mileage", + "type": "xychart" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT unit_of_length FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "SELECT unit_of_length FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT preferred_range FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "SELECT preferred_range FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT base_url FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "SELECT base_url FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "-- CONCATENATED JOIN QUERIES TO IMPROVE PERFORMANCE\n-- The following query is the result of many tests and hours of work. This panel is for your own personal use. \n-- If you think you can improve it and contribute, please create a pull request and do not take it to your repository, \n-- much less upload it to another repository as if the original idea were yours, nor do you share it on social media\n-- without mentioning the author. Respect the ingenuity and work of others. Cheers!\n-- 2024-03-19\n-- By @jheredianet - Twitter: @juanheredia", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "aux", + "options": [], + "query": "WITH Aux AS\n(\n\t\tSELECT \n car_id,\n\t\tCOALESCE(efficiency, \n\t\t(SELECT efficiency\n\t\t\tFROM cars WHERE id = $car_id) * 100) AS efficiency\n\tFROM (\n\t\tSELECT ROUND((charge_energy_added / NULLIF(end_rated_range_km - start_rated_range_km, 0))::numeric, 3) * 100 as efficiency,\n\t\t\tCOUNT(*) as count, $car_id AS car_id \n\t\tFROM charging_processes\n\t\tWHERE car_id = $car_id\n\t\t\tAND duration_min > 10\n\t\t\tAND end_battery_level <= 95\n\t\t\tAND start_rated_range_km IS NOT NULL\n\t\t\tAND end_rated_range_km IS NOT NULL\n\t\t\tAND charge_energy_added > 0\n\t\tGROUP BY 1\n\t\tORDER BY 2 DESC\n\t\tLIMIT 1\n\t) AS DerivatedEfficiency\n),\nCurrentCapacity\t AS\n(\n\tSELECT AVG(Capacity) AS Capacity\nFROM (\nSELECT \n\tc.[[preferred_range]]_battery_range_km * aux.efficiency / c.usable_battery_level AS Capacity\n\tFROM charging_processes cp\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id \n INNER JOIN aux ON cp.car_id = aux.car_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.charge_energy_added >= aux.efficiency\n\t\tAND c.usable_battery_level > 0\n\t ORDER BY cp.end_date DESC LIMIT 10) AS lastCharges\n), \nMaxCapacity AS\n(\n\tSELECT \n\t\tMAX(c.[[preferred_range]]_battery_range_km * aux.efficiency / c.usable_battery_level) AS Capacity\n\tFROM charging_processes cp\n\t\tINNER JOIN (\n\t\t\tSELECT charging_process_id, MAX(date) as date FROM charges WHERE usable_battery_level > 0 GROUP BY charging_process_id) AS gcharges\t\n\t\t\tON cp.id = gcharges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = gcharges.date\n\t\tINNER JOIN aux ON cp.car_id = aux.car_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.charge_energy_added >= aux.efficiency\n), \nCurrentRange AS\n(\n SELECT (range * 100.0 / usable_battery_level) AS range\n\tFROM (\n\t\t(SELECT date, [[preferred_range]]_battery_range_km AS range, usable_battery_level AS usable_battery_level\n\t\t\tFROM positions\tWHERE car_id = $car_id AND [[preferred_range]]_battery_range_km IS NOT NULL AND usable_battery_level > 0 ORDER BY date DESC LIMIT 1)\n\t\tUNION ALL\n\t\t(SELECT date, [[preferred_range]]_battery_range_km AS range, usable_battery_level as usable_battery_level\n\t\t\tFROM charges c JOIN charging_processes p ON p.id = c.charging_process_id\n\t\t\tWHERE p.car_id = $car_id AND usable_battery_level > 0 ORDER BY date DESC LIMIT 1)\n\t) AS data\n\tORDER BY date DESC\n\tLIMIT 1\n), \nMaxRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS time,\n\t CASE WHEN sum(usable_battery_level) = 0 THEN sum([[preferred_range]]_battery_range_km) * 100\n\t\t ELSE sum([[preferred_range]]_battery_range_km) / sum(usable_battery_level) * 100\n\tEND AS range\n FROM (\n\t\tSELECT battery_level, usable_battery_level, date, [[preferred_range]]_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 2 DESC\n\tLIMIT 1\n) \nSELECT CONCAT('{\"MaxRange\": ', convert_km(MaxRange.range,'$length_unit'),\n ', \"CurrentRange\": ',convert_km(CurrentRange.range,'$length_unit'),\n ', \"MaxCapacity\": ', MaxCapacity.Capacity,\n ', \"CurrentCapacity\": ', CASE WHEN CurrentCapacity.Capacity IS NULL THEN 1 ELSE CurrentCapacity.Capacity END,\n ', \"RatedEfficiency\": ', aux.efficiency, '}') \nFROM MaxRange, CurrentRange, Aux, MaxCapacity, CurrentCapacity", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the capacity of your car battery when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, it will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Battery Capacity (kWh) when new", + "name": "custom_kwh_new", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the max range to 100% of your car when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, the degradation will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Max Range when new", + "name": "custom_max_range", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "timepicker": { + "hidden": true + }, + "timezone": "browser", + "title": "Battery Health V2", + "uid": "jchmRiqUfXgRx", + "version": 23, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/BrowseCharges.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/BrowseCharges.json new file mode 100644 index 00000000000..673f9f3e164 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/BrowseCharges.json @@ -0,0 +1,1486 @@ +{ + "__elements": [], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.5.15" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "iteration": 1686816148286, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "Browse your charges by Geofence, Location, Type, Cost and Duration in order to have an accurate Total of kWh added and their respective costs", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "displayMode": "auto", + "filterable": false, + "inspect": false, + "minWidth": 150 + }, + "decimals": 2, + "displayName": "", + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "View charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}&var-car_id=${__data.fields.car_id.numeric}&var-charging_process_id=${__data.fields.id.numeric}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 160 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added" + }, + "properties": [ + { + "id": "displayName", + "value": "Added" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.minWidth", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "start_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "% Start" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.minWidth", + "value": 62 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_battery_level" + }, + "properties": [ + { + "id": "displayName", + "value": "% End" + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.minWidth", + "value": 62 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "m" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 75 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_avg_c" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "celsius" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#C0D8FF", + "value": null + }, + { + "color": "#C8F2C2", + "value": 10 + }, + { + "color": "#FFA6B0", + "value": 20 + } + ] + } + }, + { + "id": "custom.minWidth", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost" + }, + "properties": [ + { + "id": "displayName", + "value": "Cost" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": false, + "title": "Set Cost", + "url": "[[base_url:raw]]/charge-cost/${__data.fields.id.numeric}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "noValue", + "value": "-" + }, + { + "id": "custom.minWidth", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "address" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + }, + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Create or edit geo-fence", + "url": "[[base_url:raw]]/geo-fences/${__data.fields.path}" + } + ] + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 300 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Driven" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.minWidth", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_added_per_hour" + }, + "properties": [ + { + "id": "displayName", + "value": "kW" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.align" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "#96D98D", + "value": null + }, + { + "color": "#56A64B", + "value": 20 + }, + { + "color": "#37872D", + "value": 55 + } + ] + } + }, + { + "id": "custom.minWidth", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_added_per_hour_km" + }, + "properties": [ + { + "id": "displayName", + "value": "km / h" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.minWidth", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_avg_f" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Driven" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "custom.align" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.minWidth", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_added_per_hour_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "mi / h" + }, + { + "id": "unit", + "value": "none" + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 70 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "path" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Used" + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.minWidth", + "value": 85 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charging_efficiency" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.displayMode", + "value": "basic" + }, + { + "id": "color", + "value": { + "mode": "continuous-RdYlGr" + } + }, + { + "id": "max", + "value": 1 + }, + { + "id": "custom.minWidth", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "car_id" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_date" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align" + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cost_per_kwh" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "displayName", + "value": "Cost/kWh" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "noValue", + "value": "-" + }, + { + "id": "custom.minWidth", + "value": 80 + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_type" + }, + "properties": [ + { + "id": "displayName", + "value": "Type" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.minWidth", + "value": 40 + } + ] + } + ] + }, + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 6, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts,\n (round(extract(epoch FROM end_date) + 10) * 1000) AS end_date_ts,\n start_date,\n end_date,\n CONCAT_WS(', ', COALESCE(addresses.name, nullif(CONCAT_WS(' ', addresses.road, addresses.house_number), '')), addresses.city) AS address,\n g.name as geofence_name,\n g.id as geofence_id,\n p.latitude,\n p.longitude,\n cp.charge_energy_added,\n cp.charge_energy_used,\n duration_min,\n start_battery_level,\n end_battery_level,\n start_[[preferred_range]]_range_km,\n end_[[preferred_range]]_range_km,\n outside_temp_avg,\n cp.id,\n lag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n p.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance,\n cars.efficiency,\n cp.car_id,\n cost,\n max(c.charger_voltage) as max_charger_voltage,\n CASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC' ELSE 'AC' END AS charge_type\n FROM\n charging_processes cp\n\t LEFT JOIN charges c ON cp.id = c.charging_process_id\n LEFT JOIN positions p ON p.id = cp.position_id\n LEFT JOIN cars ON cars.id = cp.car_id\n LEFT JOIN addresses ON addresses.id = cp.address_id\n LEFT JOIN geofences g ON g.id = geofence_id\nWHERE \n cp.car_id = $car_id AND\n $__timeFilter(start_date) AND\n (cp.charge_energy_added IS NULL OR cp.charge_energy_added > 0) AND\n ('${geofence:pipe}' = '-1' OR geofence_id in ($geofence))\nGROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,21,p.odometer\nORDER BY\n start_date\n)\nSELECT\n start_date_ts,\n end_date_ts,\n CASE WHEN geofence_id IS NULL THEN CONCAT('new?lat=', latitude, '&lng=', longitude)\n WHEN geofence_id IS NOT NULL THEN CONCAT(geofence_id, '/edit')\n END as path,\n car_id,\n id,\n -- Columns\n start_date,\n end_date,\n COALESCE(geofence_name, address) as address, \n charge_type,\n duration_min,\n cost,\n cost / NULLIF(greatest(charge_energy_added, charge_energy_used), 0) as cost_per_kwh,\n charge_energy_added,\n charge_energy_used,\n CASE WHEN charge_energy_used IS NULL THEN NULL ELSE LEAST(charge_energy_added / NULLIF(charge_energy_used, 0), 1.0) END as charging_efficiency,\n convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_avg_$temp_unit,\n charge_energy_added * 60 / NULLIF (duration_min, 0) AS charge_energy_added_per_hour,\n convert_km((end_[[preferred_range]]_range_km - start_[[preferred_range]]_range_km) * 60 / NULLIF (duration_min, 0), '$length_unit') AS range_added_per_hour_$length_unit,\n start_battery_level,\n end_battery_level,\n convert_km(distance::numeric, '$length_unit') AS distance_$length_unit\n FROM\n data\nWHERE\n (distance >= 0 OR distance IS NULL)\n AND duration_min >= '$min_duration_min'\n AND CASE WHEN $cost = 0 THEN (cost IS NULL OR cost >= 0) ELSE cost >= $cost END\n AND charge_type = ANY(CASE WHEN array_to_string(ARRAY[$charge_type], ',') = 'DC' THEN ARRAY['DC'] WHEN array_to_string(ARRAY[$charge_type], ',') = 'AC' THEN ARRAY['AC'] ELSE ARRAY['DC', 'AC'] END)\n AND address ILIKE '%$location%'\nORDER BY\n start_date DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charges: $charge_type", + "transformations": [], + "type": "table" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 7, + "x": 0, + "y": 21 + }, + "id": 10, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 6, + "refId": "A" + } + ], + "title": "Energy added", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": ["charge_energy_added"] + } + } + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 7, + "x": 7, + "y": 21 + }, + "id": 12, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 6, + "refId": "A" + } + ], + "title": "Energy used", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": ["charge_energy_used"] + } + } + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 14, + "y": 21 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 6, + "refId": "A" + } + ], + "title": "Cost", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": ["cost"] + } + } + } + ], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "m" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 19, + "y": 21 + }, + "id": 15, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 6, + "refId": "A" + } + ], + "title": "Average Duration", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": ["duration_min"] + } + } + } + ], + "transparent": true, + "type": "stat" + } + ], + "refresh": "", + "schemaVersion": 36, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "-1", + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM geofences ORDER BY name COLLATE \"C\" ASC;", + "hide": 0, + "includeAll": true, + "label": "Geofence", + "multi": true, + "name": "geofence", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM geofences ORDER BY name COLLATE \"C\" ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "description": "Type a text contained in Location", + "hide": 0, + "label": "Location", + "name": "location", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "skipUrlSync": false, + "type": "textbox" + }, + { + "allValue": "", + "current": { + "selected": true, + "text": ["All"], + "value": ["$__all"] + }, + "hide": 0, + "includeAll": true, + "label": "Type", + "multi": true, + "name": "charge_type", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "AC", + "value": "AC" + }, + { + "selected": false, + "text": "DC", + "value": "DC" + } + ], + "query": "AC, DC", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "Cost >=", + "name": "cost", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": true, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "Duration (minutes) >=", + "name": "min_duration_min", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-1M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Browse Charges", + "uid": "jchmTSmNYvRRk", + "version": 4, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCostsStats.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCostsStats.json new file mode 100644 index 00000000000..459607f6d62 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCostsStats.json @@ -0,0 +1,3404 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.4.0" + }, + { + "type": "datasource", + "id": "grafana-postgresql-datasource", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:75", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [], + "title": "Summary", + "type": "row" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 1 + }, + "id": 10, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_used)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;\n", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Energy Used", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 1 + }, + "id": 33, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_used)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\n\tAND cost = 0;\n", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Free Energy", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 1 + }, + "id": 64, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH energy as(\r\nSELECT\r\n\tsum(charge_energy_used) AS charged_kWh\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\t$__timeFilter(end_date)\r\n\tAND car_id = $car_id),\r\nsince as (\r\n\tSELECT date FROM positions\r\n\tWHERE car_id = $car_id\r\n\tORDER BY date ASC\r\n\tLIMIT 1\r\n)\r\nSELECT (energy.charged_kWh / $distance_driven) as \"kwh_per_$length_unit\" FROM energy", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "kWh per $length_unit", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + }, + "unit": "times" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 1 + }, + "id": 38, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tcount(*)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND charge_energy_used > 0.01\n\tAND car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Charges", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "For this section, it's important that you have geo-fences called \"Home\" and \"Work\" if you want to see a bar with the energy charged on those places.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 49, + "options": { + "displayMode": "gradient", + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "vertical", + "reduceOptions": { + "calcs": [], + "fields": "/^energy$/", + "values": true + }, + "showUnfilled": false, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT location, SUM(charge_energy_used) AS Energy\r\nFROM (\r\nSELECT\r\n CASE\r\n WHEN COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.display_name), '')))) ILIKE '%Home%' THEN COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.display_name), ''))))\r\n\t WHEN COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.display_name), '')))) ILIKE '%Work%' THEN COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.display_name), ''))))\r\n\t WHEN COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.display_name), '')))) ILIKE '%supercharger%' THEN 'Superchargers'\r\n\t ELSE 'Other'\r\n END AS location, charge_energy_used\r\nFROM\r\n\tcharging_processes c\r\nLEFT JOIN addresses address ON c.address_id = address.id\r\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\r\nWHERE\r\n\t car_id = $car_id\r\n\tAND $__timeFilter(end_date)\r\n\tAND c.charge_energy_used > 0\r\n) ChargeLocations\r\nGROUP BY location\r\nORDER BY Energy DESC", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Main locations", + "type": "bargauge" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to have a look of all the charges in a given period (last 10 years by default). You can see the distance driven, number of charges, total charging cost, etc., both in summary or in separated lists.\n\nYou can expand/collapse the rows as needed.\n\nFrom the Monthly Stats row, you will have a table with links to other Teslamate Dashboards to have a look on a specific period, charge or trip.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 2, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 51, + "maxDataPoints": 3, + "options": { + "displayLabels": ["name", "percent", "value"], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_used,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_used > 0.01\n\t AND $__timeFilter(start_date)\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(charge_energy_used) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Summary AC/DC Energy Used", + "type": "piechart" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "Use the dropdown at the top to choose the Geofence to display energy added from", + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 4 + }, + "id": 66, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH free_energy AS (\r\nSELECT sum(charge_energy_used) AS free_charged_kWh\r\nFROM charging_processes cp\r\nINNER JOIN geofences g ON g.id = cp.geofence_id\r\nWHERE\r\n\t$__timeFilter(end_date)\r\n\tAND car_id = $car_id AND g.name = '$geofence'\r\nGROUP BY g.name),\r\nenergy as(\r\nSELECT\r\n\tsum(charge_energy_used) AS charged_kWh\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\t$__timeFilter(end_date)\r\n\tAND car_id = $car_id\r\n)\r\nSELECT ($distance_driven * free_energy.free_charged_kWh / energy.charged_kWh) as \"distance_$length_unit\" FROM energy, free_energy", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Added at $geofence", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 4 + }, + "id": 65, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH free_energy AS (\r\nSELECT sum(charge_energy_used) AS free_charged_kWh\r\nFROM charging_processes\r\nWHERE\r\n\t$__timeFilter(end_date)\r\n\tAND car_id = $car_id\r\n\tAND cost = 0),\r\nenergy as(\r\nSELECT\r\n\tsum(charge_energy_used) AS charged_kWh\r\nFROM\r\n\tcharging_processes\r\nWHERE\r\n\t$__timeFilter(end_date)\r\n\tAND car_id = $car_id\r\n)\r\nSELECT ($distance_driven * free_energy.free_charged_kWh / energy.charged_kWh) as \"distance_$length_unit\" FROM energy, free_energy", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Added free (no cost)", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 4 + }, + "id": 67, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH suc_data AS (\r\n\tSELECT c.charging_process_id\r\n\tFROM charges c\r\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\r\n\tLEFT JOIN addresses addr ON addr.id = cp.address_id\r\n\tLEFT JOIN geofences geo ON geo.id = geofence_id\r\n\tWHERE \r\n cp.car_id = $car_id AND c.fast_charger_present\r\n\t\tAND COALESCE(geo.name, CONCAT_WS(', ', COALESCE(addr.name, nullif(CONCAT_WS(' ', addr.display_name), '')))) ILIKE '%supercharger%'\r\n AND $__timeFilter(end_date)\r\n\tGROUP BY 1\r\n), suc_energy AS (\r\n SELECT coalesce(sum(charge_energy_used), 0) AS charged_kWh\r\n FROM charging_processes cp\r\n INNER JOIN suc_data ON suc_data.charging_process_id = cp.id\r\n), energy AS(\r\n SELECT\r\n\t sum(charge_energy_used) AS charged_kWh\r\n FROM charging_processes\r\n WHERE $__timeFilter(end_date)\tAND car_id = $car_id\r\n)\r\nSELECT ($distance_driven * suc_energy.charged_kWh / energy.charged_kWh) as \"distance_$length_unit\" FROM energy, suc_energy;\r\n", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Added at SuC", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 4 + }, + "id": 36, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["sum"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $distance_driven as \"distance_$length_unit\"", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Driven", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 7 + }, + "id": 56, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $ACCost\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Cost at AC Stations", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 7 + }, + "id": 44, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $DCCost\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Cost at DC Stations", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 7 + }, + "id": 14, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $SucCost", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charging Cost at SuC", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 7 + }, + "id": 27, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $TotalCost\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Charging Costs", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "", + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 10 + }, + "id": 40, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT (\n SELECT sum(cost)\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n) / $distance_driven * 100", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Cost per 100 $length_unit", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 10 + }, + "id": 42, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT (\n SELECT sum(cost)\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n) / (\n SELECT sum(greatest(charge_energy_used, charge_energy_used))\n FROM charging_processes\n WHERE $__timeFilter(end_date) AND car_id = $car_id\n)", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average kWh Cost", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "Net is the efficiency while driving", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-orange", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 10 + }, + "id": 69, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n sum((start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km) * cars.efficiency) / sum(distance) * 1000 * \n CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END AS \"consumption_$length_unit\"\nfrom drives \ninner join cars on cars.id = car_id\nwhere \n distance is not null and\n start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km >= 0.1 and\n car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Consumption (net)", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "Gross is all consumption (including while idle, phantom drains, sentry mode, etc)", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-orange", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 10 + }, + "id": 71, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value", + "wideLayout": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d1 AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM\n\t\tcharging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id\n\tORDER BY\n\t\tstart_date\n),\nd2 AS (\nSELECT\n\tcar_id,\n\tsum(range_loss) AS range_loss,\n\tsum(distance) AS distance\nFROM\n\td1\nWHERE\n\tdistance >= 0 AND range_loss >= 0\nGROUP BY\n\tcar_id\n)\nSELECT\nrange_loss * c.efficiency / distance * 1000 *\n CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END AS \"consumption_$length_unit\"\nFROM\n\td2\n\tLEFT JOIN cars c ON c.id = car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Consumption (gross) ", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 60, + "panels": [], + "title": "Top 10 Charges", + "type": "row" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Charged" + }, + { + "id": "custom.width", + "value": 110 + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 6, + "x": 0, + "y": 14 + }, + "id": 46, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS location,\n\tCASE\n WHEN SUM(charge_energy_used) < 1000 THEN SUM(charge_energy_used)::NUMERIC(4,0)::VARCHAR || ' kWh' \n WHEN SUM(charge_energy_used) < 1000000 THEN (SUM(charge_energy_used) / 1000)::NUMERIC(9, 3)::VARCHAR || ' MWh' \n WHEN SUM(charge_energy_used) >= 1000000 THEN (SUM(charge_energy_used) / 1000000)::NUMERIC(9, 3)::VARCHAR || ' GWh' \n END as charge_energy_used, sum(cost) as \"Cost\"\nFROM\n\tcharging_processes c\nLEFT JOIN addresses address ON c.address_id = address.id\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\n\tAND charge_energy_used > 0\nGROUP BY\n\t1\nORDER BY\n\tSUM(charge_energy_used) DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top 10 General Charging Stations (Charged)", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Charged" + }, + { + "id": "custom.width", + "value": 110 + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 6, + "x": 6, + "y": 14 + }, + "id": 4, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS location,\n\tCASE\n WHEN SUM(charge_energy_used) < 1000 THEN SUM(charge_energy_used)::NUMERIC(4,0)::VARCHAR || ' kWh' \n WHEN SUM(charge_energy_used) < 1000000 THEN (SUM(charge_energy_used) / 1000)::NUMERIC(9, 3)::VARCHAR || ' MWh' \n WHEN SUM(charge_energy_used) >= 1000000 THEN (SUM(charge_energy_used) / 1000000)::NUMERIC(9, 3)::VARCHAR || ' GWh' \n END as charge_energy_used, sum(cost) as \"Cost\"\nFROM\n\tcharging_processes c\nLEFT JOIN addresses address ON c.address_id = address.id\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\n\tAND cost > 0\n\tAND charge_energy_used > 0\nGROUP BY\n\t1\nORDER BY\n\tSUM(charge_energy_used) DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top 10 Paid Stations (Charged)", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Charged" + }, + { + "id": "custom.width", + "value": 110 + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 6, + "x": 12, + "y": 14 + }, + "id": 34, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS location,\n\tCASE\n WHEN SUM(charge_energy_used) < 1000 THEN SUM(charge_energy_used)::NUMERIC(4,0)::VARCHAR || ' kWh' \n WHEN SUM(charge_energy_used) < 1000000 THEN (SUM(charge_energy_used) / 1000)::NUMERIC(9, 3)::VARCHAR || ' MWh' \n WHEN SUM(charge_energy_used) >= 1000000 THEN (SUM(charge_energy_used) / 1000000)::NUMERIC(9, 3)::VARCHAR || ' GWh' \n END as charge_energy_used, sum(cost) as \"Cost\"\nFROM\n\tcharging_processes c\nLEFT JOIN addresses address ON c.address_id = address.id\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\n\tAND charge_energy_used > 0\n\tAND COALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.display_name), '')))) ILIKE '%supercharger%'\nGROUP BY\n\t1\nORDER BY\n\tSUM(charge_energy_used) DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top 10 SuperCharger Stations (Charged)", + "type": "table" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "location" + }, + "properties": [ + { + "id": "displayName", + "value": "Location" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "charge_energy_used" + }, + "properties": [ + { + "id": "displayName", + "value": "Charged" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Cost" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 6, + "x": 18, + "y": 14 + }, + "id": 32, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.4.0", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCOALESCE(geofence.name, CONCAT_WS(', ', COALESCE(address.name, nullif(CONCAT_WS(' ', address.road, address.house_number), '')), address.city)) AS location,\n\tCASE\n WHEN SUM(charge_energy_used) < 1000 THEN SUM(charge_energy_used)::NUMERIC(4,0)::VARCHAR || ' kWh' \n WHEN SUM(charge_energy_used) < 1000000 THEN (SUM(charge_energy_used) / 1000)::NUMERIC(9, 3)::VARCHAR || ' MWh' \n WHEN SUM(charge_energy_used) >= 1000000 THEN (SUM(charge_energy_used) / 1000000)::NUMERIC(9, 3)::VARCHAR || ' GWh' \n END as charge_energy_used, sum(cost) as \"Cost\"\nFROM\n\tcharging_processes c\nLEFT JOIN addresses address ON c.address_id = address.id\nLEFT JOIN geofences geofence ON geofence_id = geofence.id\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id\n\tAND charge_energy_used > 0\n\tAND cost = 0\nGROUP BY\n\t1\nORDER BY\n\tSUM(charge_energy_used) DESC\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top 10 Free Stations (Charged)", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 62, + "panels": [], + "title": "Monthly Stats", + "type": "row" + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false, + "width": 120 + }, + "mappings": [], + "noValue": "--", + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 50 + }, + { + "color": "green", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time driven" + }, + "properties": [ + { + "id": "unit", + "value": "clocks" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Period" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Trip", + "url": "d/FkUpJpQZk/trip?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Efficiency" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "thresholds", + "value": { + "mode": "percentage", + "steps": [ + { + "color": "super-light-orange", + "value": null + }, + { + "color": "light-orange", + "value": 65 + }, + { + "color": "light-green", + "value": 99 + } + ] + } + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Energy used" + }, + "properties": [ + { + "id": "decimals", + "value": 1 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Charging stats", + "url": "d/-pkIkhmRz/charging-stats?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + }, + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Avg charged" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Costs" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.align", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "# charges" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Charges", + "url": "d/TSmNYvRRk/charges?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "# drives" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Drives", + "url": "d/Y8upc6ZRk/drives?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_km/" + }, + "properties": [ + { + "id": "unit", + "value": "km" + }, + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-GrYlRd" + } + }, + { + "id": "max", + "value": 8000 + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/avg_outside_temp_c/" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + }, + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + }, + { + "color": "super-light-green", + "value": 10 + }, + { + "color": "super-light-red", + "value": 20 + } + ] + } + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + }, + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-GrYlRd" + } + }, + { + "id": "max", + "value": 8000 + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_net_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (drives)" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_charged_net_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (charges)" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.* at/" + }, + "properties": [ + { + "id": "unit", + "value": "dateTimeAsSystem" + }, + { + "id": "custom.width" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_net_km/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (drives)" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/efficiency_charged_net_km/" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg consumption (charges)" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "noValue", + "value": "--" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "NaN": { + "index": 0, + "text": "--" + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/avg_outside_temp_f/" + }, + "properties": [ + { + "id": "displayName", + "value": "Temperature" + }, + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "date_from" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "date_to" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 15, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 58, + "maxPerRow": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "frameIndex": 1, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.4.0", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\nSELECT\n duration_min > 1 AND\n distance > 1 AND\n ( \n start_position.usable_battery_level IS NULL OR\n (end_position.battery_level - end_position.usable_battery_level) = 0 \n ) AS is_sufficiently_precise,\n NULLIF(GREATEST(start_ideal_range_km - end_ideal_range_km, 0), 0) AS range_diff,\n date_trunc('month', (start_date::TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE '$timezone') as local_period,\n drives.*\nFROM drives\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('month', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('month', local_period + ('1 ' || 'month')::INTERVAL))*1000 AS date_to,\n CASE 'month'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n convert_km(max(end_km)::integer - min(start_km)::integer, '$length_unit') AS sum_distance_$length_unit,\n convert_celsius(avg(outside_temp_avg), '$temp_unit') AS avg_outside_temp_$temp_unit,\n sum(distance)/sum(range_diff) AS efficiency\nFROM data WHERE\n car_id = $car_id\nGROUP BY date\nORDER BY date DESC", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n charging_processes.*,\n date_trunc('month', (start_date::TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE '$timezone') as local_period\n FROM charging_processes)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('month', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('month', local_period + ('1 ' || 'month')::INTERVAL))*1000 AS date_to,\n CASE 'month'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n sum(greatest(charge_energy_used,charge_energy_used)) AS sum_consumption_kwh,\n sum(greatest(charge_energy_used,charge_energy_used)) / count(*) AS avg_consumption_kwh,\n sum(cost) AS cost_charges,\n count(*) AS cnt_charges\nFROM data WHERE\n car_id = $car_id AND\n (charge_energy_used IS NULL OR charge_energy_used > 0.1)\nGROUP BY date\nORDER BY date", + "refId": "B", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n drives.*,\n date_trunc('month', (start_date::TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE '$timezone') as local_period\n FROM drives)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('month', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('month', local_period + ('1 ' || 'month')::INTERVAL))*1000 AS date_to,\n CASE 'month'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n sum(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0) * car.efficiency * 1000) / \n convert_km(sum(distance)::numeric, '$length_unit') as efficiency_net_$length_unit\nFROM data\nJOIN cars car ON car.id = car_id\nWHERE\n car_id = $car_id\nGROUP BY date\nORDER BY date", + "refId": "C", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Stats per month", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "seriesToColumns", + "options": { + "byField": "date" + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_km_temp", + "binary": { + "left": "sum_consumption_kwh", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_km" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": false + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_km", + "binary": { + "left": "efficiency_charged_net_km_temp", + "operator": "*", + "reducer": "sum", + "right": "1000" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_mi_temp", + "binary": { + "left": "sum_consumption_kwh", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_mi" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": false + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_mi", + "binary": { + "left": "efficiency_charged_net_mi_temp", + "operator": "*", + "reducer": "sum", + "right": "1000" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "date": true, + "date_from": false, + "date_to": false, + "efficiency_charged_net_km_temp": true, + "efficiency_charged_net_mi_temp": true, + "timezone": true + }, + "indexByName": { + "avg_consumption_kwh": 8, + "avg_outside_temp_c": 3, + "cnt_charges": 7, + "cost_charges": 5, + "date": 1, + "date_from": 11, + "date_to": 12, + "display": 0, + "efficiency": 4, + "efficiency_charged_net_km": 10, + "efficiency_charged_net_km_temp": 13, + "efficiency_net_km": 9, + "sum_consumption_kwh": 6, + "sum_distance_km": 2 + }, + "renameByName": { + "avg_consumption_kwh": "Avg charged", + "avg_outside_temp_c": "", + "cnt": "# drives", + "cnt_charges": "# charges", + "cost_charges": "Costs", + "date": "Starting at", + "date_from": "", + "date_to": "", + "display": "Period", + "efficiency": "Efficiency", + "efficiency_net_km": "", + "sum_consumption_kwh": "Energy used", + "sum_distance_km": "", + "sum_duration_h": "Time driven" + } + } + } + ], + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT\n\tcoalesce(sum(cost), 0)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;\n\t", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "TotalCost", + "options": [], + "query": "SELECT\n\tcoalesce(sum(cost), 0)\nFROM\n\tcharging_processes\nWHERE\n\t$__timeFilter(end_date)\n\tAND car_id = $car_id;\n\t", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "WITH data AS (\n\tSELECT c.charging_process_id \n\tFROM charges c\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\n\tLEFT JOIN addresses addr ON addr.id = cp.address_id\n\tLEFT JOIN geofences geo ON geo.id = geofence_id\n\tWHERE \n\t cp.car_id = $car_id AND c.fast_charger_present\n\t\tAND COALESCE(geo.name, CONCAT_WS(', ', COALESCE(addr.name, nullif(CONCAT_WS(' ', addr.display_name), '')))) ILIKE '%supercharger%'\n\tGROUP BY 1\n)\nSELECT\n coalesce(sum(cp.cost), 0)\nFROM\n\tcharging_processes cp, data\nWHERE\n $__timeFilter(end_date)\n AND cp.id IN (data.charging_process_id);", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "SucCost", + "options": [], + "query": "WITH data AS (\n\tSELECT c.charging_process_id \n\tFROM charges c\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\n\tLEFT JOIN addresses addr ON addr.id = cp.address_id\n\tLEFT JOIN geofences geo ON geo.id = geofence_id\n\tWHERE \n\t cp.car_id = $car_id AND c.fast_charger_present\n\t\tAND COALESCE(geo.name, CONCAT_WS(', ', COALESCE(addr.name, nullif(CONCAT_WS(' ', addr.display_name), '')))) ILIKE '%supercharger%'\n\tGROUP BY 1\n)\nSELECT\n coalesce(sum(cp.cost), 0)\nFROM\n\tcharging_processes cp, data\nWHERE\n $__timeFilter(end_date)\n AND cp.id IN (data.charging_process_id);", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "WITH data AS (\n\tSELECT c.charging_process_id \n\tFROM charges c\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\n\tWHERE \n cp.car_id = $car_id AND c.fast_charger_present\n\tGROUP BY 1\n)\nSELECT\n coalesce(sum(cp.cost) - $SucCost , 0)\t\nFROM\n\tcharging_processes cp, data\nWHERE\n $__timeFilter(end_date)\n AND cp.id IN (data.charging_process_id);", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "DCCost", + "options": [], + "query": "WITH data AS (\n\tSELECT c.charging_process_id \n\tFROM charges c\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\n\tWHERE \n cp.car_id = $car_id AND c.fast_charger_present\n\tGROUP BY 1\n)\nSELECT\n coalesce(sum(cp.cost) - $SucCost , 0)\t\nFROM\n\tcharging_processes cp, data\nWHERE\n $__timeFilter(end_date)\n AND cp.id IN (data.charging_process_id);", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "WITH data AS (\n\tSELECT c.charging_process_id \n\tFROM charges c\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\n\tWHERE \n\t\tcp.car_id = $car_id AND NOT c.fast_charger_present\n GROUP BY 1\n)\nSELECT\n coalesce(sum(cp.cost) , 0)\nFROM\n\tcharging_processes cp, data\nWHERE\n $__timeFilter(end_date)\n AND cp.cost IS NOT NULL\n AND cp.id IN (data.charging_process_id);", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "ACCost", + "options": [], + "query": "WITH data AS (\n\tSELECT c.charging_process_id \n\tFROM charges c\n\tLEFT JOIN charging_processes cp ON cp.id = c.charging_process_id\n\tWHERE \n\t\tcp.car_id = $car_id AND NOT c.fast_charger_present\n GROUP BY 1\n)\nSELECT\n coalesce(sum(cp.cost) , 0)\nFROM\n\tcharging_processes cp, data\nWHERE\n $__timeFilter(end_date)\n AND cp.cost IS NOT NULL\n AND cp.id IN (data.charging_process_id);", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "select current_setting('TIMEZONE'), name from pg_timezone_names where abbrev ~ '^[a-zA-Z]{3,4}$' and name not like 'posix%' order by 2;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "timezone", + "options": [], + "query": "select current_setting('TIMEZONE'), name from pg_timezone_names where abbrev ~ '^[a-zA-Z]{3,4}$' and name not like 'posix%' order by 2;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT convert_km((max(odometer) - min(odometer))::numeric, '$length_unit')\nfrom positions where car_id = $car_id AND $__timeFilter(date)", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "distance_driven", + "options": [], + "query": "SELECT convert_km((max(odometer) - min(odometer))::numeric, '$length_unit')\nfrom positions where car_id = $car_id AND $__timeFilter(date)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "TeslaMate" + }, + "definition": "SELECT name FROM geofences ORDER BY id", + "description": "Geofence to display energy added at", + "hide": 0, + "includeAll": false, + "label": "Geofence", + "multi": false, + "name": "geofence", + "options": [], + "query": "SELECT name FROM geofences ORDER BY id", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-10y", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charging Costs Stats", + "uid": "jchmDdLe5uFVk", + "version": 16, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCurveStats.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCurveStats.json new file mode 100644 index 00000000000..e5f60191d7c --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ChargingCurveStats.json @@ -0,0 +1,870 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "barchart", + "name": "Bar chart", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "xychart", + "name": "XY Chart", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:75", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd", + "seriesBy": "last" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 10 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date.numeric}&to=${__data.fields.end_date.numeric}&var-car_id=${car_id}&var-charging_process_id=${__data.fields.charging_process_id.numeric}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 29, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "field": "Power [kW]", + "fixed": "super-light-yellow" + }, + "pointSize": { + "fixed": 2, + "max": 100, + "min": 1 + }, + "x": "SOC [%]", + "y": "Power [kW]" + }, + { + "pointColor": { + "field": "B - SOC [%]" + }, + "pointSize": { + "fixed": 12, + "max": 100, + "min": 1 + }, + "x": "B - SOC [%]", + "y": "B - Avg Power [kW]" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.11", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n c.battery_level as \"SOC [%]\",\r\n round(avg(c.charger_power), 0) as \"Power [kW]\",\r\n c.charging_process_id as \"charging_process_id\",\r\n COALESCE(g.name, a.name) || ' ' || to_char(c.date, 'YYYY-MM-dd') as \"Charge\",\r\n p.start_date as \"start_date\",\r\n p.end_date as \"end_date\"\r\nFROM\r\n charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id \r\nJOIN addresses a ON a.id = p.address_id\r\nLEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n $__timeFilter(date)\r\n AND p.car_id = $car_id\r\n AND c.battery_level >= $filter_soc_from AND c.battery_level <= $filter_soc_to\r\n AND charger_power >= $filter_power_from AND charger_power <= $filter_power_to\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%supercharger%' \r\nGROUP BY c.battery_level, c.charging_process_id, a.name, g.name, p.start_date, p.end_date, to_char(c.date, 'YYYY-MM-dd')", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n c.battery_level as \"B - SOC [%]\",\n PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY charger_power) as \"B - Avg Power [kW]\"\nFROM\n charges c\nJOIN charging_processes p ON p.id = c.charging_process_id \nJOIN addresses a ON a.id = p.address_id\nLEFT JOIN geofences g ON g.id = p.geofence_id\nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND c.battery_level >= $filter_soc_from AND c.battery_level <= $filter_soc_to\n AND charger_power >= $filter_power_from AND charger_power <= $filter_power_to\n AND c.fast_charger_present\n AND COALESCE(g.name, a.name) ILIKE '%supercharger%' \nGROUP BY battery_level", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Supercharger Charging Curve", + "type": "xychart" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-YlRd" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 3 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date.numeric}&to=${__data.fields.end_date.numeric}&var-car_id=${car_id}&var-charging_process_id=${__data.fields.charging_process_id.numeric}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 32, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "series": [ + { + "pointColor": { + "field": "Power [kW]" + }, + "pointSize": { + "fixed": 2, + "max": 100, + "min": 1 + }, + "x": "SOC [%]", + "y": "Power [kW]" + }, + { + "pointColor": { + "field": "B - Avg Power [kW]" + }, + "pointSize": { + "fixed": 10, + "max": 100, + "min": 1 + }, + "x": "B - SOC [%]", + "y": "B - Avg Power [kW]" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "7.5.11", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n c.battery_level as \"SOC [%]\",\r\n round(avg(c.charger_power), 0) as \"Power [kW]\",\r\n c.charging_process_id as \"charging_process_id\",\r\n COALESCE(g.name, a.name) || ' ' || to_char(c.date, 'YYYY-MM-dd') as \"Charge\",\r\n p.start_date as \"start_date\",\r\n p.end_date as \"end_date\"\r\nFROM\r\n charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id \r\nJOIN addresses a ON a.id = p.address_id\r\nLEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n $__timeFilter(date)\r\n AND p.car_id = $car_id\r\n AND c.battery_level >= $filter_soc_from AND c.battery_level <= $filter_soc_to\r\n AND charger_power >= $filter_power_from AND charger_power <= $filter_power_to\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) NOT ILIKE '%supercharger%' \r\nGROUP BY c.battery_level, c.charging_process_id, a.name, g.name, p.start_date, p.end_date, to_char(c.date, 'YYYY-MM-dd')", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n c.battery_level as \"B - SOC [%]\",\n PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY charger_power) as \"B - Avg Power [kW]\"\nFROM\n charges c\nJOIN charging_processes p ON p.id = c.charging_process_id \nJOIN addresses a ON a.id = p.address_id\nLEFT JOIN geofences g ON g.id = p.geofence_id\nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND c.battery_level >= $filter_soc_from AND c.battery_level <= $filter_soc_to\n AND charger_power >= $filter_power_from AND charger_power <= $filter_power_to\n AND c.fast_charger_present\n AND COALESCE(g.name, a.name) NOT ILIKE '%supercharger%' \nGROUP BY battery_level", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Other DC Charging Curve", + "type": "xychart" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 40, + "panels": [], + "title": "Fast Charging Sessions", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to have a look of the charging curve sessions on Tesla Supercharges or other Fast Charging Station.\n\nAlso, you can see number of fast charging sessions you've done on each type of chargers and the count of max power (kW) reached on a session.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 0, + "y": 15 + }, + "id": 38, + "options": { + "displayLabels": ["value", "percent"], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH charges_summary AS (\n SELECT\n cp.id,\n COALESCE(geo.name, CONCAT_WS(', ', COALESCE(addr.name, nullif(CONCAT_WS(' ', addr.road, addr.house_number), '')), addr.city)) AS location,\n COUNT(c.charging_process_id)\n FROM\n charging_processes cp\n LEFT JOIN \n addresses addr ON addr.id = address_id\n LEFT JOIN\n geofences geo ON geo.id = geofence_id\n LEFT JOIN\n charges c ON cp.id = c.charging_process_id\n WHERE\n $__timeFilter(date) AND\n cp.car_id = $car_id AND cp.charge_energy_added > 0.01 AND c.fast_charger_present \n GROUP BY 1, 2\n)\nSELECT \n CASE\n WHEN location ILIKE '%supercharger%' THEN 'Tesla Supercharger'\n ELSE 'Other DC Stations' END AS location,\n COUNT(location) AS n\nFROM charges_summary\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-greens" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 90, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "n" + }, + "properties": [ + { + "id": "displayName", + "value": "Number of times" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Power [kW]" + }, + "properties": [ + { + "id": "unit", + "value": "kwatt" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 20, + "x": 4, + "y": 15 + }, + "id": 34, + "links": [], + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xField": "Power [kW]", + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH power_summary AS (\n SELECT ROUND(MAX(charges.charger_power) / 5, 0) * 5 AS \"power\"\n FROM charging_processes\n LEFT JOIN charges ON charging_processes.id = charges.charging_process_id\n WHERE $__timeFilter(date) AND charging_processes.car_id = $car_id AND charging_processes.charge_energy_added > 0.01 AND charges.fast_charger_present\n GROUP BY charging_processes.id\n)\nSELECT power_summary.power AS \"Power [kW]\", COUNT(power_summary.power) AS n\nFROM power_summary\nWHERE power_summary.power >= $filter_power_from AND power_summary.power <= $filter_power_to\nGROUP BY 1\nORDER BY 1 DESC\n", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Max Power", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "Power >=", + "name": "filter_power_from", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "260", + "value": "260" + }, + "hide": 0, + "label": "Power <=", + "name": "filter_power_to", + "options": [ + { + "selected": true, + "text": "260", + "value": "260" + } + ], + "query": "260", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "SOC >=", + "name": "filter_soc_from", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "100", + "value": "100" + }, + "hide": 0, + "label": "SOC <=", + "name": "filter_soc_to", + "options": [ + { + "selected": true, + "text": "100", + "value": "100" + } + ], + "query": "100", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-1M", + "to": "now" + }, + "timepicker": { + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Charging Curve Stats", + "uid": "jchmXpkIkhmRz", + "version": 9, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ContinuousTrips.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ContinuousTrips.json new file mode 100644 index 00000000000..93d06f58ebe --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/ContinuousTrips.json @@ -0,0 +1,810 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:24", + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This dashboard has a table with all the trips you've made between charges sessions, so you can browse the longest or shortest mileage you travel.\n\nYou may also take a look to a specific trip from the initial charge session (before the trip) to the end of the of the charge session (after the trip), through the link in the first column that will take you to the Trips dashboard.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "start_date" + }, + "properties": [ + { + "id": "displayName", + "value": "Start Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "View Trip details", + "url": "d/FkUpJpQZk?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}" + } + ] + }, + { + "id": "custom.minWidth", + "value": 180 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.minWidth", + "value": 200 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + }, + { + "id": "max", + "value": 400 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.minWidth", + "value": 200 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "end_date" + }, + "properties": [ + { + "id": "custom.minWidth", + "value": 180 + }, + { + "id": "displayName", + "value": "End Date" + }, + { + "id": "unit", + "value": "dateTimeAsLocal" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "duration_min" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "clocks" + }, + { + "id": "custom.minWidth", + "value": 120 + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg Speed" + }, + { + "id": "custom.minWidth", + "value": 110 + }, + { + "id": "unit", + "value": "velocitykmh" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg Speed" + }, + { + "id": "custom.minWidth", + "value": 110 + }, + { + "id": "unit", + "value": "velocitymph" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_ts/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "decimals", + "value": 2 + }, + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/%/" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.minWidth", + "value": 65 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "power_max" + }, + "properties": [ + { + "id": "displayName", + "value": "max Power" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "custom.minWidth", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_max_km" + }, + "properties": [ + { + "id": "displayName", + "value": "max Speed" + }, + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "custom.minWidth", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_max_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "max Speed" + }, + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "custom.minWidth", + "value": 90 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_temp_c" + }, + "properties": [ + { + "id": "unit", + "value": "celsius" + }, + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "custom.minWidth", + "value": 75 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "outside_temp_f" + }, + "properties": [ + { + "id": "displayName", + "value": "Temp" + }, + { + "id": "unit", + "value": "fahrenheit" + }, + { + "id": "custom.minWidth", + "value": 75 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.minWidth", + "value": 110 + }, + { + "id": "displayName", + "value": "Consumption gross" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.minWidth", + "value": 150 + }, + { + "id": "displayName", + "value": "Consumption gross" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_kwh" + }, + "properties": [ + { + "id": "displayName", + "value": "Energy" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.minWidth", + "value": 90 + }, + { + "id": "unit", + "value": "kwatth" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency" + }, + "properties": [ + { + "id": "displayName", + "value": "Efficiency" + }, + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "decimals", + "value": 0 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-red", + "value": null + }, + { + "color": "super-light-yellow", + "value": 0.65 + }, + { + "color": "light-green", + "value": 0.99 + } + ] + } + }, + { + "id": "custom.minWidth", + "value": 100 + } + ] + } + ] + }, + "gridPos": { + "h": 30, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH \r\ntrip AS (\r\n SELECT start_date sd, end_date ed, distance, duration_min, start_usable_battery_level, end_usable_battery_level, \r\n outside_temp_avg, power_max, speed_max, start_[[preferred_range]]_range_km, end_[[preferred_range]]_range_km\r\n FROM drives INNER JOIN (\r\n SELECT drive_id, MIN(usable_battery_level) AS end_usable_battery_level, MAX(usable_battery_level) AS start_usable_battery_level\r\n FROM (\r\n SELECT p.drive_id, p.usable_battery_level, ROW_NUMBER() OVER (PARTITION BY p.drive_id ORDER BY date) AS row_num\r\n FROM drives d INNER JOIN positions p ON p.drive_id = d.id\r\n WHERE d.car_id = $car_id\r\n AND $__timeFilter(p.date)\r\n AND d.end_date IS NOT NULL\r\n AND d.duration_min > 0\r\n AND d.start_[[preferred_range]]_range_km > d.end_[[preferred_range]]_range_km\r\n AND p.usable_battery_level IS NOT NULL\r\n ) AS pos\r\n GROUP BY drive_id\r\n ) AS filter_drives ON filter_drives.drive_id = drives.id\r\n),\r\ncp AS (\r\n SELECT car_id, start_date, end_date, COALESCE(LAG(start_date) OVER(ORDER BY start_date DESC), now()) next_date, start_battery_level, end_battery_level\r\n FROM charging_processes WHERE $__timeFilter(start_date) AND car_id = $car_id\r\n),\r\ndriven AS (\r\nSELECT cp.car_id, cp.start_date, cp.end_date, cp.next_date, \r\n MIN(trip.sd) trip_start_date, \r\n MAX(trip.ed) trip_end_date,\r\n SUM(convert_km(trip.distance::numeric, '$length_unit')) AS distance_$length_unit, \r\n MAX(convert_km(trip.speed_max::numeric, '$length_unit')) AS speed_max_$length_unit,\r\n SUM(trip.duration_min) duration_min,\r\n MAX(trip.start_usable_battery_level) start_soc, \r\n MIN(trip.end_usable_battery_level) end_soc, \r\n AVG(convert_celsius(trip.outside_temp_avg, '$temp_unit')) AS avg_temp_$temp_unit, \r\n MAX(trip.power_max) AS power_max, \r\n convert_km((MAX(trip.start_[[preferred_range]]_range_km) - MIN(trip.end_[[preferred_range]]_range_km))::numeric, '$length_unit') AS range_diff_$length_unit \r\n\tFROM cp\tINNER JOIN trip ON trip.sd BETWEEN cp.start_date and cp.next_date\r\n GROUP BY cp.car_id, cp.start_date, cp.end_date, cp.next_date\r\n)\r\nSELECT \r\n ROUND(EXTRACT(epoch FROM start_date) - 10) * 1000 AS start_date_ts, ROUND(EXTRACT(epoch FROM next_date) + 10) * 1000 AS end_date_ts, start_date, next_date end_date,\r\n distance_$length_unit, duration_min * 60 as duration_min, \r\n (distance_$length_unit / duration_min * 60) as speed_$length_unit, \r\n start_soc as \"% Start\", end_soc as \"% End\", avg_temp_$temp_unit, power_max, speed_max_$length_unit,\r\n (range_diff_$length_unit * car.efficiency) consumption_kwh, \r\n (range_diff_$length_unit * car.efficiency / distance_$length_unit * 1000.0) consumption_kWh_$length_unit,\r\n (distance_$length_unit / range_diff_$length_unit) efficiency\r\nFROM driven\r\nINNER JOIN cars car ON car.id = driven.car_id\r\nWHERE distance_$length_unit >= $min_dist AND (distance_$length_unit / duration_min * 60) >= $min_avg_speed\r\nORDER BY start_date DESC\r\n", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Long Trips", + "transformations": [], + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT unit_of_length FROM settings limit 1", + "hide": 2, + "includeAll": false, + "label": "length unit", + "multi": false, + "name": "length_unit", + "options": [], + "query": "SELECT unit_of_length FROM settings limit 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT base_url FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "SELECT base_url FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "definition": "SELECT preferred_range FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "SELECT preferred_range FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT unit_of_temperature FROM settings LIMIT 1", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "SELECT unit_of_temperature FROM settings LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "includeAll": false, + "label": "Distance >=", + "name": "min_dist", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "hide": 0, + "label": "Avg Speed >=", + "name": "min_avg_speed", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-1M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Continuous Trips", + "uid": "jchmY8upc6ZRk", + "version": 5, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentChargeView.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentChargeView.json new file mode 100644 index 00000000000..5e30f174b5f --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentChargeView.json @@ -0,0 +1,1953 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "panel", + "id": "geomap", + "name": "Geomap", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["Custom"], + "targetBlank": false, + "title": "Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "info", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Current Charge", + "tooltip": "Show Current Charge Data", + "type": "link", + "url": "d/jchm9RxutVS7a/current-charge-view?kiosk&var-car_id=${car_id}&from=${current_charge_time}&to=${current_end_time}&var-BatteryCapacity=${BatteryCapacity}&var-charging_processes=${charging_processes}" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-orange", + "value": 80 + }, + { + "color": "light-blue", + "value": 100 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "displayMode": "lcd", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": { + "valueSize": 40 + }, + "valueMode": "color" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT battery_level as \"SOC [%]\" FROM charges c join charging_processes p ON p.id = c.charging_process_id WHERE $__timeFilter(date) AND p.car_id = $car_id ORDER BY c.ID DESC LIMIT 1", + "refId": "SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-green", + "value": 7.84 + }, + { + "color": "semi-dark-orange", + "value": 31.36 + }, + { + "color": "light-blue", + "value": 35.28 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 33, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^kWh$/", + "values": false + }, + "showUnfilled": true, + "text": { + "valueSize": 40 + }, + "valueMode": "color" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT battery_level * $BatteryCapacity / 100 as \"kWh\", $BatteryCapacity AS Total FROM charges c join charging_processes p ON p.id = c.charging_process_id WHERE $__timeFilter(date) AND p.car_id = $car_id ORDER BY c.ID DESC LIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "Load this dashboard to while you are in a charging session. When you open this dashboard it will show the last 15 minutes, but you should click the \"Current Charge\" button at the top right corner, to enter in Kiosk mode:\n\n- If you are charging, you will see the information from the start time of the current charge session until now and it will refesh automatically every 30 seconds.\n\n- If you are just browsing (not charging) you will see the information of the last charge session.", + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 0 + }, + "id": 51, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "
\n\n
", + "mode": "html" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n start_date AS \"time\",\n start_km\nFROM drives\nWHERE\n $__timeFilter(start_date)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "text" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "decimals": 2, + "mappings": [], + "max": 49, + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-orange", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 0 + }, + "id": 36, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^Added$/", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "kWh Added", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(charge_energy_added) as \"Added\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ", + "refId": "B", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Added", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 37, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^coalesce$/", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT COALESCE(g.name, CONCAT_WS(', ', COALESCE(addresses.name, CONCAT_WS(' ', addresses.road, addresses.house_number)), addresses.city)) FROM \tcharging_processes c \tLEFT JOIN addresses ON addresses.id = c.address_id \tLEFT JOIN geofences g ON g.id = geofence_id WHERE \tc.id = $charging_processes", + "refId": "Voltage", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 51, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Power [kW]" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SOC [%]" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-blue", + "mode": "fixed" + } + }, + { + "id": "custom.axisPlacement", + "value": "right" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Battery heater" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "bool_on_off" + } + ] + } + ] + }, + "gridPos": { + "h": 20, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 28, + "options": { + "legend": { + "calcs": ["mean", "min", "max", "last"], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.1.2", + "targets": [ + { + "alias": "Power [kW]", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["none"], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT $__time(date), battery_level as \"SOC [%]\", (case when charger_phases >= 1 then (case when charger_phases = 2 then 3 when charger_phases = 1 then 1 else 0 end) * charger_actual_current * charger_voltage / 1000.0 else charger_power end) as \"Power [kW]\", (case when battery_heater_on then 10 when battery_heater then 10 else 0 end) as \"Battery heater\" FROM charges c JOIN charging_processes p ON p.id = c.charging_process_id WHERE $__timeFilter(date) and p.car_id = $car_id ORDER BY 1", + "refId": "Power", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "tags": [], + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "timeseries" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "light-green", + "mode": "fixed" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 12, + "y": 4 + }, + "id": 35, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["first"], + "fields": "", + "values": true + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "Real", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [], + "hide": false, + "measurement": "km", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": " SELECT battery_level as \"Initial SOC\" FROM charges \twhere charging_process_id=$charging_processes \tORDER BY DATE ASC \tLIMIT 1", + "refId": "Inital SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT battery_level - (SELECT battery_level as \"Added\" FROM charges where charging_process_id=$charging_processes\tORDER BY DATE ASC \tLIMIT 1) as \"Added\" FROM charges c join charging_processes p ON p.id = c.charging_process_id WHERE $__timeFilter(date) AND p.car_id = $car_id ORDER BY c.ID DESC LIMIT 1", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "clocks" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 15, + "y": 4 + }, + "id": 30, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["sum"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "Elapsed Time", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "WITH start_process AS ( SELECT date FROM charges \twhere charging_process_id=$charging_processes \tORDER BY DATE ASC \tLIMIT 1 ) SELECT EXTRACT(EPOCH FROM (charges.date - start_process.date)) AS \"Elapsed\" FROM charges, start_process WHERE charging_process_id = $charging_processes AND $__timeFilter(charges.date) order by charges.date desc LIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["utc"], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 14, + "w": 6, + "x": 18, + "y": 4 + }, + "id": 50, + "links": [], + "maxDataPoints": 50000, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 20, + "max": 15, + "min": 2 + }, + "symbol": { + "field": "", + "fixed": "", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "route", + "opacity": 1, + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [ + { + "params": ["$__interval", "none"], + "type": "time" + } + ], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n latitude,\n longitude\nFROM positions\nWHERE \n car_id = $car_id AND \n $__timeFilter(date)\nORDER BY \n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["lat"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ], + [ + { + "params": ["lng"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ] + }, + "table": "pos", + "timeColumn": "Datum", + "timeColumnType": "datetime", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "geomap" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-yellow", + "mode": "fixed" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Km" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 15, + "y": 7 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["first"], + "fields": "", + "values": true + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "Real", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "groupBy": [], + "hide": false, + "measurement": "km", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "select $__time(date), convert_km(odometer::numeric, '$length_unit') as \"Odometer\" from positions where car_id = $car_id order by date desc limit 1;", + "refId": "odometer", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + }, + "unit": "lengthkm" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 10 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "Real", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "groupBy": [], + "hide": false, + "measurement": "km", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(convert_km(rated_battery_range_km, '$length_unit')) as \"Initial Range\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 asc limit 1", + "refId": "Initial Range", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["value"], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "Real", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "groupBy": [], + "hide": false, + "measurement": "km", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(convert_km(rated_battery_range_km, '$length_unit')) as \"Rated Range\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 desc limit 1", + "refId": "Rated", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["value"], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "Estimated", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "groupBy": [], + "hide": false, + "measurement": "km", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(convert_km(est_battery_range_km, '$length_unit')) as \"Estimated Range\" FROM positions WHERE $__timeFilter(date) GROUP BY 1 ORDER BY 1 desc limit 1", + "refId": "Estimated", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["value"], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "light-blue", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Current" + }, + "properties": [ + { + "id": "unit", + "value": "amp" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 14 + }, + "id": 49, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(case when charger_voltage > 2 then charger_actual_current else ((2.85 + (usable_battery_level * 0.013)) * 96) * charger_power / 100 end) as \"Current\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 ", + "refId": "Current", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "volt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 14 + }, + "id": 47, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^Volt$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(case when charger_voltage > 2 then charger_voltage else charger_power / GREATEST(0.1, (((2.85 + (usable_battery_level * 0.013)) * 96.0) * charger_power / 100.0)) * 1000.0 end) as \"Volt\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 ", + "refId": "Voltage", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "orange", + "mode": "fixed" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "kwatt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 18 + }, + "id": 34, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(case when charger_phases >= 1 then (case when charger_phases = 2 then 3 when charger_phases = 1 then 1 else 0 end) * charger_actual_current * charger_voltage / 1000.0 else charger_power end) as \"Power\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 ", + "refId": "Current", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 18 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(convert_celsius(outside_temp, '$temp_unit')) as \"Outdoor\" FROM charges WHERE charging_process_id = $charging_processes AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 ", + "refId": "Outdoor", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__timeGroupAlias(date,$__interval), avg(convert_celsius(inside_temp, '$temp_unit')) AS \"Inside\" FROM positions WHERE car_id = $car_id and inside_temp is not null AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 ", + "refId": "Inside", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \t$__timeGroupAlias(date,$__interval), \tavg(convert_celsius(driver_temp_setting, '$temp_unit')) as \"Driver\" FROM positions WHERE driver_temp_setting IS NOT NULL AND car_id = $car_id AND $__timeFilter(date) GROUP BY 1 ORDER BY 1 ", + "refId": "Driver", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + } + ], + "refresh": false, + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "--- Extracted from Battery Health Dashboard", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "BatteryCapacity", + "options": [], + "query": "SELECT AVG(Capacity) AS CurrentCapacity FROM\n (SELECT (100.0 * cp.charge_energy_added) / (GREATEST(1,MAX(usable_battery_level) - MIN(usable_battery_level))) AS Capacity\t\n FROM charging_processes cp\n\t INNER JOIN charges c ON cp.id = c.charging_process_id\n\t WHERE cp.car_id = $car_id AND \n cp.charge_energy_added >= (SELECT efficiency FROM cars WHERE id = 1) * 100.0\n GROUP BY cp.charge_energy_added, cp.end_date\n ORDER BY cp.end_date DESC \n LIMIT 5) AS lastEstimatedCapacity;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts FROM charging_processes WHERE id = $charging_processes", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "current_charge_time", + "options": [], + "query": "SELECT (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts FROM charging_processes WHERE id = $charging_processes", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT id FROM charging_processes WHERE car_id = $car_id ORDER BY start_date DESC LIMIT 1", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "charging_processes", + "options": [], + "query": "SELECT id FROM charging_processes WHERE car_id = $car_id ORDER BY start_date DESC LIMIT 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT CASE WHEN end_date IS NULL THEN 'now&refresh=10s' ELSE CAST(round(extract(epoch FROM end_date) - 10) * 1000 AS VARCHAR(100)) END FROM charging_processes WHERE id = $charging_processes", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "current_end_time", + "options": [], + "query": "SELECT CASE WHEN end_date IS NULL THEN 'now&refresh=10s' ELSE CAST(round(extract(epoch FROM end_date) - 10) * 1000 AS VARCHAR(100)) END FROM charging_processes WHERE id = $charging_processes", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Current Charge View", + "uid": "jchm9RxutVS7a", + "version": 7, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentDriveView.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentDriveView.json new file mode 100644 index 00000000000..0917402bf8a --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentDriveView.json @@ -0,0 +1,1858 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "panel", + "id": "geomap", + "name": "Geomap", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:286", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "A high level overview of your car", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": false, + "icon": "info", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Current Drive", + "tooltip": "Adjust to current drive", + "type": "link", + "url": "d/jchmkOuP_Fggz/current-drive-view?kiosk&var-car_id=${car_id}&from=${current_drive_start_time}&to=${current_drive_end_time}&var-current_drive=${current_drive}&var-BatteryCapacity=${BatteryCapacity}&var-efficiency=${efficiency}&var-preferred_range=${preferred_range}" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This is a special dashboard to load while driving. When you open this dashboard it will show the last 15 minutes, but you should click the \"Current Drive\" button at the top right corner, to enter in Kiosk mode:\n\n - If you are driving, you will see the information from the start time of the current drive until now and it will refesh automatically every 30 seconds.\n\n - If you are just browsing (not driving) you will see the information of the last drive.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 5, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Battery heater" + }, + "properties": [ + { + "id": "unit", + "value": "bool_on_off" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + }, + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "power" + }, + "properties": [ + { + "id": "displayName", + "value": "Power" + }, + { + "id": "color", + "value": { + "fixedColor": "dark-orange", + "mode": "fixed", + "seriesBy": "last" + } + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "dark-green", + "value": 0 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "elevation_m" + }, + "properties": [ + { + "id": "displayName", + "value": "Elevation" + }, + { + "id": "unit", + "value": "lengthm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_kmh" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "displayName", + "value": "Speed" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_mih" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + }, + { + "id": "unit", + "value": "velocitymih" + }, + { + "id": "displayName", + "value": "Speed" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 20, + "x": 0, + "y": 0 + }, + "id": 26, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.4", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tavg(power) AS Power,\n\tavg(battery_heater::integer) AS \"Battery heater\",\n\tavg(convert_km(speed::numeric, '$length_unit')) AS speed_[[length_unit]]h\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nGROUP BY 1 \nORDER BY\n\tdate ASC", + "refId": "Power", + "select": [ + [ + { + "params": ["id"], + "type": "column" + } + ] + ], + "table": "charging", + "timeColumn": "Datum", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tAVG(ROUND(convert_m(elevation, '$alternative_length_unit'))) AS elevation_[[alternative_length_unit]]\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND\n $__timeFilter(date)\nGROUP BY 1 \nORDER BY\n\tdate ASC", + "refId": "Elevation", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Power", + "type": "timeseries" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".*_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": ".*_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM charging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t end_date IS NOT NULL AND\n\t c.car_id = $car_id AND\n\t $__timeFilter(start_date)\n\tORDER BY start_date\n),\n\nrange_loss_between_charges AS (\n SELECT sum(range_loss) AS range_loss\n FROM d\n WHERE distance >= 0 AND range_loss >= 0\n GROUP BY car_id\n),\n\ncharge_dates AS (\n\tSELECT\n\t\tmin(start_date) as first_charge,\n\t\tmax(end_date) as last_charge\n\tFROM\n\t\tcharging_processes\n\tWHERE\n\t\tend_date IS NOT NULL\n\t\tAND car_id = $car_id\n\t\tAND $__timeFilter(start_date)\n),\n\nrange_loss_before_first_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND ((select first_charge from charge_dates) is null OR date < (select first_charge from charge_dates))\n),\n\nrange_loss_after_last_charge AS (\n\tSELECT\n\t\tmax([[preferred_range]]_battery_range_km) - min([[preferred_range]]_battery_range_km) AS range_loss\n\tFROM positions, charge_dates\n\tWHERE\n\t\tcar_id = $car_id\n\t\tAND $__timeFilter(date)\n\t\tAND date > (select last_charge from charge_dates)\t\n),\n\ntotal_range_loss AS (\n SELECT sum(range_loss) as range_loss\n FROM (\n SELECT range_loss FROM range_loss_between_charges\n UNION ALL\n SELECT range_loss FROM range_loss_before_first_charge\n UNION ALL\n SELECT range_loss FROM range_loss_after_last_charge\n ) r\n),\n\ndistance AS (\n SELECT max(odometer) - min(odometer) as distance\n FROM positions\n WHERE car_id = $car_id AND $__timeFilter(date)\n)\n\nSELECT \n NULLIF(range_loss, 0) * (c.efficiency * 1000) / convert_km(NULLIF(distance::numeric, 0), '$length_unit') as \"consumption_$length_unit\"\nFROM total_range_loss, distance\nLEFT JOIN cars c ON c.id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current Consumption", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "efficiency_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 3 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCASE WHEN '$length_unit' = 'km' THEN $efficiency\n\t WHEN '$length_unit' = 'mi' THEN $efficiency * 1.60934\n\tEND as \"efficiency_$length_unit\"\nFROM settings\nWHERE\tid = $car_id;\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current $preferred_range efficiency", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-orange", + "value": 80 + }, + { + "color": "light-blue", + "value": 100 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 2, + "x": 20, + "y": 6 + }, + "id": 29, + "options": { + "displayMode": "lcd", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "vertical", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": {}, + "valueMode": "color" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "(SELECT battery_level, date\nFROM positions\nWHERE car_id = $car_id\nORDER BY date DESC\nLIMIT 1)\nUNION\nSELECT battery_level, date\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE $__timeFilter(date) AND p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-green", + "value": 7.84 + }, + { + "color": "semi-dark-orange", + "value": 31.36 + }, + { + "color": "light-blue", + "value": 35.28 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 2, + "x": 22, + "y": 6 + }, + "id": 31, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "vertical", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^kwh$/", + "values": false + }, + "showUnfilled": true, + "text": {}, + "valueMode": "color" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": ["$__interval"], + "type": "time" + }, + { + "params": ["null"], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "policy": "default", + "rawQuery": true, + "rawSql": "(SELECT battery_level * $BatteryCapacity / 100 as kWh, date, $BatteryCapacity as Total\nFROM positions\nWHERE car_id = $car_id\nORDER BY date DESC\nLIMIT 1)\nUNION\nSELECT battery_level * $BatteryCapacity / 100 as kWh, date, $BatteryCapacity as Total\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE $__timeFilter(date) AND p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 0, + "y": 12 + }, + "id": 8, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH last_position AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM positions\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1\n),\nlast_charge AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM charges\n\tJOIN charging_processes ON charges.charging_process_id = charging_processes.id\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1\n)\nSELECT * FROM last_position\nUNION ALL\nSELECT * FROM last_charge\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Outside Temp", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 3, + "y": 12 + }, + "id": 9, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n date,\n convert_celsius(inside_temp, '$temp_unit') AS \"Inside Temperature [°$temp_unit]\"\nFROM positions\nWHERE\n car_id = $car_id\n and inside_temp is not null AND $__timeFilter(date)\norder by date desc\nlimit 1 ", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Inside Temp", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 6, + "y": 12 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tconvert_celsius(driver_temp_setting, '$temp_unit') as \"Driver Temperature [°$temp_unit]\"\nFROM positions\nWHERE driver_temp_setting IS NOT NULL AND car_id = $car_id AND $__timeFilter(date)\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Driver Temp", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "lengthkm" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 12 + }, + "id": 27, + "links": [ + { + "targetBlank": true, + "title": "Mileage", + "url": "/d/NjtMTFggz/mileage?" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km((max(odometer) - min(odometer))::numeric, '$length_unit') as \"distance_$length_unit\"\n FROM positions\n WHERE car_id = $car_id AND $__timeFilter(date)", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Distance", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "range_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 12, + "y": 12 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), range as \"range_$length_unit\"\nFROM (\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM positions\n\tWHERE car_id = $car_id AND [[preferred_range]]_battery_range_km IS NOT NULL\n ORDER BY date DESC\n\tLIMIT 1)\n\tUNION ALL\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM charges c\n\tJOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE p.car_id = $car_id\n\tORDER BY date DESC\n\tLIMIT 1)\n) AS data\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Range", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "odometer_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 15, + "y": 12 + }, + "id": 6, + "links": [ + { + "targetBlank": true, + "title": "Mileage", + "url": "/d/NjtMTFggz/mileage?" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(date), convert_km(odometer::numeric, '$length_unit') as \"odometer_$length_unit\"\nfrom positions \nwhere car_id = $car_id \norder by date desc \nlimit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Odometer", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 33, + "links": [], + "maxDataPoints": 50000, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 3, + "max": 15, + "min": 2 + }, + "symbol": { + "field": "", + "fixed": "", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "route", + "opacity": 1, + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [ + { + "params": ["$__interval", "none"], + "type": "time" + } + ], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n latitude,\n longitude\nFROM positions\nWHERE \n car_id = $car_id AND \n $__timeFilter(date)\nORDER BY \n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["lat"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ], + [ + { + "params": ["lng"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ] + }, + "table": "pos", + "timeColumn": "Datum", + "timeColumnType": "datetime", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "geomap" + } + ], + "refresh": "10s", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "alternative_length_unit", + "options": [], + "query": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT drive_id FROM positions WHERE car_id = $car_id AND drive_id IS NOT NULL ORDER BY date DESC LIMIT 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "current_drive", + "options": [], + "query": "SELECT drive_id FROM positions WHERE car_id = $car_id AND drive_id IS NOT NULL ORDER BY date DESC LIMIT 1;", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT \n (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts\n FROM drives \n WHERE id = $current_drive", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "current_drive_start_time", + "options": [], + "query": "SELECT \n (round(extract(epoch FROM start_date) - 10) * 1000) AS start_date_ts\n FROM drives \n WHERE id = $current_drive", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT \n CASE WHEN end_date IS NULL THEN 'now&refresh=10s' \n ELSE CAST(round(extract(epoch FROM end_date) - 10) * 1000 AS VARCHAR(100)) END\n FROM drives\n WHERE id = $current_drive", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "current_drive_end_time", + "options": [], + "query": "SELECT \n CASE WHEN end_date IS NULL THEN 'now&refresh=10s' \n ELSE CAST(round(extract(epoch FROM end_date) - 10) * 1000 AS VARCHAR(100)) END\n FROM drives\n WHERE id = $current_drive", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "--- Extracted from Battery Health Dashboard", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "BatteryCapacity", + "options": [], + "query": "SELECT AVG(Capacity) AS CurrentCapacity FROM\n (SELECT (100.0 * cp.charge_energy_added) / (GREATEST(1,MAX(usable_battery_level) - MIN(usable_battery_level))) AS Capacity\t\n FROM charging_processes cp\n\t INNER JOIN charges c ON cp.id = c.charging_process_id\n\t WHERE cp.car_id = $car_id AND \n cp.charge_energy_added >= (SELECT efficiency FROM cars WHERE id = 1) * 100.0\n GROUP BY cp.charge_energy_added, cp.end_date\n ORDER BY cp.end_date DESC \n LIMIT 5) AS lastEstimatedCapacity;", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT\n\tCASE WHEN '$length_unit' = 'km' THEN efficiency\n\t WHEN '$length_unit' = 'mi' THEN efficiency * 1.60934\n\tEND * 1000 as \"efficiency_$length_unit\"\nFROM\n\tcars\nWHERE\n\tid = $car_id;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "efficiency", + "options": [], + "query": "SELECT\n\tCASE WHEN '$length_unit' = 'km' THEN efficiency\n\t WHEN '$length_unit' = 'mi' THEN efficiency * 1.60934\n\tEND * 1000 as \"efficiency_$length_unit\"\nFROM\n\tcars\nWHERE\n\tid = $car_id;", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "hidden": false, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Current Drive View", + "uid": "jchmkOuP_Fggz", + "version": 8, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentState.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentState.json new file mode 100644 index 00000000000..4c487639572 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/CurrentState.json @@ -0,0 +1,1841 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "panel", + "id": "geomap", + "name": "Geomap", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "state-timeline", + "name": "State timeline", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:427", + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "Only distinguishes between online, offline and asleep.", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 6, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^state$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(start_date), state from states where car_id = $car_id AND $__timeFilter(start_date) order by start_date desc limit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current State", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This dasboard is just to see the current state of the car with the last data recorded by TeslaMate.\n\nAdditionally, you can see the states stats of the selected period.", + "fieldConfig": { + "defaults": { + "mappings": [], + "noValue": "-", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "dateTimeAsSystem" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 4, + "y": 0 + }, + "id": 2, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^time$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select $__time(start_date), state from states where car_id = $car_id AND $__timeFilter(start_date) order by start_date desc limit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Last state change", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "range_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 0 + }, + "id": 69, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), range as \"range_$length_unit\"\nFROM (\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM positions\n\tWHERE car_id = $car_id AND [[preferred_range]]_battery_range_km IS NOT NULL AND $__timeFilter(date)\n ORDER BY date DESC\n\tLIMIT 1)\n\tUNION ALL\n\t(SELECT date, convert_km([[preferred_range]]_battery_range_km, '$length_unit') AS range\n\tFROM charges c\n\tJOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE p.car_id = $car_id AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1)\n) AS data\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "$preferred_range range", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "range_km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "range_mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 0 + }, + "id": 70, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT $__time(date), range as \"range_$length_unit\"\nFROM (\n\t(SELECT date, convert_km(est_battery_range_km, '$length_unit') AS range\n\tFROM positions\n\tWHERE car_id = $car_id AND est_battery_range_km IS NOT NULL AND $__timeFilter(date)\n ORDER BY date DESC\n\tLIMIT 1)\n\tUNION ALL\n\t(SELECT date, convert_km(ideal_battery_range_km, '$length_unit') AS range\n\tFROM charges c\n\tJOIN charging_processes p ON p.id = c.charging_process_id\n\tWHERE p.car_id = $car_id AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1)\n) AS data\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "estimated range", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "displayName": "", + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "semi-dark-yellow", + "value": 10 + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-yellow", + "value": 81 + }, + { + "color": "light-red", + "value": 91 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 18, + "y": 0 + }, + "id": 85, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "(SELECT battery_level, date FROM positions WHERE car_id = $car_id AND $__timeFilter(date) ORDER BY date DESC LIMIT 1)\nUNION\nSELECT battery_level, date\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE $__timeFilter(date) AND p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "A", + "select": [ + [ + { + "params": ["battery_level"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [] + } + ], + "title": "Battery Level", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 71, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": true + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n convert_tire_pressure(tpms_pressure_fl,'$pressure_unit') AS \"Front left\",\r\n convert_tire_pressure(tpms_pressure_fr,'$pressure_unit') AS \"Front right\",\r\n convert_tire_pressure(tpms_pressure_rl,'$pressure_unit') AS \"Rear left\",\r\n convert_tire_pressure(tpms_pressure_rr,'$pressure_unit') AS \"Rear right\"\r\nFROM\r\n positions\r\nWHERE\r\n car_id = $car_id AND\r\n $__timeFilter(date) AND\r\n tpms_pressure_fl is not null\r\nORDER BY\r\n date DESC LIMIT 1", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Tire Pressure ($pressure_unit)", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 14, + "w": 12, + "x": 0, + "y": 3 + }, + "id": 86, + "links": [], + "maxDataPoints": 50000, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 3, + "max": 15, + "min": 2 + }, + "symbol": { + "field": "", + "fixed": "", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "route", + "opacity": 1, + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [ + { + "params": ["$__interval", "none"], + "type": "time" + } + ], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n $__time(date),\n latitude,\n longitude\nFROM positions\nWHERE \n car_id = $car_id AND \n $__timeFilter(date)\nORDER BY \n date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["lat"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ], + [ + { + "params": ["lng"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ] + }, + "table": "pos", + "timeColumn": "Datum", + "timeColumnType": "datetime", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "geomap" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 4 + }, + "id": 59, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t$__time(date),\n\tconvert_celsius(driver_temp_setting, '$temp_unit') as \"Driver Temperature [°$temp_unit]\"\nFROM positions\nWHERE driver_temp_setting IS NOT NULL AND car_id = $car_id AND $__timeFilter(date)\nORDER BY date DESC\nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Driver Temp", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 4 + }, + "id": 63, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n date,\n convert_celsius(inside_temp, '$temp_unit') AS \"Inside Temperature [°$temp_unit]\"\nFROM positions\nWHERE\n car_id = $car_id\n and inside_temp is not null AND $__timeFilter(date)\norder by date desc\nlimit 1 ", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Inside Temp", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-green", + "value": null + } + ] + }, + "unit": "degree" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 18, + "y": 4 + }, + "id": 61, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["firstNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH last_position AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM positions\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1\n),\nlast_charge AS (\n\tSELECT date, convert_celsius(outside_temp, '$temp_unit') AS \"Outside Temperature [°$temp_unit]\"\n\tFROM charges\n\tJOIN charging_processes ON charges.charging_process_id = charging_processes.id\n\tWHERE car_id = $car_id AND outside_temp IS NOT NULL AND $__timeFilter(date)\n\tORDER BY date DESC\n\tLIMIT 1\n)\nSELECT * FROM last_position\nUNION ALL\nSELECT * FROM last_charge\nORDER BY date DESC \nLIMIT 1;", + "refId": "A", + "select": [ + [ + { + "params": ["outside_temp"], + "type": "column" + } + ] + ], + "table": "positions", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Outside Temp", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "super-light-blue", + "mode": "fixed" + }, + "mappings": [], + "noValue": "-", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 12, + "y": 8 + }, + "id": 79, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^coalesce$/", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n COALESCE(g.name, CONCAT_WS(', ', COALESCE(addresses.name, CONCAT_WS(' ', addresses.road, addresses.house_number)), addresses.city))\n\tFROM drives d\n\tLEFT JOIN addresses ON addresses.id = d.end_address_id\n\tLEFT JOIN geofences g ON g.id = d.end_geofence_id\nWHERE\n\t $__timeFilter(d.end_date) AND d.car_id = $car_id \nORDER BY d.end_date DESC\nLIMIT 1", + "refId": "Voltage", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Location", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [ + { + "options": { + "0": { + "color": "super-light-blue", + "index": 0, + "text": "online" + }, + "1": { + "color": "purple", + "index": 1, + "text": "driving" + }, + "2": { + "color": "yellow", + "index": 2, + "text": "charging" + }, + "3": { + "color": "super-light-orange", + "index": 3, + "text": "offline" + }, + "4": { + "color": "green", + "index": 4, + "text": "asleep" + }, + "5": { + "color": "super-light-blue", + "index": 5, + "text": "online" + }, + "6": { + "color": "red", + "index": 6, + "text": "updating" + }, + "null": { + "index": 7, + "text": "N/A" + } + }, + "type": "value" + } + ], + "noValue": "0", + "unit": "dtdhms" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 9, + "x": 15, + "y": 8 + }, + "id": 41, + "options": { + "displayLabels": ["percent", "name"], + "legend": { + "displayMode": "table", + "placement": "right", + "showLegend": true, + "values": ["value", "percent"] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/^total_time$/", + "values": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH states AS (\r\n SELECT\r\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\r\n unnest(ARRAY [2, 0]) AS state\r\n FROM charging_processes\r\n WHERE\r\n car_id = $car_id AND \r\n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \r\n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\r\n UNION\r\n SELECT\r\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\r\n unnest(ARRAY [1, 0]) AS state\r\n FROM drives\r\n WHERE\r\n car_id = $car_id AND \r\n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \r\n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\r\n UNION\r\n SELECT\r\n start_date AS date,\r\n CASE\r\n WHEN state = 'offline' THEN 3\r\n WHEN state = 'asleep' THEN 4\r\n WHEN state = 'online' THEN 5\r\n END AS state\r\n FROM states\r\n WHERE\r\n car_id = $car_id AND \r\n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \r\n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\r\n UNION\r\n SELECT\r\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\r\n unnest(ARRAY [6, 0]) AS state\r\n FROM updates\r\n WHERE\r\n car_id = $car_id AND \r\n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \r\n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\r\n), aux AS (\r\n SELECT $__timeFrom() :: timestamp AS date, (SELECT state FROM states WHERE date <= $__timeFrom() ORDER BY date DESC LIMIT 1) AS state, false AS include\r\n UNION\r\n SELECT date, state, true AS include FROM states\r\n UNION\r\n SELECT $__timeTo() :: timestamp as date, NULL AS state, true as include\r\n ORDER BY date\r\n), states_elapsed AS (\r\n SELECT \r\n date, state AS current_state, include,\r\n LAG(state) OVER (ORDER BY date) AS state,\r\n LAG(date) OVER (ORDER BY date) AS last_state_time,\r\n date - LAG(date) OVER (ORDER BY date) AS elapsed_time\r\n FROM aux \r\n)\r\nSELECT \r\n CASE\r\n WHEN state = 0 OR state = 5 THEN 'online'\r\n WHEN state = 1 THEN 'driving'\r\n WHEN state = 2 THEN 'charging'\r\n WHEN state = 3 THEN 'offline'\r\n WHEN state = 4 THEN 'asleep'\r\n WHEN state = 6 THEN 'updating'\r\n END AS state,\r\n EXTRACT(EPOCH FROM SUM(elapsed_time)) as Total_Time\r\nFROM states_elapsed\r\nWHERE $__timeFilter(date) AND include\r\nGROUP BY 1\r\n\r\n", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "States", + "type": "piechart" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "odometer_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "odometer_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 12, + "y": 11 + }, + "id": 55, + "links": [ + { + "targetBlank": true, + "title": "Mileage", + "url": "/d/NjtMTFggz/mileage?" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select convert_km(odometer::numeric, '$length_unit') as \"odometer_$length_unit\"\nfrom positions \nwhere car_id = $car_id AND $__timeFilter(date)\norder by date desc \nlimit 1;", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Odometer", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "version" + }, + "properties": [ + { + "id": "unit", + "value": "string" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 12, + "y": 14 + }, + "id": 57, + "links": [ + { + "targetBlank": true, + "title": "Updates", + "url": "/d/IiC07mgWz/updates?" + } + ], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["first"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "/^version$/", + "values": true + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select split_part(version, ' ', 1) as version \nfrom updates \nwhere car_id = $car_id AND start_date <= $__timeTo()\norder by start_date desc \nlimit 1", + "refId": "A", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Firmware", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "fillOpacity": 100, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "color": "#6ED0E0", + "index": 0, + "text": "online" + }, + "1": { + "color": "#8F3BB8", + "index": 1, + "text": "driving" + }, + "2": { + "color": "#F2CC0C", + "index": 2, + "text": "charging" + }, + "3": { + "color": "#FFB357", + "index": 3, + "text": "offline" + }, + "4": { + "color": "#56A64B", + "index": 4, + "text": "asleep" + }, + "5": { + "color": "#6ED0E0", + "index": 5, + "text": "online" + }, + "6": { + "color": "#E02F44", + "index": 6, + "text": "updating" + }, + "null": { + "index": 7, + "text": "N/A" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 83, + "links": [ + { + "title": "States", + "url": "/d/xo4BNRkZz/states" + } + ], + "options": { + "alignValue": "center", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": true, + "rowHeight": 0.9, + "showValue": "auto", + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH states AS (\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [2, 0]) AS state\n FROM charging_processes\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [1, 0]) AS state\n FROM drives\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n start_date AS date,\n CASE\n WHEN state = 'offline' THEN 3\n WHEN state = 'asleep' THEN 4\n WHEN state = 'online' THEN 5\n END AS state\n FROM states\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n UNION\n SELECT\n unnest(ARRAY [start_date + interval '1 second', end_date]) AS date,\n unnest(ARRAY [6, 0]) AS state\n FROM updates\n WHERE\n car_id = $car_id AND \n ($__timeFrom() :: timestamp - interval '30 day') < start_date AND \n (end_date < ($__timeTo() :: timestamp + interval '30 day') OR end_date IS NULL)\n)\nSELECT date AS \"time\", state\nFROM states\nWHERE \n date IS NOT NULL AND\n ($__timeFrom() :: timestamp - interval '30 day') < date AND \n date < ($__timeTo() :: timestamp + interval '30 day') \nORDER BY date ASC, state ASC;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "geofences", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Timeline", + "type": "state-timeline" + } + ], + "refresh": "30s", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_temperature from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "temp_unit", + "options": [], + "query": "select unit_of_temperature from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_pressure from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "pressure_unit", + "options": [], + "query": "select unit_of_pressure from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Current State", + "uid": "jchmo4BNRkZz", + "version": 11, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/DCChargingCurvesByCarrier.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/DCChargingCurvesByCarrier.json new file mode 100644 index 00000000000..427731fac92 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/DCChargingCurvesByCarrier.json @@ -0,0 +1,1026 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + }, + { + "type": "panel", + "id": "xychart", + "name": "XY Chart", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:75", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-RdYlGr" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "pointSize": { + "fixed": 5 + }, + "scaleDistribution": { + "type": "linear" + }, + "show": "points" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Show charge details", + "url": "d/BHhxFeZRz?from=${__data.fields.start_date.numeric}&to=${__data.fields.end_date.numeric}&var-car_id=${car_id}&var-charging_process_id=${__data.fields.charging_process_id.numeric}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 20, + "x": 0, + "y": 0 + }, + "id": 32, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "series": [ + { + "pointColor": { + "field": "Power [kW]" + }, + "pointSize": { + "fixed": 2, + "max": 100, + "min": 1 + }, + "x": "SOC [%]", + "y": "Power [kW]" + }, + { + "pointColor": { + "field": "B - Avg Power [kW]" + }, + "pointSize": { + "fixed": 12, + "max": 100, + "min": 1 + }, + "x": "B - SOC [%]", + "y": "B - Avg Power [kW]" + } + ], + "seriesMapping": "manual", + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.5.11", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n c.battery_level as \"SOC [%]\",\r\n round(avg(c.charger_power), 0) as \"Power [kW]\",\r\n c.charging_process_id as \"charging_process_id\",\r\n COALESCE(g.name, a.name) || ' ' || to_char(c.date, 'YYYY-MM-dd') as \"Charge\",\r\n p.start_date as \"start_date\",\r\n p.end_date as \"end_date\"\r\nFROM\r\n charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id \r\nJOIN addresses a ON a.id = p.address_id\r\nLEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n $__timeFilter(date)\r\n AND p.car_id = $car_id\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\nGROUP BY c.battery_level, c.charging_process_id, a.name, g.name, p.start_date, p.end_date, to_char(c.date, 'YYYY-MM-dd')", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n c.battery_level as \"B - SOC [%]\",\n PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY charger_power) as \"B - Avg Power [kW]\"\nFROM\n charges c\nJOIN charging_processes p ON p.id = c.charging_process_id \nJOIN addresses a ON a.id = p.address_id\nLEFT JOIN geofences g ON g.id = p.geofence_id\nWHERE\n $__timeFilter(date)\n AND p.car_id = $car_id\n AND c.fast_charger_present\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%'\nGROUP BY battery_level", + "refId": "B", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charger Carrier Contains: $carrier", + "type": "xychart" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 44, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\r\nSELECT\r\n COALESCE(g.name, a.name) AS name\r\nFROM charging_processes p\r\n LEFT JOIN charges c ON c.charging_process_id = p.id\r\n LEFT JOIN addresses a ON a.id = p.address_id\r\n LEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n p.car_id = $car_id \r\n AND $__timeFilter(start_date)\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\nGROUP BY p.id, g.name, a.name\r\n)\r\nSELECT name AS \"Charger Carrier\" FROM data GROUP BY name\r\n\r\n\r\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 16 + }, + "id": 35, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n AVG(p.charge_energy_added)\r\nFROM charging_processes p\r\n LEFT JOIN charges c ON c.charging_process_id = p.id\r\n LEFT JOIN addresses a ON a.id = p.address_id\r\n LEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n p.car_id = $car_id \r\n AND $__timeFilter(start_date)\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\nGROUP BY p.id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg. Energy Added", + "transformations": [], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 6, + "y": 16 + }, + "id": 36, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n AVG(p.charge_energy_used)\r\nFROM charging_processes p\r\n LEFT JOIN charges c ON c.charging_process_id = p.id\r\n LEFT JOIN addresses a ON a.id = p.address_id\r\n LEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n p.car_id = $car_id \r\n AND $__timeFilter(start_date)\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\nGROUP BY p.id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg. Energy Used", + "transformations": [], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "m" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 11, + "y": 16 + }, + "id": 34, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n AVG(duration_min)\r\nFROM charging_processes p\r\n LEFT JOIN charges c ON c.charging_process_id = p.id\r\n LEFT JOIN addresses a ON a.id = p.address_id\r\n LEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n p.car_id = $car_id \r\n AND $__timeFilter(start_date)\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\n", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg. Time", + "transformations": [], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 16 + }, + "id": 37, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n AVG(p.cost)\r\nFROM charging_processes p\r\n LEFT JOIN charges c ON c.charging_process_id = p.id\r\n LEFT JOIN addresses a ON a.id = p.address_id\r\n LEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n p.car_id = $car_id \r\n AND $__timeFilter(start_date)\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\nGROUP BY p.id", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg. Cost", + "transformations": [], + "transparent": true, + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 16 + }, + "id": 38, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\r\nSELECT\r\n AVG(p.charge_energy_used) AS charge_energy_used, AVG(p.cost) AS cost \r\nFROM charging_processes p\r\n LEFT JOIN charges c ON c.charging_process_id = p.id\r\n LEFT JOIN addresses a ON a.id = p.address_id\r\n LEFT JOIN geofences g ON g.id = p.geofence_id\r\nWHERE\r\n p.car_id = $car_id \r\n AND $__timeFilter(start_date)\r\n AND c.fast_charger_present\r\n AND COALESCE(g.name, a.name) ILIKE '%$carrier%' \r\nGROUP BY p.id\r\n)\r\nSELECT AVG(cost) / AVG(charge_energy_used) cost_kwh FROM data", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Avg. Cost per kWh", + "transformations": [], + "transparent": true, + "type": "stat" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 42, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 40, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "#### DC Charing curves by Carrier\n\nTo analyse data with this dashboard, it's important that you \nhave Geo-Fences added related with the name of the carrier\nyou have recharged your car, or you may want to edit \nperiodically the **name** field of the **addresses** table,\nso that it contains its name. \n\nFor example, if **Teslamate** geolocates the name as \n*\"Esso Purley Way\"* you may modify it to \n*\"Esso Purley Way - IONITY\"* or *\"IONITY Esso Purley Way\"*, \nthen you can filter using\nthe textbox above as **IONITY** to show all the charging curves\nof all charging sessions at that carrier.", + "mode": "markdown" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n start_date AS \"time\",\n start_km\nFROM drives\nWHERE\n $__timeFilter(start_date)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "text" + } + ], + "title": "Help", + "type": "row" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "description": "Carrier Name", + "hide": 0, + "label": "Carrier", + "name": "carrier", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-1M", + "to": "now" + }, + "timepicker": { + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "DC Charging Curves by Carrier", + "uid": "jchmXpkcccIkh", + "version": 6, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/DatabaseDashboadInfo.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/DatabaseDashboadInfo.json new file mode 100644 index 00000000000..1607e0f4915 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/DatabaseDashboadInfo.json @@ -0,0 +1,1233 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 0, + "y": 0 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ROUND(convert_km((max(odometer) - min(odometer))::numeric, '$length_unit'),0)|| ' $length_unit' as \"Logged\"\nfrom positions where car_id = $car_id;", + "refId": "DistanceLogged", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select ROUND(convert_km(ROUND(odometer::numeric,0), '$length_unit'),0) || ' $length_unit' as \"Odometer\"\nfrom positions \nwhere car_id = $car_id\norder by date desc \nlimit 1;", + "refId": "Odometer", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Mileage", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 5, + "y": 0 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT COUNT(id) AS \"Charges\" FROM charging_processes WHERE car_id=$car_id \n", + "refId": "Charges", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT COUNT(id) AS \"Drives\" FROM drives WHERE car_id=$car_id ", + "refId": "Drives", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Stats", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 0 + }, + "id": 39, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT COUNT(id) as \"Nº Car Updates\"\nFROM Updates \nWHERE car_id = $car_id\n", + "refId": "Car Updates", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "select split_part(version, ' ', 1) as \"Current Car Firmware\" \r\nfrom updates \r\nwhere car_id = $car_id \r\norder by start_date desc \r\nlimit 1", + "refId": "Firmware", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Software", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 15, + "y": 0 + }, + "id": 42, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT COUNT(id) as \"Charges not closed\"\nFROM charging_processes \nWHERE car_id = $car_id AND end_date is null\n", + "refId": "Charges", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT COUNT(id) AS \"Drives not closed\"\r\nFROM drives \r\nWHERE car_id = $car_id AND end_date is null", + "refId": "Drives", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Incomplete Data", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 40, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "You can go to the \nIncomplete Data dashboard
\nto see details of the **Drives** or **Charges** not closed.\n", + "mode": "markdown" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n start_date AS \"time\",\n start_km\nFROM drives\nWHERE\n $__timeFilter(start_date)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "About incomplete data", + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 + }, + "id": 34, + "panels": [], + "title": "Database Information", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Size" + }, + "properties": [ + { + "id": "custom.align", + "value": "right" + }, + { + "id": "custom.width", + "value": 150 + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 5, + "x": 0, + "y": 5 + }, + "id": 33, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "SELECT \r\n relname AS \"Table\",\r\n pg_size_pretty(pg_total_relation_size(relid)) As \"Size\"\r\nFROM \r\n pg_catalog.pg_statio_user_tables\r\nORDER BY \r\n pg_total_relation_size(relid) DESC;", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Row Count" + }, + "properties": [ + { + "id": "custom.align", + "value": "right" + }, + { + "id": "custom.width", + "value": 150 + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 5, + "x": 5, + "y": 5 + }, + "id": 38, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "SELECT table_name AS \"Table Name\", \r\n (xpath('/row/cnt/text()', xml_count))[1]::text::int AS \"Row Count\"\r\nFROM (\r\n SELECT table_name, \r\n query_to_xml(format('SELECT count(*) as cnt FROM %I.%I', table_schema, table_name), false, true, '') AS xml_count\r\n FROM information_schema.tables\r\n WHERE table_schema NOT IN ('pg_catalog', 'information_schema')\r\n) AS t\r\nORDER BY 2 DESC;", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "These statistics can help you evaluate the efficiency of your indexes.\n\nYou should reindex all the database periodically.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 14, + "x": 10, + "y": 5 + }, + "id": 41, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": true, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "rawQuery": true, + "rawSql": "SELECT\r\n relname AS \"Table\",\r\n indexrelname AS \"Index\",\r\n idx_scan AS \"Index Scans\",\r\n idx_tup_read AS \"Tuples Read\",\r\n idx_tup_fetch AS \"Tuples Fetched\"\r\nFROM\r\n pg_stat_all_indexes\r\nWHERE\r\n schemaname NOT LIKE 'pg_%' AND\r\n indexrelname IS NOT NULL\r\nORDER BY 3 DESC;", + "refId": "A", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "Indexes", + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 10, + "x": 0, + "y": 21 + }, + "id": 35, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n pg_size_pretty(SUM(pg_total_relation_size(relid))) As \"Size\"\nFROM \n pg_catalog.pg_statio_user_tables;", + "refId": "DistanceLogged", + "select": [ + [ + { + "params": ["efficiency"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Database Total Size", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "links": [ + { + "targetBlank": true, + "title": "Click to check last Version", + "url": "https://github.com/jheredianet/Teslamate-CustomGrafanaDashboards/releases/" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 14, + "x": 10, + "y": 21 + }, + "id": 43, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "hide": false, + "rawQuery": true, + "rawSql": "SELECT '2024.04.02' AS \"Current Version\"", + "refId": "DashboardVersion", + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + } + } + ], + "title": "About Teslamate Custom Dashboards", + "type": "stat" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "description": "", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "hidden": true, + "refresh_intervals": [] + }, + "timezone": "browser", + "title": "Database Information", + "uid": "jchm_dbInfo", + "version": 3, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/IncompleteData.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/IncompleteData.json new file mode 100644 index 00000000000..84e5fce4dcc --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/IncompleteData.json @@ -0,0 +1,446 @@ +{ + "__elements": [], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.5.15" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "iteration": 1686842645876, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "align": "center", + "displayMode": "auto", + "inspect": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "options": { + "footer": { + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": false + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT 'Car ID: ' || id as id, 'Name: '|| name as name , 'Model: '|| model as model, 'VIN: '|| vin as vin, \n 'Color: '|| exterior_color as color, 'Wheels: '|| wheel_type, 'Efficiency: '|| efficiency as efficiency \nFROM cars\nWHERE id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Car Information 🚘", + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 10, + "options": { + "content": "#### Incomplete Data\n\nFrom here you can check if you have incomplete data of **Drives** and **Charges**. If so, you may follow the official guide by Manually fixing data", + "mode": "markdown" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n start_date AS \"time\",\n start_km\nFROM drives\nWHERE\n $__timeFilter(start_date)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "text" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "align": "center", + "displayMode": "auto", + "inspect": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 15, + "links": [], + "options": { + "footer": { + "enablePagination": true, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT id AS \"Drive ID\", start_date, end_date, distance, duration_min \nFROM drives \nWHERE car_id = $car_id AND end_date is null\nORDER BY start_date DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Incomplete Drives 🛣️", + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "align": "center", + "displayMode": "auto", + "inspect": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 22, + "links": [], + "options": { + "footer": { + "enablePagination": true, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT id as \"Charging Process ID\", start_date, end_date, charge_energy_added, charge_energy_used, start_battery_level, end_battery_level, duration_min\nFROM charging_processes \nWHERE car_id = $car_id AND end_date is null\nORDER BY start_date DESC\n", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Incomplete Charges 🪫", + "type": "table" + } + ], + "refresh": false, + "schemaVersion": 36, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "timepicker": { + "hidden": true, + "refresh_intervals": [] + }, + "timezone": "", + "title": "Incomplete Data", + "uid": "jchmIDopVO_mgz", + "version": 1, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/MileageStats.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/MileageStats.json new file mode 100644 index 00000000000..27ca8a4fe6f --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/MileageStats.json @@ -0,0 +1,816 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "barchart", + "name": "Bar chart", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": "TeslaMate", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "panels": [], + "repeat": "car_id", + "title": "$car_id", + "type": "row" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "custom": { + "align": "left", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false, + "width": 120 + }, + "mappings": [], + "noValue": "--", + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 50 + }, + { + "color": "green", + "value": 90 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time driven" + }, + "properties": [ + { + "id": "unit", + "value": "dtdurations" + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "custom.width" + }, + { + "id": "decimals", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Period" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Trip", + "url": "d/FkUpJpQZk/trip?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Efficiency" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "custom.width" + }, + { + "id": "max", + "value": 1 + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "# drives" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "Drives", + "url": "d/Y8upc6ZRk/drives?from=${__data.fields.date_from}&to=${__data.fields.date_to}&var-car_id=$car_id" + } + ] + }, + { + "id": "custom.align", + "value": "auto" + }, + { + "id": "custom.width", + "value": 80 + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_km/" + }, + "properties": [ + { + "id": "unit", + "value": "km" + }, + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "unit", + "value": "mi" + }, + { + "id": "custom.align", + "value": "auto" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "date_from" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "date_to" + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 9, + "x": 0, + "y": 1 + }, + "id": 10, + "maxPerRow": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "frameIndex": 1, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Starting at" + } + ] + }, + "pluginVersion": "10.1.2", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\nSELECT\n duration_min > 1 AND\n distance > 1 AND\n ( \n start_position.usable_battery_level IS NULL OR\n (end_position.battery_level - end_position.usable_battery_level) = 0 \n ) AS is_sufficiently_precise,\n NULLIF(GREATEST(start_ideal_range_km - end_ideal_range_km, 0), 0) AS range_diff,\n date_trunc('$period', start_date::TIMESTAMP) as local_period,\n drives.*\nFROM drives\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('$period', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('$period', local_period + ('1 ' || '$period')::INTERVAL))*1000 AS date_to,\n CASE '$period'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS display,\n local_period AS date,\n sum(duration_min)*60 AS sum_duration_h, \n convert_km(max(end_km)::integer - min(start_km)::integer, '$length_unit') AS sum_distance_$length_unit,\n count(*) AS cnt,\n sum(distance)/sum(range_diff) AS efficiency\nFROM data WHERE\n car_id = $car_id AND\n $__timeFilter(start_date)\nGROUP BY date\nORDER BY date", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Stats per ${period}", + "transformations": [ + { + "id": "seriesToColumns", + "options": { + "byField": "date" + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_km_temp", + "binary": { + "left": "sum_consumption_kwh", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_km" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": false + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_km", + "binary": { + "left": "efficiency_charged_net_km_temp", + "operator": "*", + "reducer": "sum", + "right": "1000" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_mi_temp", + "binary": { + "left": "sum_consumption_kwh", + "operator": "/", + "reducer": "sum", + "right": "sum_distance_mi" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": false + } + }, + { + "id": "calculateField", + "options": { + "alias": "efficiency_charged_net_mi", + "binary": { + "left": "efficiency_charged_net_mi_temp", + "operator": "*", + "reducer": "sum", + "right": "1000" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "date": true, + "date_from": false, + "date_to": false, + "efficiency_charged_net_km_temp": true, + "efficiency_charged_net_mi_temp": true, + "timezone": true + }, + "indexByName": { + "avg_consumption_kwh": 9, + "avg_outside_temp_c": 5, + "cnt": 6, + "cnt_charges": 11, + "cost_charges": 10, + "date": 1, + "date_from": 16, + "date_to": 17, + "display": 0, + "efficiency": 7, + "efficiency_charged_net_km": 14, + "efficiency_charged_net_mi": 15, + "efficiency_net_km": 12, + "efficiency_net_mi": 13, + "sum_consumption_kwh": 8, + "sum_distance_km": 3, + "sum_distance_mi": 4, + "sum_duration_h": 2 + }, + "renameByName": { + "avg_consumption_kwh": "Avg charged", + "avg_outside_temp_c": "", + "cnt": "# drives", + "cnt_charges": "# charges", + "cost_charges": "Costs", + "date": "Starting at", + "date_from": "", + "date_to": "", + "display": "Period", + "efficiency": "Efficiency", + "efficiency_net_km": "", + "sum_consumption_kwh": "Energy charged", + "sum_distance_km": "", + "sum_duration_h": "Time driven" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "With this dashboard you may analize your mileage and number of drives by year, month, week or day.\n\nThe dashboard shows a table with the selected period, time driven, distance, number of drives and efficiency then a bar chart to have a better look for comparison.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "noValue": "--", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_km/" + }, + "properties": [ + { + "id": "unit", + "value": "km" + }, + { + "id": "displayName", + "value": "Distance" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/sum_distance_mi/" + }, + "properties": [ + { + "id": "displayName", + "value": "Distance" + }, + { + "id": "unit", + "value": "mi" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "cnt" + }, + "properties": [ + { + "id": "unit", + "value": "drives" + }, + { + "id": "custom.axisPlacement", + "value": "hidden" + }, + { + "id": "displayName", + "value": "Count" + } + ] + } + ] + }, + "gridPos": { + "h": 14, + "w": 15, + "x": 9, + "y": 1 + }, + "id": 27, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": ["max", "min"], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "always", + "stacking": "none", + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "8.5.6", + "repeatDirection": "h", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\nSELECT\n duration_min > 1 AND\n distance > 1 AND\n ( \n start_position.usable_battery_level IS NULL OR\n (end_position.battery_level - end_position.usable_battery_level) = 0 \n ) AS is_sufficiently_precise,\n NULLIF(GREATEST(start_ideal_range_km - end_ideal_range_km, 0), 0) AS range_diff,\n date_trunc('$period', start_date::TIMESTAMP) as local_period,\n drives.*\nFROM drives\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id)\nSELECT\n EXTRACT(EPOCH FROM date_trunc('$period', local_period))*1000 AS date_from,\n EXTRACT(EPOCH FROM date_trunc('$period', local_period + ('1 ' || '$period')::INTERVAL))*1000 AS date_to,\n CASE '$period'\n WHEN 'month' THEN to_char(local_period, 'YYYY Month')\n WHEN 'year' THEN to_char(local_period, 'YYYY')\n WHEN 'week' THEN 'week ' || to_char(local_period, 'WW') || ' starting ' || to_char(local_period, 'YYYY-MM-DD')\n ELSE to_char(local_period, 'YYYY-MM-DD')\n END AS \"Period\",\n local_period AS date,\n sum(duration_min)*60 AS sum_duration_h, \n convert_km(max(end_km)::integer - min(start_km)::integer, '$length_unit') AS sum_distance_$length_unit,\n count(*) AS cnt,\n sum(distance)/sum(range_diff) AS efficiency\nFROM data WHERE\n car_id = $car_id AND\n $__timeFilter(start_date)\nGROUP BY date\nORDER BY date", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "${length_unit} & drives per ${period}", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": ["sum_distance_km", "cnt", "Period"] + } + } + } + ], + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 2, + "includeAll": true, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": true, + "text": "month", + "value": "month" + }, + "hide": 0, + "includeAll": false, + "label": "Period", + "multi": false, + "name": "period", + "options": [ + { + "selected": true, + "text": "month", + "value": "month" + }, + { + "selected": false, + "text": "year", + "value": "year" + }, + { + "selected": false, + "text": "day", + "value": "day" + }, + { + "selected": false, + "text": "week", + "value": "week" + } + ], + "query": "month,year,day,week", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Mileage Stats", + "uid": "jchmNjtMTFx", + "version": 4, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/SpeedRates.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/SpeedRates.json new file mode 100644 index 00000000000..666e8f8c3cc --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/SpeedRates.json @@ -0,0 +1,1218 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "avg_consumption_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. Consumption" + }, + { + "id": "unit", + "value": "Wh/km" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_consumption_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. Consumption" + }, + { + "id": "unit", + "value": "Wh/mi" + }, + { + "id": "custom.width", + "value": 200 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_distance_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. Distance" + }, + { + "id": "unit", + "value": "km" + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-GrYlRd" + } + }, + { + "id": "min" + }, + { + "id": "max" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_distance_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. Distance" + }, + { + "id": "unit", + "value": "mi" + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "max" + }, + { + "id": "min" + }, + { + "id": "color", + "value": { + "mode": "continuous-GrYlRd" + } + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_range_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Segment (km/h)" + }, + { + "id": "custom.width", + "value": 125 + }, + { + "id": "custom.align", + "value": "center" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_range_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Segment (mph)" + }, + { + "id": "custom.width", + "value": 125 + }, + { + "id": "custom.align", + "value": "center" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_speed_km" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg Speed" + }, + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_speed_mi" + }, + "properties": [ + { + "id": "displayName", + "value": "Avg. Speed" + }, + { + "id": "unit", + "value": "velocitymph" + }, + { + "id": "custom.width", + "value": 120 + }, + { + "id": "decimals", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg_power" + }, + "properties": [ + { + "id": "custom.width", + "value": 200 + }, + { + "id": "displayName", + "value": "Avg. Power" + }, + { + "id": "unit", + "value": "kwatt" + }, + { + "id": "decimals", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 13, + "w": 14, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [], + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "enablePagination": false, + "fields": "", + "reducer": ["sum"], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\r\n BinnedData.speed_bin AS speed_range_$length_unit,\r\n convert_km(BinnedData.total_odometer_distance::numeric, '$length_unit') AS avg_distance_$length_unit,\r\n BinnedData.avg_speed * CASE WHEN '$length_unit' = 'km' THEN 1 WHEN '$length_unit' = 'mi' THEN 0.621371 END AS avg_speed_$length_unit,\r\n ((BinnedData.total_energy_consumed / (BinnedData.total_distance * CASE WHEN '$length_unit' = 'km' THEN 1 WHEN '$length_unit' = 'mi' THEN 0.621371 END)) * 1000 ) / (BinnedData.avg_speed * CASE WHEN '$length_unit' = 'km' THEN 1 WHEN '$length_unit' = 'mi' THEN 0.621371 END) AS avg_consumption_$length_unit,\r\n avg_power\r\nFROM\r\n (SELECT\r\n CASE\r\n WHEN elevation_diff >= 1 THEN 'Uphill'\r\n WHEN elevation_diff <= -1 THEN 'Downhill'\r\n ELSE 'Flat'\r\n END AS terrain_type,\r\n ROUND(speed * CASE WHEN '$length_unit' = 'km' THEN 1 WHEN '$length_unit' = 'mi' THEN 0.621371 END / 10, 0) * 10 AS speed_bin,\r\n AVG(power) AS avg_power,\r\n SUM(power::integer * speed::integer / 60.0) AS total_energy_consumed,\r\n SUM(speed / 60.0) AS total_distance,\r\n SUM(odometer_distance) AS total_odometer_distance,\r\n AVG(speed) AS avg_speed,\r\n car_id\r\n FROM\r\n (SELECT\r\n drives.car_id,\r\n positions.speed,\r\n positions.power,\r\n positions.elevation - LAG(positions.elevation) OVER (PARTITION BY positions.drive_id ORDER BY positions.date) AS elevation_diff,\r\n positions.odometer - LAG(positions.odometer) OVER (PARTITION BY positions.drive_id ORDER BY positions.date) AS odometer_distance\r\n FROM\r\n drives\r\n JOIN positions ON drives.id = positions.drive_id\r\n WHERE\r\n $__timeFilter(drives.start_date)\r\n AND drives.car_id = $car_id\r\n AND drives.end_date IS NOT NULL\r\n AND drives.distance >= convert_km($min_distance::numeric, '$length_unit')\r\n ) AS DifferentialData\r\n GROUP BY speed_bin, terrain_type, car_id\r\n ) AS BinnedData\r\nJOIN cars ON BinnedData.car_id = cars.id\r\nWHERE BinnedData.terrain_type = '$terrain_type'\r\n AND BinnedData.total_distance > 0 \r\n AND BinnedData.total_odometer_distance > 0\r\n AND BinnedData.speed_bin >= $min_speed_segment\r\nORDER BY BinnedData.speed_bin DESC;\r\n", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Consumption by speed - $terrain_type Terrain", + "type": "table" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "distance_km" + }, + "properties": [ + { + "id": "unit", + "value": "km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "distance_mi" + }, + "properties": [ + { + "id": "unit", + "value": "mi" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 10, + "x": 14, + "y": 0 + }, + "id": 6, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select convert_km(sum(distance)::numeric, '$length_unit') as \"distance_$length_unit\" \nfrom drives \nwhere $__timeFilter(end_date) and car_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Logged Distance", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "noValue": "N/A", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 14, + "y": 6 + }, + "id": 4, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n sum((start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km) * cars.efficiency) / sum(distance) * 1000 * \n CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END AS \"consumption_$length_unit\"\nfrom drives \ninner join cars on cars.id = car_id\nwhere $__timeFilter(end_date) \n and distance is not null and\n start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km >= 0.1 and\n car_id = $car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Consumption (net)", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "noValue": "N/A", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#c7d0d9", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "consumption_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "consumption_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 3, + "x": 17, + "y": 6 + }, + "id": 8, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["mean"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["mean"], + "fields": "", + "values": false + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH d1 AS (\n\tSELECT\n\t\tc.car_id,\n\t\tlag(end_[[preferred_range]]_range_km) OVER (ORDER BY start_date) - start_[[preferred_range]]_range_km AS range_loss,\n\t\tp.odometer - lag(p.odometer) OVER (ORDER BY start_date) AS distance\n\tFROM\n\t\tcharging_processes c\n\tLEFT JOIN positions p ON p.id = c.position_id \n\tWHERE\n\t $__timeFilter(end_date)\n\t and end_date IS NOT NULL AND\n\t c.car_id = $car_id\n\tORDER BY\n\t\tstart_date\n),\nd2 AS (\nSELECT\n\tcar_id,\n\tsum(range_loss) AS range_loss,\n\tsum(distance) AS distance\nFROM\n\td1\nWHERE\n\tdistance > 0 AND range_loss >= 0\nGROUP BY\n\tcar_id\n)\nSELECT\nrange_loss * c.efficiency / distance * 1000 *\n CASE WHEN '$length_unit' = 'km' THEN 1\n WHEN '$length_unit' = 'mi' THEN 1.60934\n END AS \"consumption_$length_unit\"\nFROM\n\td2\n\tLEFT JOIN cars c ON c.id = car_id", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Consumption (gross) ", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "efficiency_km" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/km" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "efficiency_mi" + }, + "properties": [ + { + "id": "unit", + "value": "Wh/mi" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 20, + "y": 6 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tCASE WHEN '$length_unit' = 'km' THEN efficiency\n\t WHEN '$length_unit' = 'mi' THEN efficiency * 1.60934\n\tEND * 1000 as \"efficiency_$length_unit\"\nFROM\n\tcars\nWHERE\n\tid = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": ["charge_energy_added"], + "type": "column" + } + ] + ], + "table": "charges", + "timeColumn": "date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current $preferred_range efficiency", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "mappings": [], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "seconds_elapsed" + }, + "properties": [ + { + "id": "unit", + "value": "s" + }, + { + "id": "decimals", + "value": 1 + } + ] + } + ] + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 16, + "links": [], + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": true + }, + "showUnfilled": false, + "valueMode": "color" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \r\n speed_section_$length_unit || CASE WHEN '$length_unit' = 'km' THEN ' km/h' WHEN '$length_unit' = 'mi' THEN ' mph' END AS speed,\r\n SUM(seconds_elapsed) AS seconds_elapsed\r\nFROM (\r\n SELECT\r\n ROUND(convert_km(p.speed::numeric, '$length_unit') / 10,0) * 10 AS speed_section_$length_unit,\r\n EXTRACT(EPOCH FROM (LEAD(p.\"date\") OVER (ORDER BY p.\"date\") - p.\"date\")) AS seconds_elapsed\r\n FROM drives d\r\n INNER JOIN positions p ON p.drive_id = d.id\r\n WHERE\r\n $__timeFilter(d.start_date)\r\n AND d.car_id = $car_id \r\n AND d.end_date IS NOT NULL\r\n AND d.distance >= convert_km($min_distance::numeric,'$length_unit')\r\n AND p.speed > 0.1\r\n) AS drivedata\r\nWHERE speed_section_$length_unit >= $min_speed_segment\r\nGROUP BY speed_section_$length_unit\r\nORDER BY speed_section_$length_unit DESC", + "refId": "A", + "select": [ + [ + { + "params": ["value"], + "type": "column" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ], + "limit": 50 + }, + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Speeds", + "type": "bargauge" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": true, + "text": "50", + "value": "50" + }, + "hide": 0, + "includeAll": false, + "label": "Min. speed segment", + "multi": false, + "name": "min_speed_segment", + "options": [ + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": false, + "text": "20", + "value": "20" + }, + { + "selected": false, + "text": "30", + "value": "30" + }, + { + "selected": false, + "text": "40", + "value": "40" + }, + { + "selected": true, + "text": "50", + "value": "50" + } + ], + "query": "10,20,30,40,50", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": { + "selected": true, + "text": "25", + "value": "25" + }, + "hide": 0, + "includeAll": false, + "label": "Min. driving distance", + "multi": false, + "name": "min_distance", + "options": [ + { + "selected": false, + "text": "1", + "value": "1" + }, + { + "selected": false, + "text": "5", + "value": "5" + }, + { + "selected": false, + "text": "10", + "value": "10" + }, + { + "selected": true, + "text": "25", + "value": "25" + }, + { + "selected": false, + "text": "50", + "value": "50" + }, + { + "selected": false, + "text": "100", + "value": "100" + }, + { + "selected": false, + "text": "150", + "value": "150" + }, + { + "selected": false, + "text": "200", + "value": "200" + } + ], + "query": "1,5,10,25,50,100,150,200", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "selected": true, + "text": "Flat", + "value": "Flat" + }, + "hide": 0, + "includeAll": false, + "label": "Terrain Type", + "multi": false, + "name": "terrain_type", + "options": [ + { + "selected": true, + "text": "Flat", + "value": "Flat" + }, + { + "selected": false, + "text": "Uphill", + "value": "Uphill" + }, + { + "selected": false, + "text": "Downhill", + "value": "Downhill" + } + ], + "query": "Flat, Uphill, Downhill", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-30d", + "to": "now" + }, + "timepicker": { + "hidden": false, + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Speed Rates", + "uid": "jchmfu4SiQgWz", + "version": 10, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/dashboards/teslamate2/TrackingDrives.json b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/TrackingDrives.json new file mode 100644 index 00000000000..47a5a0d8b45 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/dashboards/teslamate2/TrackingDrives.json @@ -0,0 +1,1363 @@ +{ + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "geomap", + "name": "Geomap", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "10.1.2" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:24", + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "definition": "TeslaMate|U2FsdGVkX1/cEWK+8cz7pjEKXtzJnDN7b21ZDXt1MGneFGPWTLqOPtxKmu02mJPLzi/f29I+NBHd3vi0FB8R4Xn0+GtobWDgk6VAVSBTdSNniOKO8i2WPlhRaOsl2+hG7gnZ7wrf1Th2nxR7f1uYCrbwOek0IzkfLzrkjh7gkr6inT6bbDuJqrmogZajLxmAMrQ6V+/vHxBRGiwjJhgiEeq3hM1q2h04JKkNiZ8RHbsF5Cd/xd8Q9u0JVrZzIrtnhM/SFlaApU7RtRMu8CSj1llTX7WEOj6VDZAMSf+XUAanWdk725kEPN9MNu89o2zEq5P3E3cju8IbbBdPzXLV3oVuzD6/tMnxFToIIV1E/BrpF7s2RtNa8+KJJ1PF8xgs6m+/KTD2hy+WsP0636AgObRAmYg7+qotGrgNvpNPdE0EgrB7WHYlV7R/1q66bcq6tCe51X1Un70k+zo+K6AK0o4B1H6IyMlEVuRH/Fz8QVl9aYu2ztd08RbuKJlYVKpkH+pxVETAO9MclYQ90tzE6TfwDZrQZzsAlMenr4s1ZB1OlFXjLjVjnddnUilzO76cqv4yI2THQEuyQ47nuVQ4gUbx02K59vMQhns3C01JOAYokOaSXe66Y7QYdMlk09Lf|aes-256-cbc", + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": ["tesla"], + "title": "Dashboards", + "type": "dashboards" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": ["TeslamateCustomDashboards"], + "targetBlank": false, + "title": "Custom Dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to analize a drive based on a date you select, then you can pass the pointer over the lines in graph to see data details and a blue point in the map tranking the route. With this option you can analized a specific point location in the map, to see the speed, power, SOC, elevation and if battery heater was on.\n\nBe aware that the drive you select in the dropdown list from the top could be outside the time range of the Timeline graph, if its the case you have to click on the \"Zoom to data\" button on the graph in order to update it.\n\nTip: On Grafana you can press \"h\" to get a keyboard shortcuts if you want to change the current Zoom out time range or use the mouse to select/change the time range.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "battery_heater" + }, + "properties": [ + { + "id": "displayName", + "value": "Battery heater (On/Off)" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "power" + }, + "properties": [ + { + "id": "displayName", + "value": "Power (kW)" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "elevation_m" + }, + "properties": [ + { + "id": "displayName", + "value": "Elevation (m)" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_kmh" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed (km/h)" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_mih" + }, + "properties": [ + { + "id": "displayName", + "value": "Speed (mi/h)" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "soc" + }, + "properties": [ + { + "id": "displayName", + "value": "SOC (%)" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Battery heater (On/Off)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Elevation" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#ccccdc", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Elevation (m)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Power (kW)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Rated Efficiency (kWh/100km)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SOC (%)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-purple", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Speed (km/h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_kmh" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Elevation" + }, + "properties": [ + { + "id": "decimals", + "value": 0 + }, + { + "id": "min", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Elevation (m)" + }, + "properties": [ + { + "id": "decimals", + "value": 0 + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 17, + "w": 15, + "x": 0, + "y": 0 + }, + "hideTimeOverride": false, + "id": 8, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH journey AS (SELECT start_date, end_date FROM drives WHERE id = $journey)\nSELECT\n\t$__time(date),\n\tAVG(convert_km(speed::numeric, '$length_unit')) AS speed_[[length_unit]]h,\n\tAVG(power) AS Power,\n\tAVG(battery_level) AS SOC,\n\tAVG(battery_heater::integer * 100) AS battery_heater,\n\tAVG(ROUND(convert_m(elevation, '$alternative_length_unit'))) AS elevation_[[alternative_length_unit]]\nFROM\n\tpositions, journey\nWHERE\n car_id = $car_id AND (date BETWEEN journey.start_date AND journey.end_date)\nGROUP BY 1 \nORDER BY\n\tdate ASC", + "refId": "Power", + "select": [ + [ + { + "params": ["id"], + "type": "column" + } + ] + ], + "table": "charging", + "timeColumn": "Datum", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Drive", + "type": "timeseries" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "red", + "mode": "thresholds" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 20, + "w": 9, + "x": 15, + "y": 0 + }, + "id": 18, + "links": [], + "maxDataPoints": 50000, + "options": { + "basemap": { + "config": {}, + "name": "Layer 0", + "type": "osm-standard" + }, + "controls": { + "mouseWheelZoom": true, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "arrow": 0, + "style": { + "color": { + "fixed": "dark-blue" + }, + "lineWidth": 2, + "opacity": 1, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 3, + "max": 15, + "min": 2 + }, + "symbol": { + "field": "", + "fixed": "", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "mode": "auto" + }, + "name": "route", + "opacity": 1, + "tooltip": true, + "type": "route" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "fit", + "lat": 0, + "lon": 0, + "zoom": 15 + } + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "editorMode": "code", + "format": "time_series", + "group": [ + { + "params": ["$__interval", "none"], + "type": "time" + } + ], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH journey AS (SELECT start_date, end_date FROM drives WHERE id = $journey)\nSELECT\n $__time(date), latitude, longitude\nFROM positions, journey\nWHERE\n car_id = $car_id AND (date BETWEEN journey.start_date AND journey.end_date)\nORDER BY date ASC", + "refId": "A", + "select": [ + [ + { + "params": ["lat"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ], + [ + { + "params": ["lng"], + "type": "column" + }, + { + "params": ["avg"], + "type": "aggregate" + }, + { + "params": ["lat"], + "type": "alias" + } + ] + ], + "sql": { + "columns": [ + { + "parameters": [], + "type": "function" + } + ], + "groupBy": [ + { + "property": { + "type": "string" + }, + "type": "groupBy" + } + ] + }, + "table": "pos", + "timeColumn": "Datum", + "timeColumnType": "datetime", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "geomap" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-purple", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "sec_diff" + }, + "properties": [ + { + "id": "displayName", + "value": "Duration" + }, + { + "id": "unit", + "value": "clocks" + }, + { + "id": "decimals", + "value": 1 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "km" + }, + "properties": [ + { + "id": "displayName", + "value": "Consumption" + }, + { + "id": "unit", + "value": "Wh/km" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 0, + "y": 17 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "text": { + "titleSize": 16 + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ((DATE_PART('day', end_date - start_date) * 24 + \n DATE_PART('hour', end_date - start_date)) * 60 +\n DATE_PART('minute', end_date - start_date)) * 60 +\n DATE_PART('second', end_date - start_date) as sec_diff\nFROM drives\nWHERE drives.id = $journey;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\t(NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency) *1000 /\n\t convert_km(distance::numeric, '$length_unit') as \"$length_unit\"\nfrom drives d\nJOIN cars car ON car.id = car_id\nwhere d.id = $journey;", + "refId": "Distance", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "km" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + }, + { + "id": "displayName", + "value": "Distance" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "mi" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + }, + { + "id": "displayName", + "value": "Distance" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_mih" + }, + "properties": [ + { + "id": "unit", + "value": "velocitymih" + }, + { + "id": "displayName", + "value": "Avg Speed" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "speed_kmh" + }, + "properties": [ + { + "id": "unit", + "value": "velocitykmh" + }, + { + "id": "displayName", + "value": "Avg Speed" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 5, + "y": 17 + }, + "id": 12, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": { + "titleSize": 16 + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select convert_km(distance::numeric, '$length_unit') as \"$length_unit\" from drives where id = $journey;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH journey AS (SELECT start_date, end_date FROM drives WHERE id = $journey)\nSELECT\n\tAVG(convert_km(speed::numeric, '$length_unit')) AS speed_[[length_unit]]h\nFROM\n\tpositions, journey\nWHERE\n car_id = $car_id AND (date BETWEEN journey.start_date AND journey.end_date)", + "refId": "B", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "displayName": "Energy used", + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "semi-dark-orange", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 9, + "y": 17 + }, + "id": 16, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "text": { + "titleSize": 16 + }, + "textMode": "value" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\t(NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency)\nFROM\n\tdrives d\nJOIN cars car ON car.id = car_id\nWHERE\n\td.id = $journey;", + "refId": "A", + "select": [ + [ + { + "params": ["latitude"], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Energy used", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 12, + "y": 17 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "center", + "orientation": "vertical", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "/.*/", + "values": false + }, + "text": { + "titleSize": 16 + }, + "textMode": "value_and_name" + }, + "pluginVersion": "10.1.2", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH height as (SELECT\n\televation-LAG(elevation,1) over ( order BY\n\tdate ASC ) as diff\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND (date BETWEEN (SELECT start_date FROM drives WHERE id = $journey) AND (SELECT end_date FROM drives WHERE id = $journey))\nORDER BY\n\tdate ASC\n\t)\nselect convert_m(sum(diff), '$alternative_length_unit') || ' $alternative_length_unit' as \"Up\" from height where diff > 0", + "refId": "A", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH height as (SELECT\n\televation-LAG(elevation,1) over ( order BY\n\tdate ASC ) as diff\nFROM\n\tpositions\nWHERE\n car_id = $car_id AND (date BETWEEN (SELECT start_date FROM drives WHERE id = $journey) AND (SELECT end_date FROM drives WHERE id = $journey))\nORDER BY\n\tdate ASC\n\t)\n\t\n\t\nselect convert_m(sum(diff), '$alternative_length_unit') || ' $alternative_length_unit' as \"Down\" from height where diff < 0", + "refId": "B", + "select": [ + [ + { + "params": ["start_km"], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Elevation", + "type": "stat" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": ["TeslamateCustomDashboards"], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "alternative_length_unit", + "options": [], + "query": "select case when unit_of_length = 'km' then 'm' when unit_of_length = 'mi' then 'ft' end from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT TO_CHAR(start_date, 'YYYY') as year FROM drives\nWHERE car_id = $car_id\nGROUP BY 1\nORDER BY 1 DESC;", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "Year", + "options": [], + "query": "SELECT TO_CHAR(start_date, 'YYYY') as year FROM drives\nWHERE car_id = $car_id\nGROUP BY 1\nORDER BY 1 DESC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "(SELECT TO_CHAR(start_date, 'MM') as month FROM drives WHERE car_id = $car_id ORDER BY start_date DESC LIMIT 1)\nUNION ALL\n(SELECT TO_CHAR(start_date, 'MM') as month FROM drives WHERE car_id = $car_id AND TO_CHAR(start_date, 'YYYY') = '$Year'\nGROUP BY 1\nORDER BY 1);", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "Month", + "options": [], + "query": "(SELECT TO_CHAR(start_date, 'MM') as month FROM drives WHERE car_id = $car_id ORDER BY start_date DESC LIMIT 1)\nUNION ALL\n(SELECT TO_CHAR(start_date, 'MM') as month FROM drives WHERE car_id = $car_id AND TO_CHAR(start_date, 'YYYY') = '$Year'\nGROUP BY 1\nORDER BY 1);", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "(SELECT TO_CHAR(start_date, 'DD') as day FROM drives WHERE car_id = $car_id ORDER BY start_date DESC LIMIT 1)\nUNION ALL\n(SELECT TO_CHAR(start_date, 'DD') as day FROM drives \nWHERE car_id = $car_id AND TO_CHAR(start_date, 'YYYY') = '$Year' AND TO_CHAR(start_date, 'MM') = '$Month'\nGROUP BY 1 ORDER BY 1);", + "hide": 0, + "includeAll": false, + "multi": false, + "name": "Day", + "options": [], + "query": "(SELECT TO_CHAR(start_date, 'DD') as day FROM drives WHERE car_id = $car_id ORDER BY start_date DESC LIMIT 1)\nUNION ALL\n(SELECT TO_CHAR(start_date, 'DD') as day FROM drives \nWHERE car_id = $car_id AND TO_CHAR(start_date, 'YYYY') = '$Year' AND TO_CHAR(start_date, 'MM') = '$Month'\nGROUP BY 1 ORDER BY 1);", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "WITH data AS (\n SELECT\n drives.id as drive_id,\n start_date,\n COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS start_address,\n COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS end_address\n FROM drives\n LEFT JOIN addresses start_address ON start_address_id = start_address.id\n LEFT JOIN addresses end_address ON end_address_id = end_address.id\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id\n LEFT JOIN geofences start_geofence ON start_geofence_id = start_geofence.id\n LEFT JOIN geofences end_geofence ON end_geofence_id = end_geofence.id\n LEFT JOIN cars car ON car.id = drives.car_id\n WHERE drives.car_id = $car_id AND start_date::date = '$Year-$Month-$Day' AND distance > 0 \n ORDER BY start_date DESC\n)\nSELECT\n 'route=\"' || to_char(start_date:: timestamp, 'YYYY-MM-DD') || ' ' || start_address || ' ---> ' || end_address || '\" id=\"' || drive_id || '\"'AS journey\nFROM data;", + "hide": 0, + "includeAll": false, + "label": "Journey", + "multi": false, + "name": "journey", + "options": [], + "query": "WITH data AS (\n SELECT\n drives.id as drive_id,\n start_date,\n COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS start_address,\n COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS end_address\n FROM drives\n LEFT JOIN addresses start_address ON start_address_id = start_address.id\n LEFT JOIN addresses end_address ON end_address_id = end_address.id\n LEFT JOIN positions start_position ON start_position_id = start_position.id\n LEFT JOIN positions end_position ON end_position_id = end_position.id\n LEFT JOIN geofences start_geofence ON start_geofence_id = start_geofence.id\n LEFT JOIN geofences end_geofence ON end_geofence_id = end_geofence.id\n LEFT JOIN cars car ON car.id = drives.car_id\n WHERE drives.car_id = $car_id AND start_date::date = '$Year-$Month-$Day' AND distance > 0 \n ORDER BY start_date DESC\n)\nSELECT\n 'route=\"' || to_char(start_date:: timestamp, 'YYYY-MM-DD') || ' ' || start_address || ' ---> ' || end_address || '\" id=\"' || drive_id || '\"'AS journey\nFROM data;", + "refresh": 1, + "regex": "/route=\"(?[^\"]+)|id=\"(?[^\"]+)/g", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select preferred_range from settings limit 1;", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "preferred_range", + "options": [], + "query": "select preferred_range from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "2023-11-28T12:32:29.961Z", + "to": "2023-11-28T12:40:33.863Z" + }, + "timepicker": { + "hidden": true, + "refresh_intervals": [] + }, + "timezone": "", + "title": "Tracking Drives", + "uid": "jchmX8upc6ZRk", + "version": 3, + "weekStart": "" +} diff --git a/incubator/TeslaMate/0.0.2/ix_values.yaml b/incubator/TeslaMate/0.0.2/ix_values.yaml new file mode 100644 index 00000000000..dc76692a496 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/ix_values.yaml @@ -0,0 +1,84 @@ +image: + repository: teslamate/teslamate + pullPolicy: IfNotPresent + tag: 1.28.5@sha256:aa3f37ecccc7ea77fa1e259391c8f2a05533e208228a42ebb4dbe560828db057 + +securityContext: + container: + readOnlyRootFilesystem: false + +service: + main: + ports: + main: + protocol: http + port: 4000 + +workload: + main: + replicas: 1 + strategy: RollingUpdate + podSpec: + containers: + main: + env: + ENCRYPTION_KEY: + secretKeyRef: + name: teslamate-secrets + key: TESLAMATE_ENCRYPTION_KEY + DATABASE_USER: "{{ .Values.cnpg.main.user }}" + DATABASE_PASS: + secretKeyRef: + name: cnpg-main-user + key: password + DATABASE_NAME: "{{ .Values.cnpg.main.database }}" + DATABASE_HOST: + secretKeyRef: + name: cnpg-main-urls + key: host + DISABLE_MQTT: true + MQTT_HOST: "" + MQTT_PORT: 1883 + MQTT_USERNAME: "" + MQTT_PASSWORD: "" + +configmap: + datasource: + enabled: true + labels: + grafana_datasources: "1" + data: + datasourceteslamatepsql.yaml: |- + apiVersion: 1 + datasources: + - name: TeslaMate + type: postgres + uid: TeslaMate + url: {{ printf "%s.%s:5432" (.Values.cnpg.main.creds.host | trimAll "\"") .Release.Namespace }} + access: proxy + user: {{ .Values.cnpg.main.user }} + secureJsonData: + password: {{ .Values.cnpg.main.creds.password | default "na" }} + jsonData: + database: {{ .Values.cnpg.main.database }} + sslmode: 'disable' # disable/require/verify-ca/verify-full + maxOpenConns: 100 # Grafana v5.4+ + maxIdleConns: 100 # Grafana v5.4+ + maxIdleConnsAuto: true # Grafana v9.5.1+ + connMaxLifetime: 14400 # Grafana v5.4+ + postgresVersion: 1500 # 903=9.3, 904=9.4, 905=9.5, 906=9.6, 1000=10 + timescaledb: false + +portal: + open: + enabled: true + +cnpg: + main: + enabled: true + user: teslamate + database: teslamate + cluster: + initdb: + postInitApplicationSQL: + - ALTER USER teslamate WITH SUPERUSER diff --git a/incubator/TeslaMate/0.0.2/questions.yaml b/incubator/TeslaMate/0.0.2/questions.yaml new file mode 100755 index 00000000000..52a1ff316b0 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/questions.yaml @@ -0,0 +1,2911 @@ +groups: + - name: Container Image + description: Image to be used for container + - name: General Settings + description: General Deployment Settings + - name: Workload Settings + description: Workload Settings + - name: App Configuration + description: App Specific Config Options + - name: Networking and Services + description: Configure Network and Services for Container + - name: Storage and Persistence + description: Persist and Share Data that is Separate from the Container + - name: Ingress + description: Ingress Configuration + - name: Security and Permissions + description: Configure Security Context and Permissions + - name: Resources and Devices + description: "Specify Resources/Devices to be Allocated to Workload" + - name: Middlewares + description: Traefik Middlewares + - name: Metrics + description: Metrics + - name: Addons + description: Addon Configuration + - name: Backup Configuration + description: Configure Velero Backup Schedule + - name: Advanced + description: Advanced Configuration + - name: Postgresql + description: Postgresql + - name: Dependencies + description: Dependencies + - name: Documentation + description: Documentation + +portals: + open: + protocols: + - "$kubernetes-resource_configmap_tcportal-open_protocol" + host: + - "$kubernetes-resource_configmap_tcportal-open_host" + ports: + - "$kubernetes-resource_configmap_tcportal-open_port" + +questions: + - variable: global + group: General Settings + label: "Global Settings" + schema: + additional_attrs: true + type: dict + attrs: + - variable: stopAll + label: Stop All + description: "Stops All Running pods and hibernates cnpg" + schema: + type: boolean + default: false + + - variable: workload + group: "Workload Settings" + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: main + label: "" + schema: + additional_attrs: true + type: dict + attrs: + + - variable: type + label: Type (Advanced) + schema: + type: string + default: Deployment + enum: + - value: Deployment + description: Deployment + - value: DaemonSet + description: DaemonSet + + - variable: replicas + label: Replicas (Advanced) + description: Set the number of Replicas + schema: + type: int + show_if: [["type", "!=", "DaemonSet"]] + default: 1 + + - variable: podSpec + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: containers + label: Containers + schema: + additional_attrs: true + type: dict + attrs: + + - variable: main + label: Main Container + schema: + additional_attrs: true + type: dict + attrs: + + - variable: env + label: "Image Environment" + schema: + additional_attrs: true + type: dict + attrs: + - variable: DISABLE_MQTT + label: "Mqtt Disabled" + description: "Disables the MQTT feature if true" + schema: + type: boolean + default: true + - variable: MQTT_HOST + label: "Mqtt Host" + description: "Hostname of the broker." + schema: + type: string + default: "" + show_if: [["DISABLE_MQTT", "=", false]] + - variable: MQTT_PORT + label: "Mqtt Port" + schema: + type: int + default: 1883 + show_if: [["DISABLE_MQTT", "=", false]] + - variable: MQTT_USERNAME + label: "Mqtt Username" + description: "Username of the broker." + schema: + type: string + default: "" + show_if: [["DISABLE_MQTT", "=", false]] + - variable: MQTT_PASSWORD + label: "Mqtt Password" + description: "Password of the broker." + schema: + type: string + private: true + show_if: [["DISABLE_MQTT", "=", false]] + + - variable: envList + label: Extra Environment Variables + description: "Please be aware that some variables are set in the background, adding duplicates here might cause issues or prevent the app from starting..." + schema: + type: list + default: [] + items: + - variable: envItem + label: Environment Variable + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + - variable: value + label: Value + schema: + type: string + - variable: extraArgs + label: Extra Args + schema: + type: list + default: [] + items: + - variable: arg + label: Arg + schema: + type: string + + - variable: advanced + label: Show Advanced Settings + description: Advanced settings are not covered by TrueCharts Support + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: command + label: Command + schema: + type: list + default: [] + items: + - variable: param + label: Param + schema: + type: string + + - variable: TZ + label: Timezone + group: "General Settings" + schema: + type: string + default: "Etc/UTC" + $ref: + - "definitions/timezone" + + - variable: podOptions + group: "General Settings" + label: "Global Pod Options (Advanced)" + schema: + additional_attrs: true + type: dict + attrs: + - variable: expertPodOpts + label: "Expert - Pod Options" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: hostNetwork + label: "Host Networking" + schema: + type: boolean + default: false + - variable: dnsConfig + label: "DNS Configuration" + schema: + type: dict + additional_attrs: true + attrs: + - variable: options + label: "Options" + schema: + type: list + default: [{"name": "ndots", "value": "1"}] + items: + - variable: optionsEntry + label: "Option Entry" + schema: + type: dict + additional_attrs: true + attrs: + - variable: name + label: "Name" + schema: + type: string + required: true + - variable: value + label: "Value" + schema: + type: string + - variable: nameservers + label: "Nameservers" + schema: + type: list + default: [] + items: + - variable: nsEntry + label: "Nameserver Entry" + schema: + type: string + required: true + - variable: searches + label: "Searches" + schema: + type: list + default: [] + items: + - variable: searchEntry + label: "Search Entry" + schema: + type: string + required: true + + - variable: imagePullSecretList + group: "General Settings" + label: "Image Pull Secrets" + schema: + type: list + default: [] + items: + - variable: pullsecretentry + label: "Pull Secret" + schema: + type: dict + additional_attrs: true + attrs: + - variable: enabled + label: Enabled + schema: + type: boolean + default: true + - variable: data + label: Data + schema: + type: dict + additional_attrs: true + attrs: + - variable: registry + label: "Registry" + schema: + type: string + required: true + default: "https://index.docker.io/v1/" + - variable: username + label: "Username" + schema: + type: string + required: true + default: "" + - variable: password + label: "Password" + schema: + type: string + required: true + private: true + default: "" + - variable: email + label: "Email" + schema: + type: string + required: true + default: "" + + - variable: service + group: Networking and Services + label: Configure Service(s) + schema: + additional_attrs: true + type: dict + attrs: + + - variable: main + label: "Main Service" + description: "The Primary service on which the healthcheck runs, often the webUI" + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable the Service + schema: + type: boolean + default: true + hidden: true + - variable: type + label: Service Type + description: "ClusterIP's are only internally available and Loadbalancer exposes the service using the system loadbalancer" + schema: + type: string + default: LoadBalancer + enum: + - value: LoadBalancer + description: LoadBalancer (Expose Ports) + - value: ClusterIP + description: ClusterIP (Do Not Expose Ports) + + - variable: loadBalancerIP + label: LoadBalancer IP + description: "MetalLB Only: Selects the Loadbalancer IP to expose on. Required when using PortalButton with MetalLB" + schema: + show_if: [["type", "=", "LoadBalancer"]] + type: string + default: "" + - variable: ports + label: "Service's Port(s) Configuration" + schema: + additional_attrs: true + type: dict + attrs: + + - variable: main + label: "Main Service Port Configuration" + schema: + additional_attrs: true + type: dict + attrs: + - variable: port + label: "Port" + description: "This port exposes the container port on the service" + schema: + type: int + default: 10038 + required: true + - variable: serviceexpert + group: Networking and Services + label: Show Expert Config + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + + - variable: scaleExternalInterface + description: Add External Interfaces + label: Add external Interfaces + group: Networking + schema: + type: list + items: + - variable: interfaceConfiguration + description: Interface Configuration + label: Interface Configuration + schema: + additional_attrs: true + type: dict + $ref: + - "normalize/interfaceConfiguration" + attrs: + - variable: hostInterface + description: Please Specify Host Interface + label: Host Interface + schema: + type: string + required: true + $ref: + - "definitions/interface" + - variable: ipam + description: Define how IP Address will be managed + label: IP Address Management + schema: + additional_attrs: true + type: dict + required: true + attrs: + - variable: type + description: Specify type for IPAM + label: IPAM Type + schema: + type: string + required: true + enum: + - value: dhcp + description: Use DHCP + - value: static + description: Use Static IP + - variable: staticIPConfigurations + label: Static IP Addresses + schema: + type: list + show_if: [["type", "=", "static"]] + items: + - variable: staticIP + label: Static IP + schema: + type: ipaddr + cidr: true + - variable: staticRoutes + label: Static Routes + schema: + type: list + show_if: [["type", "=", "static"]] + items: + - variable: staticRouteConfiguration + label: Static Route Configuration + schema: + additional_attrs: true + type: dict + attrs: + - variable: destination + label: Destination + schema: + type: ipaddr + cidr: true + required: true + - variable: gateway + label: Gateway + schema: + type: ipaddr + cidr: false + required: true + + - variable: serviceList + label: Add Manual Custom Services + group: Networking and Services + schema: + type: list + default: [] + items: + - variable: serviceListEntry + label: Custom Service + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable the service + schema: + type: boolean + default: true + hidden: true + - variable: name + label: Name + schema: + type: string + default: "" + - variable: type + label: Service Type + description: "ClusterIP's are only internally available and Loadbalancer exposes the service using the system loadbalancer" + schema: + type: string + default: LoadBalancer + enum: + - value: LoadBalancer + description: LoadBalancer (Expose Ports) + - value: ClusterIP + description: ClusterIP (Do Not Expose Ports) + - value: Simple + description: Deprecated CHANGE THIS + - variable: loadBalancerIP + label: LoadBalancer IP + description: "MetalLB Only: Selects the Loadbalancer IP to expose on. Required when using PortalButton with MetalLB" + schema: + show_if: [["type", "=", "LoadBalancer"]] + type: string + default: "" + - variable: advancedsvcset + label: Show Advanced Service Settings + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: externalIPs + label: "External IP's" + description: "External IP's" + schema: + type: list + default: [] + items: + - variable: externalIP + label: External IP + schema: + type: string + - variable: ipFamilyPolicy + label: IP Family Policy + description: Specify the IP Policy + schema: + type: string + default: SingleStack + enum: + - value: SingleStack + description: SingleStack + - value: PreferDualStack + description: PreferDualStack + - value: RequireDualStack + description: RequireDualStack + - variable: ipFamilies + label: IP Families + description: (Advanced) The IP Families that should be used + schema: + type: list + default: [] + items: + - variable: ipFamily + label: IP Family + schema: + type: string + - variable: portsList + label: Additional Service Ports + schema: + type: list + default: [] + items: + - variable: portsListEntry + label: Custom ports + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable the Port + schema: + type: boolean + default: true + hidden: true + - variable: name + label: Port Name + schema: + type: string + default: "" + - variable: protocol + label: Port Type + schema: + type: string + default: tcp + enum: + - value: http + description: HTTP + - value: https + description: HTTPS + - value: tcp + description: TCP + - value: udp + description: UDP + - variable: targetPort + label: Target Port + description: This port exposes the container port on the service + schema: + type: int + required: true + - variable: port + label: Container Port + schema: + type: int + required: true + + - variable: persistence + label: Integrated Persistent Storage + description: Integrated Persistent Storage + group: Storage and Persistence + schema: + additional_attrs: true + type: dict + attrs: + + - variable: type + label: Type of Storage + description: Sets the persistence type, Anything other than PVC could break rollback! + schema: + type: string + default: pvc + enum: + - value: pvc + description: PVC + - value: hostPath + description: Host Path + - value: emptyDir + description: emptyDir + - value: nfs + description: NFS Share + - value: iscsi + description: iSCSI Share + - variable: server + label: NFS Server + schema: + show_if: [["type", "=", "nfs"]] + type: string + default: "" + - variable: path + label: Path on NFS Server + schema: + show_if: [["type", "=", "nfs"]] + type: string + default: "" + - variable: iscsi + label: iSCSI Options + schema: + show_if: [["type", "=", "iscsi"]] + type: dict + additional_attrs: true + attrs: + - variable: targetPortal + label: targetPortal + schema: + type: string + required: true + default: "" + - variable: iqn + label: iqn + schema: + type: string + required: true + default: "" + - variable: lun + label: lun + schema: + type: int + default: 0 + - variable: authSession + label: authSession + schema: + type: dict + additional_attrs: true + attrs: + - variable: username + label: username + schema: + type: string + default: "" + - variable: password + label: password + schema: + type: string + default: "" + - variable: usernameInitiator + label: usernameInitiator + schema: + type: string + default: "" + - variable: passwordInitiator + label: passwordInitiator + schema: + type: string + default: "" + - variable: authDiscovery + label: authDiscovery + schema: + type: dict + additional_attrs: true + attrs: + - variable: username + label: username + schema: + type: string + default: "" + - variable: password + label: password + schema: + type: string + default: "" + - variable: usernameInitiator + label: usernameInitiator + schema: + type: string + default: "" + - variable: passwordInitiator + label: passwordInitiator + schema: + type: string + default: "" + + - variable: autoPermissions + label: Automatic Permissions Configuration + description: Automatically set permissions + schema: + show_if: [["type", "!=", "pvc"]] + type: dict + additional_attrs: true + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: chown + label: Run CHOWN + description: | + It will run CHOWN on the path with the given fsGroup + schema: + type: boolean + default: false + - variable: chmod + label: Run CHMOD + description: | + It will run CHMOD on the path with the given value
+ Format should be 3 digits, e.g. 770 + schema: + type: string + valid_chars: '[0-9]{3}' + default: "" + - variable: recursive + label: Recursive + description: | + It will run CHOWN and CHMOD recursively + schema: + type: boolean + default: false + - variable: readOnly + label: Read Only + schema: + type: boolean + default: false + - variable: hostPath + label: Host Path + description: Path inside the container the storage is mounted + schema: + show_if: [["type", "=", "hostPath"]] + type: hostpath + - variable: medium + label: EmptyDir Medium + schema: + show_if: [["type", "=", "emptyDir"]] + type: string + default: "" + enum: + - value: "" + description: Default + - value: Memory + description: Memory + - variable: size + label: Size quotum of Storage (Do NOT REDUCE after installation) + description: This value can ONLY be INCREASED after the installation + schema: + show_if: [["type", "=", "pvc"]] + type: string + default: 256Gi + - variable: storageClass + label: 'storageClass (Advanced)' + description: 'sets the storageClass to something other than iX default. Only for advanced usecases!' + schema: + show_if: [["type", "=", "pvc"]] + type: string + default: "" + - variable: static + label: 'Static Fixed PVC Bindings (Experimental)' + description: Link a PVC to a specific storage location + schema: + show_if: [["type", "=", "pvc"]] + type: dict + additional_attrs: true + attrs: + - variable: mode + label: mode + description: | + disabled: use normal dynamic PVCs + smb: connect to an SMB share + nfs: connect to an NFS share + schema: + type: string + default: "disabled" + enum: + - value: disabled + description: disabled + - value: smb + description: smb + - value: nfs + description: nfs + - variable: server + label: Server + description: server to connect to + schema: + type: string + show_if: [["mode", "!=", "disabled"]] + default: "myserver" + - variable: share + label: Share + description: share to connect to + schema: + type: string + show_if: [["mode", "!=", "disabled"]] + default: "/myshare" + - variable: user + label: User + description: connecting user + schema: + type: string + show_if: [["mode", "=", "smb"]] + default: "myuser" + - variable: domain + label: Domain + description: user domain + schema: + type: string + show_if: [["mode", "=", "smb"]] + default: "" + - variable: password + label: Password + description: connecting password + schema: + type: string + show_if: [["mode", "=", "smb"]] + default: "" + - variable: volumeSnapshots + label: 'Volume Snapshots (Experimental)' + description: Add an entry to the list to force creation of a volumeSnapshot of this PVC + schema: + show_if: [["type", "=", "pvc"]] + type: list + default: [] + items: + - variable: volumeSnapshotEntry + label: Custom volumeSnapshot + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + description: 'WARNING: renaming this, means deletion of the snapshot with the old name!' + schema: + type: string + default: "mysnapshot" + required: true + - variable: volumeSnapshotClassName + label: 'volumeSnapshot Class Name (Advanced)' + description: For use with PVCs using a non-default storageClass + schema: + type: string + default: "" + + - variable: persistenceList + label: Additional App Storage + group: Storage and Persistence + schema: + type: list + default: [] + items: + - variable: persistenceListEntry + label: Custom Storage + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable the storage + schema: + type: boolean + default: true + hidden: true + - variable: type + label: Type of Storage + description: Sets the persistence type, Anything other than PVC could break rollback! + schema: + type: string + default: hostPath + enum: + - value: pvc + description: PVC + - value: hostPath + description: Host Path + - value: emptyDir + description: emptyDir + - value: nfs + description: NFS Share + - variable: server + label: NFS Server + schema: + show_if: [["type", "=", "nfs"]] + type: string + default: "" + - variable: path + label: Path on NFS Server + schema: + show_if: [["type", "=", "nfs"]] + type: string + default: "" + - variable: iscsi + label: iSCSI Options + schema: + show_if: [["type", "=", "iscsi"]] + type: dict + additional_attrs: true + attrs: + - variable: targetPortal + label: targetPortal + schema: + type: string + required: true + default: "" + - variable: iqn + label: iqn + schema: + type: string + required: true + default: "" + - variable: lun + label: lun + schema: + type: int + default: 0 + - variable: authSession + label: authSession + schema: + type: dict + additional_attrs: true + attrs: + - variable: username + label: username + schema: + type: string + default: "" + - variable: password + label: password + schema: + type: string + default: "" + - variable: usernameInitiator + label: usernameInitiator + schema: + type: string + default: "" + - variable: passwordInitiator + label: passwordInitiator + schema: + type: string + default: "" + - variable: authDiscovery + label: authDiscovery + schema: + type: dict + additional_attrs: true + attrs: + - variable: username + label: username + schema: + type: string + default: "" + - variable: password + label: password + schema: + type: string + default: "" + - variable: usernameInitiator + label: usernameInitiator + schema: + type: string + default: "" + - variable: passwordInitiator + label: passwordInitiator + schema: + type: string + default: "" + - variable: autoPermissions + label: Automatic Permissions Configuration + description: Automatically set permissions + schema: + show_if: [["type", "!=", "pvc"]] + type: dict + additional_attrs: true + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: chown + label: Run CHOWN + description: | + It will run CHOWN on the path with the given fsGroup + schema: + type: boolean + default: false + - variable: chmod + label: Run CHMOD + description: | + It will run CHMOD on the path with the given value
+ Format should be 3 digits, e.g. 770 + schema: + type: string + valid_chars: '[0-9]{3}' + default: "" + - variable: recursive + label: Recursive + description: | + It will run CHOWN and CHMOD recursively + schema: + type: boolean + default: false + - variable: readOnly + label: Read Only + schema: + type: boolean + default: false + - variable: hostPath + label: Host Path + description: Path inside the container the storage is mounted + schema: + show_if: [["type", "=", "hostPath"]] + type: hostpath + - variable: mountPath + label: Mount Path + description: Path inside the container the storage is mounted + schema: + type: string + default: "" + required: true + valid_chars: '^\/([a-zA-Z0-9._-]+(\s?[a-zA-Z0-9._-]+|\/?))+$' + - variable: medium + label: EmptyDir Medium + schema: + show_if: [["type", "=", "emptyDir"]] + type: string + default: "" + enum: + - value: "" + description: Default + - value: Memory + description: Memory + - variable: size + label: Size Quotum of Storage + schema: + show_if: [["type", "=", "pvc"]] + type: string + default: 256Gi + - variable: storageClass + label: 'storageClass (Advanced)' + description: 'sets the storageClass to something other than iX default. Only for advanced usecases!' + schema: + show_if: [["type", "=", "pvc"]] + type: string + default: "" + - variable: static + label: 'Static Fixed PVC Bindings (Experimental)' + description: Link a PVC to a specific storage location + schema: + show_if: [["type", "=", "pvc"]] + type: dict + additional_attrs: true + attrs: + - variable: mode + label: mode + description: | + disabled: use normal dynamic PVCs + smb: connect to an SMB share + nfs: connect to an NFS share + schema: + type: string + default: "disabled" + enum: + - value: "disabled" + description: disabled + - value: smb + description: smb + - value: nfs + description: nfs + - variable: server + label: Server + description: server to connect to + schema: + type: string + show_if: [["mode", "!=", "disabled"]] + default: "myserver" + - variable: share + label: Share + description: share to connect to + schema: + type: string + show_if: [["mode", "!=", "disabled"]] + default: "/myshare" + - variable: user + label: User + description: connecting user + schema: + type: string + show_if: [["mode", "=", "smb"]] + default: "myuser" + - variable: domain + label: Domain + description: user domain + schema: + type: string + show_if: [["mode", "=", "smb"]] + default: "" + - variable: password + label: Password + description: connecting password + schema: + type: string + show_if: [["mode", "=", "smb"]] + default: "" + - variable: volumeSnapshots + label: 'Volume Snapshots (Experimental)' + description: Add an entry to the list to force creation of a volumeSnapshot of this PVC + schema: + show_if: [["type", "=", "pvc"]] + type: list + default: [] + items: + - variable: volumeSnapshotEntry + label: Custom volumeSnapshot + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + description: 'WARNING: renaming this, means deletion of the snapshot with the old name!' + schema: + type: string + default: "mysnapshot" + required: true + - variable: volumeSnapshotClassName + label: 'volumeSnapshot Class Name (Advanced)' + description: For use with PVCs using a non-default storageClass + schema: + type: string + default: "" + + - variable: ingress + label: "" + group: Ingress + schema: + additional_attrs: true + type: dict + attrs: + + - variable: main + label: "Main Ingress" + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable Ingress + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: hosts + label: Hosts + schema: + type: list + default: [] + items: + - variable: hostEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: host + label: HostName + schema: + type: string + default: "" + required: true + - variable: paths + label: Paths + schema: + type: list + default: [{path: "/", pathType: "Prefix"}] + items: + - variable: pathEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: path + label: Path + schema: + type: string + required: true + default: "/" + - variable: pathType + label: Path Type + schema: + type: string + required: true + default: Prefix + + - variable: integrations + label: Integrations + description: Connect ingress with other charts + schema: + additional_attrs: true + type: dict + attrs: + - variable: traefik + label: Traefik + description: Connect ingress with Traefik + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: true + - variable: allowCors + label: 'Allow Cross Origin Requests (advanced)' + schema: + type: boolean + default: false + show_if: [["enabled", "=", true]] + - variable: entrypoints + label: Entrypoints + schema: + type: list + default: ["websecure"] + show_if: [["enabled", "=", true]] + items: + - variable: entrypoint + label: Entrypoint + schema: + type: string + - variable: middlewares + label: Middlewares + schema: + type: list + default: [] + show_if: [["enabled", "=", true]] + items: + - variable: middleware + label: Middleware + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: name + schema: + type: string + default: "" + required: true + - variable: namespace + label: 'namespace (optional)' + schema: + type: string + default: "" + - variable: certManager + label: certManager + description: Connect ingress with certManager + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: false + - variable: certificateIssuer + label: certificateIssuer + description: defaults to chartname + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: homepage + label: Homepage + description: Connect ingress with Homepage + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: false + - variable: name + label: Name (Optional) + description: Defaults to chart name + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: description + label: Description (Optional) + description: Defaults to chart description + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: icon + label: Icon (Optional) + description: Defaults to chart icon + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: group + label: Group + schema: + type: string + required: true + default: "default" + show_if: [["enabled", "=", true]] + - variable: widget + label: Widget Settings + schema: + type: dict + additional_attrs: true + show_if: [["enabled", "=", true]] + attrs: + - variable: enabled + label: Enable Widget + description: When disabled all widget annotations are skipped. + schema: + type: boolean + default: true + - variable: custom + label: Options + schema: + type: dict + additional_attrs: true + attrs: + - variable: key + label: API-key (key) + schema: + type: string + default: "" + - variable: customkv + label: Custom Options + schema: + type: list + default: [] + items: + - variable: option + label: Option + schema: + additional_attrs: true + type: dict + attrs: + - variable: key + label: Key + schema: + type: string + default: "" + required: true + - variable: value + label: Value + schema: + type: string + default: "" + required: true + - variable: advanced + label: Show Advanced Settings + description: Advanced settings are not covered by TrueCharts Support + schema: + type: boolean + default: false + - variable: ingressClassName + label: (Advanced/Optional) IngressClass Name + schema: + type: string + show_if: [["advanced", "=", true]] + default: "" + - variable: tls + label: TLS-Settings + schema: + type: list + show_if: [["advanced", "=", true]] + default: [] + items: + - variable: tlsEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: hosts + label: Certificate Hosts + schema: + type: list + default: [] + items: + - variable: host + label: Host + schema: + type: string + default: "" + required: true + + - variable: certificateIssuer + label: Use Cert-Manager clusterIssuer + description: 'add the name of your cert-manager clusterIssuer here for automatic tls certificates.' + schema: + type: string + default: "" + - variable: clusterCertificate + label: 'Cluster Certificate (Advanced)' + description: 'Add the name of your cluster-wide certificate, that you set up in the ClusterIssuer chart.' + schema: + type: string + show_if: [["certificateIssuer", "=", ""]] + default: "" + - variable: secretName + label: 'Use Custom Certificate Secret (Advanced)' + schema: + show_if: [["certificateIssuer", "=", ""]] + type: string + default: "" + + - variable: ingressList + label: Add Manual Custom Ingresses + group: Ingress + schema: + type: list + default: [] + items: + - variable: ingressListEntry + label: Custom Ingress + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable Ingress + schema: + type: boolean + default: true + hidden: true + - variable: name + label: Name + schema: + type: string + default: "" + - variable: ingressClassName + label: IngressClass Name + schema: + type: string + default: "" + - variable: hosts + label: Hosts + schema: + type: list + default: [] + items: + - variable: hostEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: host + label: HostName + schema: + type: string + default: "" + required: true + - variable: paths + label: Paths + schema: + type: list + default: [] + items: + - variable: pathEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: path + label: Path + schema: + type: string + required: true + default: "/" + - variable: pathType + label: Path Type + schema: + type: string + required: true + default: Prefix + - variable: overrideService + label: Linked Service + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Service Name + schema: + type: string + default: "" + - variable: port + label: Service Port + schema: + type: int + - variable: tls + label: TLS-Settings + schema: + type: list + default: [] + show_if: [["certificateIssuer", "=", ""]] + items: + - variable: tlsEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: hosts + label: Certificate Hosts + schema: + type: list + default: [] + items: + - variable: host + label: Host + schema: + type: string + default: "" + required: true + - variable: certificateIssuer + label: Use Cert-Manager clusterIssuer + description: 'add the name of your Cert-Manager clusterIssuer here for automatic tls certificates.' + schema: + type: string + default: "" + - variable: clusterCertificate + label: 'Cluster Certificate (Advanced)' + description: 'Add the name of your cluster-wide certificate, that you set up in the ClusterIssuer chart.' + schema: + type: string + show_if: [["certificateIssuer", "=", ""]] + default: "" + - variable: secretName + label: Use Custom Secret (Advanced) + schema: + type: string + show_if: [["certificateIssuer", "=", ""]] + default: "" + - variable: integrations + label: Integrations + description: Connect ingress with other charts + schema: + additional_attrs: true + type: dict + attrs: + - variable: traefik + label: Traefik + description: Connect ingress with Traefik + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: true + - variable: allowCors + label: "Allow Cross Origin Requests" + schema: + type: boolean + default: false + show_if: [["enabled", "=", true]] + - variable: entrypoints + label: Entrypoints + schema: + type: list + default: ["websecure"] + show_if: [["enabled", "=", true]] + items: + - variable: entrypoint + label: Entrypoint + schema: + type: string + - variable: middlewares + label: Middlewares + schema: + type: list + default: [] + show_if: [["enabled", "=", true]] + items: + - variable: middleware + label: Middleware + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: name + schema: + type: string + default: "" + required: true + - variable: namespace + label: namespace + schema: + type: string + default: "" + - variable: certManager + label: certManager + description: Connect ingress with certManager + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: true + - variable: certificateIssuer + label: certificateIssuer + description: defaults to chartname + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: homepage + label: Homepage + description: Connect ingress with Homepage + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: false + - variable: name + label: Name + description: defaults to chartname + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: description + label: Description + description: defaults to chart description + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: group + label: Group + schema: + type: string + required: true + default: "default" + show_if: [["enabled", "=", true]] + + - variable: securityContext + group: Security and Permissions + label: Security Context + schema: + additional_attrs: true + type: dict + attrs: + - variable: container + label: Container + schema: + additional_attrs: true + type: dict + attrs: + # Settings from questions.yaml get appended here on a per-app basis + + - variable: runAsUser + label: "runAsUser" + description: "The UserID of the user running the application" + schema: + type: int + default: 568 + - variable: runAsGroup + label: "runAsGroup" + description: "The groupID of the user running the application" + schema: + type: int + default: 568 + # Settings from questions.yaml get appended here on a per-app basis + - variable: PUID + label: Process User ID - PUID + description: When supported by the container, this sets the User ID running the Application Process. Not supported by all Apps + schema: + type: int + show_if: [["runAsUser", "=", 0]] + default: 568 + - variable: UMASK + label: UMASK + description: When supported by the container, this sets the UMASK for the App. Not supported by all Apps + schema: + type: string + default: "0022" + + - variable: advanced + label: Show Advanced Settings + description: Advanced settings are not covered by TrueCharts Support + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: privileged + label: "Privileged mode" + schema: + type: boolean + default: false + - variable: readOnlyRootFilesystem + label: "ReadOnly Root Filesystem" + schema: + type: boolean + default: true + + - variable: pod + label: Pod + schema: + additional_attrs: true + type: dict + attrs: + - variable: fsGroupChangePolicy + label: "When should we take ownership?" + schema: + type: string + default: OnRootMismatch + enum: + - value: OnRootMismatch + description: OnRootMismatch + - value: Always + description: Always + - variable: supplementalGroups + label: Supplemental Groups + schema: + type: list + default: [] + items: + - variable: supplementalGroupsEntry + label: Supplemental Group + schema: + type: int + # Settings from questions.yaml get appended here on a per-app basis + + - variable: fsGroup + label: "fsGroup" + description: "The group that should own ALL storage." + schema: + type: int + default: 568 + - variable: resources + group: Resources and Devices + label: "Resource Limits" + schema: + additional_attrs: true + type: dict + attrs: + - variable: limits + label: Advanced Limit Resource Consumption + schema: + additional_attrs: true + type: dict + attrs: + - variable: cpu + label: CPU + description: "1000m means 1 hyperthread. Detailed info: https://truecharts.org/manual/SCALE/validation" + schema: + type: string + default: 4000m + valid_chars: '^(?!^0(\.0|m|)$)([0-9]+)(\.[0-9]|m?)$' + - variable: memory + label: RAM + description: "1Gi means 1 Gibibyte RAM. Detailed info: https://truecharts.org/manual/SCALE/validation" + schema: + type: string + default: 8Gi + valid_chars: '^(?!^0(e[0-9]|[EPTGMK]i?|)$)([0-9]+)(|[EPTGMK]i?|e[0-9]+)$' + - variable: 'gpu.intel.com/i915' + label: Add Intel i915 GPUs + schema: + type: int + default: 0 + - variable: 'nvidia.com/gpu' + label: Add NVIDIA GPUs (Experimental) + schema: + type: int + default: 0 + - variable: 'amd.com/gpu' + label: Add AMD GPUs + schema: + type: int + default: 0 + - variable: requests + label: "Minimum Resources Required (request)" + schema: + additional_attrs: true + type: dict + hidden: true + attrs: + - variable: cpu + label: CPU + description: "1000m means 1 hyperthread. Detailed info: https://truecharts.org/manual/SCALE/validation" + schema: + type: string + default: 10m + hidden: true + valid_chars: '^(?!^0(\.0|m|)$)([0-9]+)(\.[0-9]|m?)$' + - variable: memory + label: "RAM" + description: "1Gi means 1 Gibibyte RAM. Detailed info: https://truecharts.org/manual/SCALE/validation" + schema: + type: string + default: 50Mi + hidden: true + valid_chars: '^(?!^0(e[0-9]|[EPTGMK]i?|)$)([0-9]+)(|[EPTGMK]i?|e[0-9]+)$' + - variable: deviceList + label: Mount USB Devices + group: Resources and Devices + schema: + type: list + default: [] + items: + - variable: deviceListEntry + label: Device + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable the Storage + schema: + type: boolean + default: true + - variable: type + label: (Advanced) Type of Storage + description: Sets the persistence type + schema: + type: string + default: device + hidden: true + - variable: readOnly + label: readOnly + schema: + type: boolean + default: false + - variable: hostPath + label: Host Device Path + description: Path to the device on the host system + schema: + type: path + - variable: mountPath + label: Container Device Path + description: Path inside the container the device is mounted + schema: + type: string + default: "/dev/ttyACM0" + + - variable: metrics + group: Metrics + label: Prometheus Metrics + schema: + additional_attrs: true + type: dict + attrs: + - variable: main + label: Main Metrics + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enabled + description: Enable Prometheus Metrics + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + + - variable: prometheusRule + label: PrometheusRule + description: Enable and configure Prometheus Rules for the App. + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enabled + description: Enable Prometheus Metrics + schema: + type: boolean + default: false + # TODO: Rule List section + +# - variable: horizontalPodAutoscaler +# group: Advanced +# label: (Advanced) Horizontal Pod Autoscaler +# schema: +# type: list +# default: [] +# items: +# - variable: hpaEntry +# label: HPA Entry +# schema: +# additional_attrs: true +# type: dict +# attrs: +# - variable: name +# label: Name +# schema: +# type: string +# required: true +# default: "" +# - variable: enabled +# label: Enabled +# schema: +# type: boolean +# default: false +# show_subquestions_if: true +# subquestions: +# - variable: target +# label: Target +# description: Deployment name, Defaults to Main Deployment +# schema: +# type: string +# default: "" +# - variable: minReplicas +# label: Minimum Replicas +# schema: +# type: int +# default: 1 +# - variable: maxReplicas +# label: Maximum Replicas +# schema: +# type: int +# default: 5 +# - variable: targetCPUUtilizationPercentage +# label: Target CPU Utilization Percentage +# schema: +# type: int +# default: 80 +# - variable: targetMemoryUtilizationPercentage +# label: Target Memory Utilization Percentage +# schema: +# type: int +# default: 80 + - variable: networkPolicy + group: Advanced + label: (Advanced) Network Policy + schema: + type: list + default: [] + items: + - variable: netPolicyEntry + label: Network Policy Entry + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + default: "" + - variable: enabled + label: Enabled + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: policyType + label: Policy Type + schema: + type: string + default: "" + enum: + - value: "" + description: Default + - value: ingress + description: Ingress + - value: egress + description: Egress + - value: ingress-egress + description: Ingress and Egress + - variable: egress + label: Egress + schema: + type: list + default: [] + items: + - variable: egressEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: to + label: To + schema: + type: list + default: [] + items: + - variable: toEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: ipBlock + label: IP Block + schema: + additional_attrs: true + type: dict + attrs: + - variable: cidr + label: CIDR + schema: + type: string + default: "" + - variable: except + label: Except + schema: + type: list + default: [] + items: + - variable: exceptint + label: "" + schema: + type: string + - variable: namespaceSelector + label: Namespace Selector + schema: + additional_attrs: true + type: dict + attrs: + - variable: matchExpressions + label: Match Expressions + schema: + type: list + default: [] + items: + - variable: expressionEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: key + label: Key + schema: + type: string + - variable: operator + label: Operator + schema: + type: string + default: TCP + enum: + - value: In + description: In + - value: NotIn + description: NotIn + - value: Exists + description: Exists + - value: DoesNotExist + description: DoesNotExist + - variable: values + label: Values + schema: + type: list + default: [] + items: + - variable: value + label: "" + schema: + type: string + - variable: podSelector + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: matchExpressions + label: Match Expressions + schema: + type: list + default: [] + items: + - variable: expressionEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: key + label: Key + schema: + type: string + - variable: operator + label: Operator + schema: + type: string + default: TCP + enum: + - value: In + description: In + - value: NotIn + description: NotIn + - value: Exists + description: Exists + - value: DoesNotExist + description: DoesNotExist + - variable: values + label: Values + schema: + type: list + default: [] + items: + - variable: value + label: "" + schema: + type: string + - variable: ports + label: Ports + schema: + type: list + default: [] + items: + - variable: portsEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: port + label: Port + schema: + type: int + - variable: endPort + label: End Port + schema: + type: int + - variable: protocol + label: Protocol + schema: + type: string + default: TCP + enum: + - value: TCP + description: TCP + - value: UDP + description: UDP + - value: SCTP + description: SCTP + - variable: ingress + label: Ingress + schema: + type: list + default: [] + items: + - variable: ingressEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: from + label: From + schema: + type: list + default: [] + items: + - variable: fromEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: ipBlock + label: IP Block + schema: + additional_attrs: true + type: dict + attrs: + - variable: cidr + label: CIDR + schema: + type: string + default: "" + - variable: except + label: Except + schema: + type: list + default: [] + items: + - variable: exceptint + label: "" + schema: + type: string + - variable: namespaceSelector + label: Namespace Selector + schema: + additional_attrs: true + type: dict + attrs: + - variable: matchExpressions + label: Match Expressions + schema: + type: list + default: [] + items: + - variable: expressionEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: key + label: Key + schema: + type: string + - variable: operator + label: Operator + schema: + type: string + default: TCP + enum: + - value: In + description: In + - value: NotIn + description: NotIn + - value: Exists + description: Exists + - value: DoesNotExist + description: DoesNotExist + - variable: values + label: Values + schema: + type: list + default: [] + items: + - variable: value + label: "" + schema: + type: string + - variable: podSelector + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: matchExpressions + label: Match Expressions + schema: + type: list + default: [] + items: + - variable: expressionEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: key + label: Key + schema: + type: string + - variable: operator + label: Operator + schema: + type: string + default: TCP + enum: + - value: In + description: In + - value: NotIn + description: NotIn + - value: Exists + description: Exists + - value: DoesNotExist + description: DoesNotExist + - variable: values + label: Values + schema: + type: list + default: [] + items: + - variable: value + label: "" + schema: + type: string + - variable: ports + label: Ports + schema: + type: list + default: [] + items: + - variable: portsEntry + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: port + label: Port + schema: + type: int + - variable: endPort + label: End Port + schema: + type: int + - variable: protocol + label: Protocol + schema: + type: string + default: TCP + enum: + - value: TCP + description: TCP + - value: UDP + description: UDP + - value: SCTP + description: SCTP + + - variable: addons + group: Addons + label: "" + schema: + additional_attrs: true + type: dict + attrs: + + - variable: codeserver + label: Codeserver + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enabled + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: service + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: type + label: Service Type + description: "ClusterIP's are only internally available and Loadbalancer exposes the service using the system loadbalancer" + schema: + type: string + default: LoadBalancer + enum: + - value: NodePort + description: Deprecated CHANGE THIS + - value: ClusterIP + description: ClusterIP + - value: LoadBalancer + description: LoadBalancer + - variable: loadBalancerIP + label: LoadBalancer IP + description: "MetalLB Only: Selects the Loadbalancer IP to expose on. Required when using PortalButton with MetalLB" + schema: + show_if: [["type", "=", "LoadBalancer"]] + type: string + default: "" + - variable: ports + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: codeserver + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: port + label: Port + schema: + type: int + default: 36107 + - variable: ingress + label: "Ingress" + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enable Ingress + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: hosts + label: Hosts + schema: + type: list + default: [] + items: + - variable: hostEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: host + label: HostName + schema: + type: string + default: "" + required: true + - variable: paths + label: Paths + schema: + type: list + default: [{path: "/", pathType: "Prefix"}] + items: + - variable: pathEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: path + label: Path + schema: + type: string + required: true + default: "/" + - variable: pathType + label: Path Type + schema: + type: string + required: true + default: Prefix + - variable: integrations + label: Integrations + description: Connect ingress with other charts + schema: + additional_attrs: true + type: dict + attrs: + - variable: traefik + label: Traefik + description: Connect ingress with Traefik + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: true + - variable: allowCors + label: 'Allow Cross Origin Requests (advanced)' + schema: + type: boolean + default: false + show_if: [["enabled", "=", true]] + - variable: entrypoints + label: Entrypoints + schema: + type: list + default: ["websecure"] + show_if: [["enabled", "=", true]] + items: + - variable: entrypoint + label: Entrypoint + schema: + type: string + - variable: middlewares + label: Middlewares + schema: + type: list + default: [] + show_if: [["enabled", "=", true]] + items: + - variable: middleware + label: Middleware + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: name + schema: + type: string + default: "" + required: true + - variable: namespace + label: 'namespace (optional)' + schema: + type: string + default: "" + - variable: certManager + label: certManager + description: Connect ingress with certManager + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: enabled + schema: + type: boolean + default: false + - variable: certificateIssuer + label: certificateIssuer + description: defaults to chartname + schema: + type: string + default: "" + show_if: [["enabled", "=", true]] + - variable: advanced + label: Show Advanced Settings + description: Advanced settings are not covered by TrueCharts Support + schema: + type: boolean + default: false + - variable: ingressClassName + label: (Advanced/Optional) IngressClass Name + schema: + type: string + show_if: [["advanced", "=", true]] + default: "" + - variable: tls + label: TLS-Settings + schema: + type: list + show_if: [["advanced", "=", true]] + default: [] + items: + - variable: tlsEntry + label: Host + schema: + additional_attrs: true + type: dict + attrs: + - variable: hosts + label: Certificate Hosts + schema: + type: list + default: [] + items: + - variable: host + label: Host + schema: + type: string + default: "" + required: true + + - variable: certificateIssuer + label: Use Cert-Manager clusterIssuer + description: 'add the name of your cert-manager clusterIssuer here for automatic tls certificates.' + schema: + type: string + default: "" + - variable: clusterCertificate + label: 'Cluster Certificate (Advanced)' + description: 'Add the name of your cluster-wide certificate, that you set up in the ClusterIssuer chart.' + schema: + type: string + show_if: [["certificateIssuer", "=", ""]] + default: "" + - variable: secretName + label: 'Use Custom Certificate Secret (Advanced)' + schema: + show_if: [["certificateIssuer", "=", ""]] + type: string + default: "" + - variable: scaleCert + label: 'Use TrueNAS SCALE Certificate (Deprecated)' + schema: + show_if: [["certificateIssuer", "=", ""]] + type: int + $ref: + - "definitions/certificate" + - variable: envList + label: Codeserver Environment Variables + schema: + type: list + show_if: [["type", "!=", "disabled"]] + default: [] + items: + - variable: envItem + label: Environment Variable + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + - variable: value + label: Value + schema: + type: string + required: true + + - variable: netshoot + label: Netshoot + schema: + additional_attrs: true + type: dict + attrs: + - variable: enabled + label: Enabled + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: envList + label: Netshoot Environment Variables + schema: + type: list + show_if: [["type", "!=", "disabled"]] + default: [] + items: + - variable: envItem + label: Environment Variable + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + - variable: value + label: Value + schema: + type: string + required: true + + - variable: vpn + label: VPN + schema: + additional_attrs: true + type: dict + attrs: + - variable: type + label: Type + schema: + type: string + default: disabled + enum: + - value: disabled + description: disabled + - value: gluetun + description: Gluetun + - value: tailscale + description: Tailscale + - value: openvpn + description: OpenVPN (Deprecated) + - value: wireguard + description: Wireguard (Deprecated) + - variable: openvpn + label: OpenVPN Settings + schema: + additional_attrs: true + type: dict + show_if: [["type", "=", "openvpn"]] + attrs: + - variable: username + label: Authentication Username (Optional) + description: Authentication Username, Optional + schema: + type: string + default: "" + - variable: password + label: Authentication Password + description: Authentication Credentials + schema: + type: string + show_if: [["username", "!=", ""]] + default: "" + required: true + - variable: tailscale + label: Tailscale Settings + schema: + additional_attrs: true + type: dict + show_if: [["type", "=", "tailscale"]] + attrs: + - variable: authkey + label: Authentication Key + description: Provide an auth key to automatically authenticate the node as your user account. + schema: + type: string + private: true + default: "" + - variable: auth_once + label: Auth Once + description: Only attempt to log in if not already logged in. + schema: + type: boolean + default: true + - variable: accept_dns + label: Accept DNS + description: Accept DNS configuration from the admin console. + schema: + type: boolean + default: false + - variable: userspace + label: Userspace + description: Userspace Networking mode allows running Tailscale where you do not have access to create a VPN tunnel device. + schema: + type: boolean + default: false + - variable: routes + label: Routes + description: Expose physical subnet routes to your entire Tailscale network. + schema: + type: string + default: "" + - variable: dest_ip + label: Destination IP + description: Tells the DNAT mechanism which Destination IP to set in the IP header, and where to send packets that are matched. + schema: + type: string + default: "" + - variable: sock5_server + label: Sock5 Server + description: The address on which to listen for SOCKS5 proxying into the tailscale net. + schema: + type: string + default: "" + - variable: outbound_http_proxy_listen + label: Outbound HTTP Proxy Listen + description: The address on which to listen for HTTP proxying into the tailscale net. + schema: + type: string + default: "" + - variable: extra_args + label: Extra Args + description: Extra Args + schema: + type: string + default: "" + - variable: daemon_extra_args + label: Tailscale Daemon Extra Args + description: Tailscale Daemon Extra Args + schema: + type: string + default: "" + - variable: killSwitch + label: Enable Killswitch + schema: + type: boolean + show_if: [["type", "!=", "disabled"]] + default: true + - variable: excludedNetworks_IPv4 + label: Killswitch Excluded IPv4 networks + description: List of Killswitch Excluded IPv4 Addresses + schema: + type: list + show_if: [["type", "!=", "disabled"]] + default: [] + items: + - variable: networkv4 + label: IPv4 Network + schema: + type: string + required: true + - variable: excludedNetworks_IPv6 + label: Killswitch Excluded IPv6 networks + description: "List of Killswitch Excluded IPv6 Addresses" + schema: + type: list + show_if: [["type", "!=", "disabled"]] + default: [] + items: + - variable: networkv6 + label: IPv6 Network + schema: + type: string + required: true + - variable: configFile + label: VPN Config File Location + schema: + type: string + show_if: [["type", "!=", "disabled"]] + default: "" + + - variable: envList + label: VPN Environment Variables + schema: + type: list + show_if: [["type", "!=", "disabled"]] + default: [] + items: + - variable: envItem + label: Environment Variable + schema: + additional_attrs: true + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + - variable: value + label: Value + schema: + type: string + required: true + max_length: 10240 + + - variable: docs + group: Documentation + label: Please read the documentation at https://truecharts.org + description: Please read the documentation at +
https://truecharts.org + schema: + additional_attrs: true + type: dict + attrs: + - variable: confirmDocs + label: I have checked the documentation + schema: + type: boolean + default: true + - variable: donateNag + group: Documentation + label: Please consider supporting TrueCharts, see https://truecharts.org/sponsor + description: Please consider supporting TrueCharts, see +
https://truecharts.org/sponsor + schema: + additional_attrs: true + type: dict + attrs: + - variable: confirmDonate + label: I have considered donating + schema: + type: boolean + default: true + hidden: true + diff --git a/stable/ghostfolio/4.22.8/templates/NOTES.txt b/incubator/TeslaMate/0.0.2/templates/NOTES.txt similarity index 100% rename from stable/ghostfolio/4.22.8/templates/NOTES.txt rename to incubator/TeslaMate/0.0.2/templates/NOTES.txt diff --git a/incubator/TeslaMate/0.0.2/templates/_configmap.tpl b/incubator/TeslaMate/0.0.2/templates/_configmap.tpl new file mode 100644 index 00000000000..70d78d4d3fb --- /dev/null +++ b/incubator/TeslaMate/0.0.2/templates/_configmap.tpl @@ -0,0 +1,29 @@ +{{/* Define the configmap */}} +{{- define "teslamate.configmaps" -}} +{{- $rootDir := "dashboards/" -}} +{{- $dirs := dict -}} +{{- range $path, $_ := .Files.Glob (printf "%s**/*.json" $rootDir) }} + {{- $pathElements := splitList "/" $path -}} + {{- $dirName := index $pathElements 1 }} + {{- $existingFiles := get $dirs $dirName | default list -}} + {{- $updatedFiles := append $existingFiles $path -}} + {{- $_ := set $dirs $dirName $updatedFiles }} +{{- end }} + +{{- range $dir, $files := $dirs }} +{{- range $files }} +{{- $fileName := lower (base .) }} +{{- $fileNameWithoutExt := trimSuffix ".json" $fileName }} +{{- $configMapKey := printf "%s-%s-%s" "dashboard" $dir $fileNameWithoutExt }} +{{ $configMapKey | quote }}: + enabled: true + annotations: + k8s-sidecar-target-directory: "TeslaMate" + labels: + grafana_dashboard: "1" + data: + {{ $fileName | quote }}: | +{{ $.Files.Get . | indent 6 }} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/incubator/TeslaMate/0.0.2/templates/_secrets.tpl b/incubator/TeslaMate/0.0.2/templates/_secrets.tpl new file mode 100644 index 00000000000..5f1092a2032 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/templates/_secrets.tpl @@ -0,0 +1,13 @@ +{{/* Define the secrets */}} +{{- define "teslamate.secrets" -}} +{{- $secretName := (printf "%s-teslamate-secrets" (include "tc.v1.common.lib.chart.names.fullname" $)) }} + +{{- $encryptionKey := randAlphaNum 64 -}} + + {{- with lookup "v1" "Secret" .Release.Namespace $secretName -}} + {{- $encryptionKey = index .data "TESLAMATE_ENCRYPTION_KEY" | b64dec -}} + {{- end }} +enabled: true +data: + TESLAMATE_ENCRYPTION_KEY: {{ $encryptionKey }} +{{- end -}} diff --git a/incubator/TeslaMate/0.0.2/templates/common.yaml b/incubator/TeslaMate/0.0.2/templates/common.yaml new file mode 100644 index 00000000000..cf915e29079 --- /dev/null +++ b/incubator/TeslaMate/0.0.2/templates/common.yaml @@ -0,0 +1,17 @@ +{{/* Make sure all variables are set properly */}} +{{- include "tc.v1.common.loader.init" . -}} + +{{/* Render secrets for teslamate */}} +{{- $secrets := include "teslamate.secrets" . | fromYaml -}} +{{- if $secrets -}} + {{- $_ := set .Values.secret "teslamate-secrets" $secrets -}} +{{- end -}} + +{{/* Render configmaps for dashboards */}} +{{- $configmaps := include "teslamate.configmaps" . | fromYaml -}} +{{- if $configmaps -}} + {{- $_ := mustMergeOverwrite .Values.configmap $configmaps -}} +{{- end -}} + +{{/* Render the templates */}} +{{- include "tc.v1.common.loader.apply" . -}} diff --git a/stable/ghostfolio/4.22.8/values.yaml b/incubator/TeslaMate/0.0.2/values.yaml similarity index 100% rename from stable/ghostfolio/4.22.8/values.yaml rename to incubator/TeslaMate/0.0.2/values.yaml diff --git a/stable/ghostfolio/4.22.8/CHANGELOG.md b/stable/ghostfolio/4.22.8/CHANGELOG.md deleted file mode 100644 index 70e853f51b1..00000000000 --- a/stable/ghostfolio/4.22.8/CHANGELOG.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Changelog ---- - - -*for the complete changelog, please refer to the website* - -**Important:** - - -## [ghostfolio-4.22.8](https://github.com/truecharts/charts/compare/ghostfolio-4.9.0...ghostfolio-4.22.8) (2024-04-11) - -### Chore - - - -- update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) - -- update container image redis to v13.3.5[@7f45c09](https://github.com/7f45c09) by renovate ([#20555](https://github.com/truecharts/charts/issues/20555)) - -- update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) - -- update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) - -- update container image redis to v13.3.4[@1cc03a1](https://github.com/1cc03a1) by renovate ([#20497](https://github.com/truecharts/charts/issues/20497)) - -- update container image redis to v13.3.2[@ce33ab3](https://github.com/ce33ab3) by renovate ([#20486](https://github.com/truecharts/charts/issues/20486)) - -- update container image common to v20.3.3[@3876ba5](https://github.com/3876ba5) by renovate ([#20478](https://github.com/truecharts/charts/issues/20478)) - -- update container image redis to v13.3.1[@9b53552](https://github.com/9b53552) by renovate ([#20455](https://github.com/truecharts/charts/issues/20455)) - -- update container image redis to v13.3.0[@66b03ae](https://github.com/66b03ae) by renovate ([#20417](https://github.com/truecharts/charts/issues/20417)) - -- update container image common to v20.3.2[@0722ebb](https://github.com/0722ebb) by renovate ([#20334](https://github.com/truecharts/charts/issues/20334)) - -- update container image ghostfolio/ghostfolio to v2.71.0[@9963077](https://github.com/9963077) by renovate ([#20367](https://github.com/truecharts/charts/issues/20367)) - -- update container image ghostfolio/ghostfolio to v2.70.0[@e0b44a7](https://github.com/e0b44a7) by renovate ([#20169](https://github.com/truecharts/charts/issues/20169)) - -- update container image ghostfolio/ghostfolio to v2.69.0[@2d86c20](https://github.com/2d86c20) by renovate ([#20014](https://github.com/truecharts/charts/issues/20014)) - -- update container image common to v20.2.10[@6f99c97](https://github.com/6f99c97) by renovate ([#19876](https://github.com/truecharts/charts/issues/19876)) - -- update container image ghostfolio/ghostfolio to v2.68.0[@e66080f](https://github.com/e66080f) by renovate ([#19965](https://github.com/truecharts/charts/issues/19965)) - -- update container image common to v20.2.9[@10fd6c5](https://github.com/10fd6c5) by renovate ([#19817](https://github.com/truecharts/charts/issues/19817)) - -- update container image ghostfolio/ghostfolio to v2.67.0[@5d1c30c](https://github.com/5d1c30c) by renovate ([#19841](https://github.com/truecharts/charts/issues/19841)) - -- update container image common to v20.2.4[@f245f5c](https://github.com/f245f5c) by renovate ([#19731](https://github.com/truecharts/charts/issues/19731)) - -- update container image ghostfolio/ghostfolio to v2.66.3[@cbd0cfa](https://github.com/cbd0cfa) by renovate ([#19710](https://github.com/truecharts/charts/issues/19710)) - -- update container image common to v20.2.3[@06e462e](https://github.com/06e462e) by renovate ([#19673](https://github.com/truecharts/charts/issues/19673)) - -- update container image redis to v13.2.2[@0ea5f1a](https://github.com/0ea5f1a) by renovate ([#19365](https://github.com/truecharts/charts/issues/19365)) - -- update container image ghostfolio/ghostfolio to v2.65.0[@954e9dc](https://github.com/954e9dc) by renovate ([#19527](https://github.com/truecharts/charts/issues/19527)) - -- update container image common to v20.2.2[@f7d0b92](https://github.com/f7d0b92) by renovate ([#19432](https://github.com/truecharts/charts/issues/19432)) - -- update container image ghostfolio/ghostfolio to v2.64.0[@ceac470](https://github.com/ceac470) by renovate ([#19392](https://github.com/truecharts/charts/issues/19392)) - -- update container image common to v20.2.0[@91ade87](https://github.com/91ade87) by renovate ([#19361](https://github.com/truecharts/charts/issues/19361)) - -- update container image redis to v13.0.5[@01c1933](https://github.com/01c1933) by renovate ([#19324](https://github.com/truecharts/charts/issues/19324)) - -- update container image ghostfolio/ghostfolio to v2.63.2[@399532b](https://github.com/399532b) by renovate ([#19343](https://github.com/truecharts/charts/issues/19343)) - - -## [ghostfolio-4.22.8](https://github.com/truecharts/charts/compare/ghostfolio-4.9.0...ghostfolio-4.22.8) (2024-04-11) - -### Chore - - - -- update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) - -- update container image redis to v13.3.5[@7f45c09](https://github.com/7f45c09) by renovate ([#20555](https://github.com/truecharts/charts/issues/20555)) - -- update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) - -- update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) - -- update container image redis to v13.3.4[@1cc03a1](https://github.com/1cc03a1) by renovate ([#20497](https://github.com/truecharts/charts/issues/20497)) - -- update container image redis to v13.3.2[@ce33ab3](https://github.com/ce33ab3) by renovate ([#20486](https://github.com/truecharts/charts/issues/20486)) - -- update container image common to v20.3.3[@3876ba5](https://github.com/3876ba5) by renovate ([#20478](https://github.com/truecharts/charts/issues/20478)) - -- update container image redis to v13.3.1[@9b53552](https://github.com/9b53552) by renovate ([#20455](https://github.com/truecharts/charts/issues/20455)) - -- update container image redis to v13.3.0[@66b03ae](https://github.com/66b03ae) by renovate ([#20417](https://github.com/truecharts/charts/issues/20417)) - -- update container image common to v20.3.2[@0722ebb](https://github.com/0722ebb) by renovate ([#20334](https://github.com/truecharts/charts/issues/20334)) - -- update container image ghostfolio/ghostfolio to v2.71.0[@9963077](https://github.com/9963077) by renovate ([#20367](https://github.com/truecharts/charts/issues/20367)) - -- update container image ghostfolio/ghostfolio to v2.70.0[@e0b44a7](https://github.com/e0b44a7) by renovate ([#20169](https://github.com/truecharts/charts/issues/20169)) \ No newline at end of file diff --git a/stable/ghostfolio/4.22.8/charts/redis-13.3.5.tgz b/stable/ghostfolio/4.22.8/charts/redis-13.3.5.tgz deleted file mode 100644 index 84ab6e0a86c4068cd97860ac0e0589db38f3fd20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107461 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 L<+{6506Yx=1.24.0-0" +kubeVersion: '>=1.24.0-0' maintainers: - name: TrueCharts email: info@truecharts.org @@ -42,4 +42,4 @@ sources: - https://github.com/truecharts/charts/tree/master/charts/stable/ghostfolio - https://hub.docker.com/r/ghostfolio/ghostfolio type: application -version: 4.22.8 +version: 4.23.0 diff --git a/stable/ghostfolio/4.22.8/README.md b/stable/ghostfolio/4.23.0/README.md similarity index 100% rename from stable/ghostfolio/4.22.8/README.md rename to stable/ghostfolio/4.23.0/README.md diff --git a/stable/ghostfolio/4.22.8/app-changelog.md b/stable/ghostfolio/4.23.0/app-changelog.md similarity index 89% rename from stable/ghostfolio/4.22.8/app-changelog.md rename to stable/ghostfolio/4.23.0/app-changelog.md index 12882d92d5f..e69b4f38074 100644 --- a/stable/ghostfolio/4.22.8/app-changelog.md +++ b/stable/ghostfolio/4.23.0/app-changelog.md @@ -1,11 +1,15 @@ -## [ghostfolio-4.22.8](https://github.com/truecharts/charts/compare/ghostfolio-4.9.0...ghostfolio-4.22.8) (2024-04-11) +## [ghostfolio-4.23.0](https://github.com/truecharts/charts/compare/ghostfolio-4.9.0...ghostfolio-4.23.0) (2024-04-13) ### Chore +- update container image ghostfolio/ghostfolio to v2.72.0[@312f17b](https://github.com/312f17b) by renovate ([#20712](https://github.com/truecharts/charts/issues/20712)) + +- update container image redis to v13.3.7[@8c9b71c](https://github.com/8c9b71c) by renovate ([#20566](https://github.com/truecharts/charts/issues/20566)) + - update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) - update container image redis to v13.3.5[@7f45c09](https://github.com/7f45c09) by renovate ([#20555](https://github.com/truecharts/charts/issues/20555)) diff --git a/stable/ghostfolio/4.22.8/app-readme.md b/stable/ghostfolio/4.23.0/app-readme.md similarity index 100% rename from stable/ghostfolio/4.22.8/app-readme.md rename to stable/ghostfolio/4.23.0/app-readme.md diff --git a/stable/jackett/20.1.5/charts/common-20.3.6.tgz b/stable/ghostfolio/4.23.0/charts/common-20.3.6.tgz similarity index 100% rename from stable/jackett/20.1.5/charts/common-20.3.6.tgz rename to stable/ghostfolio/4.23.0/charts/common-20.3.6.tgz diff --git a/stable/libremdb/7.10.18/charts/redis-13.3.7.tgz b/stable/ghostfolio/4.23.0/charts/redis-13.3.7.tgz similarity index 100% rename from stable/libremdb/7.10.18/charts/redis-13.3.7.tgz rename to stable/ghostfolio/4.23.0/charts/redis-13.3.7.tgz diff --git a/stable/ghostfolio/4.22.8/ix_values.yaml b/stable/ghostfolio/4.23.0/ix_values.yaml similarity index 94% rename from stable/ghostfolio/4.22.8/ix_values.yaml rename to stable/ghostfolio/4.23.0/ix_values.yaml index 60cb2534abc..4d63275ed3e 100644 --- a/stable/ghostfolio/4.22.8/ix_values.yaml +++ b/stable/ghostfolio/4.23.0/ix_values.yaml @@ -1,7 +1,7 @@ image: repository: ghostfolio/ghostfolio pullPolicy: IfNotPresent - tag: 2.71.0@sha256:9963077b24167af3c74b81e0433d30e8bc1b8ebc83d76274ea9f189800394452 + tag: 2.72.0@sha256:312f17b92bf589abc20f351f28ac397dc441e96fbdf8643a5ac4c518b22f6861 securityContext: container: runAsNonRoot: false diff --git a/stable/ghostfolio/4.22.8/questions.yaml b/stable/ghostfolio/4.23.0/questions.yaml similarity index 100% rename from stable/ghostfolio/4.22.8/questions.yaml rename to stable/ghostfolio/4.23.0/questions.yaml diff --git a/stable/jackett/20.1.5/templates/NOTES.txt b/stable/ghostfolio/4.23.0/templates/NOTES.txt similarity index 100% rename from stable/jackett/20.1.5/templates/NOTES.txt rename to stable/ghostfolio/4.23.0/templates/NOTES.txt diff --git a/stable/ghostfolio/4.22.8/templates/_secrets.tpl b/stable/ghostfolio/4.23.0/templates/_secrets.tpl similarity index 100% rename from stable/ghostfolio/4.22.8/templates/_secrets.tpl rename to stable/ghostfolio/4.23.0/templates/_secrets.tpl diff --git a/stable/ghostfolio/4.22.8/templates/common.yaml b/stable/ghostfolio/4.23.0/templates/common.yaml similarity index 100% rename from stable/ghostfolio/4.22.8/templates/common.yaml rename to stable/ghostfolio/4.23.0/templates/common.yaml diff --git a/stable/jackett/20.1.5/values.yaml b/stable/ghostfolio/4.23.0/values.yaml similarity index 100% rename from stable/jackett/20.1.5/values.yaml rename to stable/ghostfolio/4.23.0/values.yaml diff --git a/stable/jackett/20.1.5/CHANGELOG.md b/stable/jackett/20.1.5/CHANGELOG.md deleted file mode 100644 index ce210064bf2..00000000000 --- a/stable/jackett/20.1.5/CHANGELOG.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Changelog ---- - - -*for the complete changelog, please refer to the website* - -**Important:** - - -## [jackett-20.1.5](https://github.com/truecharts/charts/compare/jackett-19.6.0...jackett-20.1.5) (2024-04-12) - -### Chore - - - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2258[@ebe5eb4](https://github.com/ebe5eb4) by renovate ([#20137](https://github.com/truecharts/charts/issues/20137)) - -- update container image common to v20.2.0[@91ade87](https://github.com/91ade87) by renovate ([#19361](https://github.com/truecharts/charts/issues/19361)) - -- update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2335[@4cd6407](https://github.com/4cd6407) by renovate ([#20529](https://github.com/truecharts/charts/issues/20529)) - -- update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) - -- update container image common to v20.3.3[@3876ba5](https://github.com/3876ba5) by renovate ([#20478](https://github.com/truecharts/charts/issues/20478)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2329[@848d1a1](https://github.com/848d1a1) by renovate ([#20481](https://github.com/truecharts/charts/issues/20481)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2324[@884c5f3](https://github.com/884c5f3) by renovate ([#20409](https://github.com/truecharts/charts/issues/20409)) - -- update container image common to v20.3.2[@0722ebb](https://github.com/0722ebb) by renovate ([#20334](https://github.com/truecharts/charts/issues/20334)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2313[@8db0eca](https://github.com/8db0eca) by renovate ([#20363](https://github.com/truecharts/charts/issues/20363)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2296[@842fe88](https://github.com/842fe88) by renovate ([#20322](https://github.com/truecharts/charts/issues/20322)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2284[@e7a63ab](https://github.com/e7a63ab) by renovate ([#20270](https://github.com/truecharts/charts/issues/20270)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2278[@f8f2136](https://github.com/f8f2136) by renovate ([#20234](https://github.com/truecharts/charts/issues/20234)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2265[@0c84a50](https://github.com/0c84a50) by renovate ([#20182](https://github.com/truecharts/charts/issues/20182)) - -- update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2232[@ff9df95](https://github.com/ff9df95) by renovate ([#20040](https://github.com/truecharts/charts/issues/20040)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2342[@3c88e8a](https://github.com/3c88e8a) by renovate ([#20601](https://github.com/truecharts/charts/issues/20601)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2219[@b48a759](https://github.com/b48a759) by renovate ([#19995](https://github.com/truecharts/charts/issues/19995)) - -- update container image common to v20.2.10[@6f99c97](https://github.com/6f99c97) by renovate ([#19876](https://github.com/truecharts/charts/issues/19876)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2212[@c15ce92](https://github.com/c15ce92) by renovate ([#19955](https://github.com/truecharts/charts/issues/19955)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2199[@0ebd2bb](https://github.com/0ebd2bb) by renovate ([#19913](https://github.com/truecharts/charts/issues/19913)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2175[@ee69ddf](https://github.com/ee69ddf) by renovate ([#19867](https://github.com/truecharts/charts/issues/19867)) - -- update container image common to v20.2.9[@10fd6c5](https://github.com/10fd6c5) by renovate ([#19817](https://github.com/truecharts/charts/issues/19817)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2163[@e48ff47](https://github.com/e48ff47) by renovate ([#19819](https://github.com/truecharts/charts/issues/19819)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2146[@4c96e8b](https://github.com/4c96e8b) by renovate ([#19771](https://github.com/truecharts/charts/issues/19771)) - -- update container image common to v20.2.4[@f245f5c](https://github.com/f245f5c) by renovate ([#19731](https://github.com/truecharts/charts/issues/19731)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2143[@ca0f107](https://github.com/ca0f107) by renovate ([#19732](https://github.com/truecharts/charts/issues/19732)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2253[@a6b0a31](https://github.com/a6b0a31) by renovate ([#20092](https://github.com/truecharts/charts/issues/20092)) - -- update container image common to v20.2.3[@06e462e](https://github.com/06e462e) by renovate ([#19673](https://github.com/truecharts/charts/issues/19673)) - -- update container image common to v20.2.2[@f7d0b92](https://github.com/f7d0b92) by renovate ([#19432](https://github.com/truecharts/charts/issues/19432)) - -- *BREAKING CHANGES* switch image to geek-cookbook ([#19700](https://github.com/truecharts/charts/issues/19700)) - -### Fix - - - -- Update severely outdated container again ([#19677](https://github.com/truecharts/charts/issues/19677)) - - -## [jackett-20.1.5](https://github.com/truecharts/charts/compare/jackett-19.6.0...jackett-20.1.5) (2024-04-12) - -### Chore - - - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2258[@ebe5eb4](https://github.com/ebe5eb4) by renovate ([#20137](https://github.com/truecharts/charts/issues/20137)) - -- update container image common to v20.2.0[@91ade87](https://github.com/91ade87) by renovate ([#19361](https://github.com/truecharts/charts/issues/19361)) - -- update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2335[@4cd6407](https://github.com/4cd6407) by renovate ([#20529](https://github.com/truecharts/charts/issues/20529)) - -- update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) \ No newline at end of file diff --git a/stable/libremdb/7.10.18/.helmignore b/stable/jackett/20.1.7/.helmignore similarity index 100% rename from stable/libremdb/7.10.18/.helmignore rename to stable/jackett/20.1.7/.helmignore diff --git a/stable/jackett/20.1.7/CHANGELOG.md b/stable/jackett/20.1.7/CHANGELOG.md new file mode 100644 index 00000000000..941abb8a218 --- /dev/null +++ b/stable/jackett/20.1.7/CHANGELOG.md @@ -0,0 +1,3 @@ +*for the complete changelog, please refer to the website* + +**Important:** \ No newline at end of file diff --git a/stable/jackett/20.1.5/Chart.yaml b/stable/jackett/20.1.7/Chart.yaml similarity index 94% rename from stable/jackett/20.1.5/Chart.yaml rename to stable/jackett/20.1.7/Chart.yaml index 5f358970efa..86a73fb4c5d 100644 --- a/stable/jackett/20.1.5/Chart.yaml +++ b/stable/jackett/20.1.7/Chart.yaml @@ -7,7 +7,7 @@ annotations: truecharts.org/min_helm_version: "3.11" truecharts.org/train: stable apiVersion: v2 -appVersion: 0.21.2342 +appVersion: 0.21.2358 dependencies: - name: common version: 20.3.6 @@ -24,7 +24,7 @@ keywords: - jackett - torrent - usenet -kubeVersion: ">=1.24.0-0" +kubeVersion: '>=1.24.0-0' maintainers: - name: TrueCharts email: info@truecharts.org @@ -36,4 +36,4 @@ sources: - https://github.com/truecharts/charts/tree/master/charts/stable/jackett - https://ghcr.io/geek-cookbook/jackett type: application -version: 20.1.5 +version: 20.1.7 diff --git a/stable/jackett/20.1.5/README.md b/stable/jackett/20.1.7/README.md similarity index 100% rename from stable/jackett/20.1.5/README.md rename to stable/jackett/20.1.7/README.md diff --git a/stable/jackett/20.1.5/app-changelog.md b/stable/jackett/20.1.7/app-changelog.md similarity index 91% rename from stable/jackett/20.1.5/app-changelog.md rename to stable/jackett/20.1.7/app-changelog.md index b256b6f94a6..01d2dc96119 100644 --- a/stable/jackett/20.1.5/app-changelog.md +++ b/stable/jackett/20.1.7/app-changelog.md @@ -1,6 +1,6 @@ -## [jackett-20.1.5](https://github.com/truecharts/charts/compare/jackett-19.6.0...jackett-20.1.5) (2024-04-12) +## [jackett-20.1.7](https://github.com/truecharts/charts/compare/jackett-19.6.0...jackett-20.1.7) (2024-04-13) ### Chore @@ -8,15 +8,19 @@ - update container image ghcr.io/geek-cookbook/jackett to v0.21.2258[@ebe5eb4](https://github.com/ebe5eb4) by renovate ([#20137](https://github.com/truecharts/charts/issues/20137)) -- update container image common to v20.2.0[@91ade87](https://github.com/91ade87) by renovate ([#19361](https://github.com/truecharts/charts/issues/19361)) +- update container image common to v20.3.3[@3876ba5](https://github.com/3876ba5) by renovate ([#20478](https://github.com/truecharts/charts/issues/20478)) - update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) +- update container image ghcr.io/geek-cookbook/jackett to v0.21.2358[@920256f](https://github.com/920256f) by renovate ([#20710](https://github.com/truecharts/charts/issues/20710)) + +- update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) + - update container image ghcr.io/geek-cookbook/jackett to v0.21.2335[@4cd6407](https://github.com/4cd6407) by renovate ([#20529](https://github.com/truecharts/charts/issues/20529)) - update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) -- update container image common to v20.3.3[@3876ba5](https://github.com/3876ba5) by renovate ([#20478](https://github.com/truecharts/charts/issues/20478)) +- update container image ghcr.io/geek-cookbook/jackett to v0.21.2253[@a6b0a31](https://github.com/a6b0a31) by renovate ([#20092](https://github.com/truecharts/charts/issues/20092)) - update container image ghcr.io/geek-cookbook/jackett to v0.21.2329[@848d1a1](https://github.com/848d1a1) by renovate ([#20481](https://github.com/truecharts/charts/issues/20481)) @@ -28,18 +32,18 @@ - update container image ghcr.io/geek-cookbook/jackett to v0.21.2296[@842fe88](https://github.com/842fe88) by renovate ([#20322](https://github.com/truecharts/charts/issues/20322)) -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2284[@e7a63ab](https://github.com/e7a63ab) by renovate ([#20270](https://github.com/truecharts/charts/issues/20270)) +- update container image ghcr.io/geek-cookbook/jackett to v0.21.2232[@ff9df95](https://github.com/ff9df95) by renovate ([#20040](https://github.com/truecharts/charts/issues/20040)) - update container image ghcr.io/geek-cookbook/jackett to v0.21.2278[@f8f2136](https://github.com/f8f2136) by renovate ([#20234](https://github.com/truecharts/charts/issues/20234)) - update container image ghcr.io/geek-cookbook/jackett to v0.21.2265[@0c84a50](https://github.com/0c84a50) by renovate ([#20182](https://github.com/truecharts/charts/issues/20182)) -- update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) - -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2232[@ff9df95](https://github.com/ff9df95) by renovate ([#20040](https://github.com/truecharts/charts/issues/20040)) - - update container image ghcr.io/geek-cookbook/jackett to v0.21.2342[@3c88e8a](https://github.com/3c88e8a) by renovate ([#20601](https://github.com/truecharts/charts/issues/20601)) +- update container image ghcr.io/geek-cookbook/jackett to v0.21.2354[@e76607e](https://github.com/e76607e) by renovate ([#20660](https://github.com/truecharts/charts/issues/20660)) + +- update container image ghcr.io/geek-cookbook/jackett to v0.21.2284[@e7a63ab](https://github.com/e7a63ab) by renovate ([#20270](https://github.com/truecharts/charts/issues/20270)) + - update container image ghcr.io/geek-cookbook/jackett to v0.21.2219[@b48a759](https://github.com/b48a759) by renovate ([#19995](https://github.com/truecharts/charts/issues/19995)) - update container image common to v20.2.10[@6f99c97](https://github.com/6f99c97) by renovate ([#19876](https://github.com/truecharts/charts/issues/19876)) @@ -60,7 +64,7 @@ - update container image ghcr.io/geek-cookbook/jackett to v0.21.2143[@ca0f107](https://github.com/ca0f107) by renovate ([#19732](https://github.com/truecharts/charts/issues/19732)) -- update container image ghcr.io/geek-cookbook/jackett to v0.21.2253[@a6b0a31](https://github.com/a6b0a31) by renovate ([#20092](https://github.com/truecharts/charts/issues/20092)) +- update container image common to v20.2.0[@91ade87](https://github.com/91ade87) by renovate ([#19361](https://github.com/truecharts/charts/issues/19361)) - update container image common to v20.2.3[@06e462e](https://github.com/06e462e) by renovate ([#19673](https://github.com/truecharts/charts/issues/19673)) diff --git a/stable/jackett/20.1.5/app-readme.md b/stable/jackett/20.1.7/app-readme.md similarity index 100% rename from stable/jackett/20.1.5/app-readme.md rename to stable/jackett/20.1.7/app-readme.md diff --git a/stable/libremdb/7.10.18/charts/common-20.3.6.tgz b/stable/jackett/20.1.7/charts/common-20.3.6.tgz similarity index 100% rename from stable/libremdb/7.10.18/charts/common-20.3.6.tgz rename to stable/jackett/20.1.7/charts/common-20.3.6.tgz diff --git a/stable/jackett/20.1.5/ix_values.yaml b/stable/jackett/20.1.7/ix_values.yaml similarity index 85% rename from stable/jackett/20.1.5/ix_values.yaml rename to stable/jackett/20.1.7/ix_values.yaml index 4198450e6d5..33c7ac3902b 100644 --- a/stable/jackett/20.1.5/ix_values.yaml +++ b/stable/jackett/20.1.7/ix_values.yaml @@ -1,7 +1,7 @@ image: repository: ghcr.io/geek-cookbook/jackett pullPolicy: IfNotPresent - tag: 0.21.2342@sha256:3c88e8afaf0c538946975a249ea1affd21b528c110d42673782989cb458f92e3 + tag: 0.21.2358@sha256:920256fcc6cabd5989980487ef183bb911a971fbe194c528e7bfea4e2d570dde service: main: ports: diff --git a/stable/jackett/20.1.5/questions.yaml b/stable/jackett/20.1.7/questions.yaml similarity index 100% rename from stable/jackett/20.1.5/questions.yaml rename to stable/jackett/20.1.7/questions.yaml diff --git a/stable/libremdb/7.10.18/templates/NOTES.txt b/stable/jackett/20.1.7/templates/NOTES.txt similarity index 100% rename from stable/libremdb/7.10.18/templates/NOTES.txt rename to stable/jackett/20.1.7/templates/NOTES.txt diff --git a/stable/jackett/20.1.5/templates/common.yaml b/stable/jackett/20.1.7/templates/common.yaml similarity index 100% rename from stable/jackett/20.1.5/templates/common.yaml rename to stable/jackett/20.1.7/templates/common.yaml diff --git a/stable/libremdb/7.10.18/values.yaml b/stable/jackett/20.1.7/values.yaml similarity index 100% rename from stable/libremdb/7.10.18/values.yaml rename to stable/jackett/20.1.7/values.yaml diff --git a/stable/libremdb/7.10.18/CHANGELOG.md b/stable/libremdb/7.10.18/CHANGELOG.md deleted file mode 100644 index d2ec2d557f0..00000000000 --- a/stable/libremdb/7.10.18/CHANGELOG.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: Changelog ---- - - -*for the complete changelog, please refer to the website* - -**Important:** - - -## [libremdb-7.10.18](https://github.com/truecharts/charts/compare/libremdb-7.6.0...libremdb-7.10.18) (2024-04-13) - -### Chore - - - -- update container image quay.io/pussthecatorg/libremdb to latest[@83ec0eb](https://github.com/83ec0eb) by renovate ([#20686](https://github.com/truecharts/charts/issues/20686)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@825eef0](https://github.com/825eef0) by renovate ([#20665](https://github.com/truecharts/charts/issues/20665)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@3675258](https://github.com/3675258) by renovate ([#20655](https://github.com/truecharts/charts/issues/20655)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@f554c6f](https://github.com/f554c6f) by renovate ([#20637](https://github.com/truecharts/charts/issues/20637)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@85e4564](https://github.com/85e4564) by renovate ([#20628](https://github.com/truecharts/charts/issues/20628)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@99c4290](https://github.com/99c4290) by renovate ([#20616](https://github.com/truecharts/charts/issues/20616)) - -- update container image redis to v13.3.7[@8c9b71c](https://github.com/8c9b71c) by renovate ([#20566](https://github.com/truecharts/charts/issues/20566)) - -- update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@5743d13](https://github.com/5743d13) by renovate ([#20598](https://github.com/truecharts/charts/issues/20598)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@18dce18](https://github.com/18dce18) by renovate ([#20585](https://github.com/truecharts/charts/issues/20585)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@1684095](https://github.com/1684095) by renovate ([#20534](https://github.com/truecharts/charts/issues/20534)) - -- update container image redis to v13.3.5[@7f45c09](https://github.com/7f45c09) by renovate ([#20555](https://github.com/truecharts/charts/issues/20555)) - -- update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) - -- update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@db85ef2](https://github.com/db85ef2) by renovate ([#20525](https://github.com/truecharts/charts/issues/20525)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@28c9ae7](https://github.com/28c9ae7) by renovate ([#20510](https://github.com/truecharts/charts/issues/20510)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@3abae39](https://github.com/3abae39) by renovate ([#20472](https://github.com/truecharts/charts/issues/20472)) - -- update container image redis to v13.3.4[@1cc03a1](https://github.com/1cc03a1) by renovate ([#20497](https://github.com/truecharts/charts/issues/20497)) - -- update container image redis to v13.3.2[@ce33ab3](https://github.com/ce33ab3) by renovate ([#20486](https://github.com/truecharts/charts/issues/20486)) - -- update container image common to v20.3.3[@3876ba5](https://github.com/3876ba5) by renovate ([#20478](https://github.com/truecharts/charts/issues/20478)) - -- update container image redis to v13.3.1[@9b53552](https://github.com/9b53552) by renovate ([#20455](https://github.com/truecharts/charts/issues/20455)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@3b7b6fe](https://github.com/3b7b6fe) by renovate ([#20450](https://github.com/truecharts/charts/issues/20450)) - -- update container image redis to v13.3.0[@66b03ae](https://github.com/66b03ae) by renovate ([#20417](https://github.com/truecharts/charts/issues/20417)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@07c4c1e](https://github.com/07c4c1e) by renovate ([#20436](https://github.com/truecharts/charts/issues/20436)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@76e1ab6](https://github.com/76e1ab6) by renovate ([#20407](https://github.com/truecharts/charts/issues/20407)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@18bd4c8](https://github.com/18bd4c8) by renovate ([#20398](https://github.com/truecharts/charts/issues/20398)) - -- update container image common to v20.3.2[@0722ebb](https://github.com/0722ebb) by renovate ([#20334](https://github.com/truecharts/charts/issues/20334)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@02684e0](https://github.com/02684e0) by renovate ([#20388](https://github.com/truecharts/charts/issues/20388)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@6410edb](https://github.com/6410edb) by renovate ([#20376](https://github.com/truecharts/charts/issues/20376)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@0ed386d](https://github.com/0ed386d) by renovate ([#20362](https://github.com/truecharts/charts/issues/20362)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@beef7b7](https://github.com/beef7b7) by renovate ([#20352](https://github.com/truecharts/charts/issues/20352)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@f95b7eb](https://github.com/f95b7eb) by renovate ([#20342](https://github.com/truecharts/charts/issues/20342)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@05bda0f](https://github.com/05bda0f) by renovate ([#20333](https://github.com/truecharts/charts/issues/20333)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@0ccf5bd](https://github.com/0ccf5bd) by renovate ([#20321](https://github.com/truecharts/charts/issues/20321)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@6d901b5](https://github.com/6d901b5) by renovate ([#20310](https://github.com/truecharts/charts/issues/20310)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@0c1786c](https://github.com/0c1786c) by renovate ([#20300](https://github.com/truecharts/charts/issues/20300)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@506e2dd](https://github.com/506e2dd) by renovate ([#20279](https://github.com/truecharts/charts/issues/20279)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@7f360d3](https://github.com/7f360d3) by renovate ([#20269](https://github.com/truecharts/charts/issues/20269)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@9cae5dc](https://github.com/9cae5dc) by renovate ([#20259](https://github.com/truecharts/charts/issues/20259)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@f4da825](https://github.com/f4da825) by renovate ([#20248](https://github.com/truecharts/charts/issues/20248)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@0778301](https://github.com/0778301) by renovate ([#20228](https://github.com/truecharts/charts/issues/20228)) - -- update container image quay.io/pussthecatorg/libremdb to latest[@2ab0aa1](https://github.com/2ab0aa1) by renovate ([#20214](https://github.com/truecharts/charts/issues/20214)) diff --git a/stable/mysql-workbench/9.8.3/.helmignore b/stable/libremdb/7.10.20/.helmignore similarity index 100% rename from stable/mysql-workbench/9.8.3/.helmignore rename to stable/libremdb/7.10.20/.helmignore diff --git a/stable/libremdb/7.10.20/CHANGELOG.md b/stable/libremdb/7.10.20/CHANGELOG.md new file mode 100644 index 00000000000..941abb8a218 --- /dev/null +++ b/stable/libremdb/7.10.20/CHANGELOG.md @@ -0,0 +1,3 @@ +*for the complete changelog, please refer to the website* + +**Important:** \ No newline at end of file diff --git a/stable/libremdb/7.10.18/Chart.yaml b/stable/libremdb/7.10.20/Chart.yaml similarity index 98% rename from stable/libremdb/7.10.18/Chart.yaml rename to stable/libremdb/7.10.20/Chart.yaml index ae92896e67d..c3e4b7cf6f9 100644 --- a/stable/libremdb/7.10.18/Chart.yaml +++ b/stable/libremdb/7.10.20/Chart.yaml @@ -43,4 +43,4 @@ sources: - https://github.com/truecharts/charts/tree/master/charts/stable/libremdb - https://quay.io/pussthecatorg/libremdb type: application -version: 7.10.18 +version: 7.10.20 diff --git a/stable/libremdb/7.10.18/README.md b/stable/libremdb/7.10.20/README.md similarity index 100% rename from stable/libremdb/7.10.18/README.md rename to stable/libremdb/7.10.20/README.md diff --git a/stable/libremdb/7.10.18/app-changelog.md b/stable/libremdb/7.10.20/app-changelog.md similarity index 97% rename from stable/libremdb/7.10.18/app-changelog.md rename to stable/libremdb/7.10.20/app-changelog.md index 4f19f487498..dc1d918be7d 100644 --- a/stable/libremdb/7.10.18/app-changelog.md +++ b/stable/libremdb/7.10.20/app-changelog.md @@ -1,11 +1,15 @@ -## [libremdb-7.10.18](https://github.com/truecharts/charts/compare/libremdb-7.6.0...libremdb-7.10.18) (2024-04-13) +## [libremdb-7.10.20](https://github.com/truecharts/charts/compare/libremdb-7.6.0...libremdb-7.10.20) (2024-04-13) ### Chore +- update container image quay.io/pussthecatorg/libremdb to latest[@ce23463](https://github.com/ce23463) by renovate ([#20708](https://github.com/truecharts/charts/issues/20708)) + +- update container image quay.io/pussthecatorg/libremdb to latest[@b522f68](https://github.com/b522f68) by renovate ([#20696](https://github.com/truecharts/charts/issues/20696)) + - update container image quay.io/pussthecatorg/libremdb to latest[@83ec0eb](https://github.com/83ec0eb) by renovate ([#20686](https://github.com/truecharts/charts/issues/20686)) - update container image quay.io/pussthecatorg/libremdb to latest[@825eef0](https://github.com/825eef0) by renovate ([#20665](https://github.com/truecharts/charts/issues/20665)) diff --git a/stable/libremdb/7.10.18/app-readme.md b/stable/libremdb/7.10.20/app-readme.md similarity index 100% rename from stable/libremdb/7.10.18/app-readme.md rename to stable/libremdb/7.10.20/app-readme.md diff --git a/stable/libremdb/7.10.20/charts/common-20.3.6.tgz b/stable/libremdb/7.10.20/charts/common-20.3.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..bc6a9c951d66fa5c2e35a7ec56fc699fe7328e3f GIT binary patch literal 101690 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

XKfL*f#O$HCh&o?F2wS!P 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

Ht3l{P#*<3%mfRpX6>vSM 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

XKfL*f#O$HCh&o?F2wS!P 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

)>8H(u<_yRJVB`9NH&)4U7^ru*fIHH!Qf@c@> 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 yLkT}TGezKNpiJ;-+Dc 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 z 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 diff --git a/stable/mysql-workbench/9.8.5/.helmignore b/stable/mysql-workbench/9.8.5/.helmignore new file mode 100644 index 00000000000..77ca5567b26 --- /dev/null +++ b/stable/mysql-workbench/9.8.5/.helmignore @@ -0,0 +1,30 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# OWNERS file for Kubernetes +OWNERS +# helm-docs templates +*.gotmpl +# docs folder +/docs +# icon +icon.png diff --git a/stable/mysql-workbench/9.8.5/CHANGELOG.md b/stable/mysql-workbench/9.8.5/CHANGELOG.md new file mode 100644 index 00000000000..941abb8a218 --- /dev/null +++ b/stable/mysql-workbench/9.8.5/CHANGELOG.md @@ -0,0 +1,3 @@ +*for the complete changelog, please refer to the website* + +**Important:** \ No newline at end of file diff --git a/stable/mysql-workbench/9.8.3/Chart.yaml b/stable/mysql-workbench/9.8.5/Chart.yaml similarity index 94% rename from stable/mysql-workbench/9.8.3/Chart.yaml rename to stable/mysql-workbench/9.8.5/Chart.yaml index d255456eb90..505ef31ee57 100644 --- a/stable/mysql-workbench/9.8.3/Chart.yaml +++ b/stable/mysql-workbench/9.8.5/Chart.yaml @@ -10,7 +10,7 @@ apiVersion: v2 appVersion: 8.0.36 dependencies: - name: common - version: 20.3.5 + version: 20.3.6 repository: oci://tccr.io/truecharts condition: "" alias: "" @@ -22,7 +22,7 @@ home: https://truecharts.org/charts/stable/mysql-workbench icon: https://truecharts.org/img/hotlink-ok/chart-icons/mysql-workbench.png keywords: - mysql-workbench -kubeVersion: ">=1.24.0-0" +kubeVersion: '>=1.24.0-0' maintainers: - name: TrueCharts email: info@truecharts.org @@ -32,4 +32,4 @@ sources: - https://github.com/truecharts/charts/tree/master/charts/stable/mysql-workbench - https://ghcr.io/linuxserver/mysql-workbench type: application -version: 9.8.3 +version: 9.8.5 diff --git a/stable/mysql-workbench/9.8.3/README.md b/stable/mysql-workbench/9.8.5/README.md similarity index 100% rename from stable/mysql-workbench/9.8.3/README.md rename to stable/mysql-workbench/9.8.5/README.md diff --git a/stable/mysql-workbench/9.8.3/app-changelog.md b/stable/mysql-workbench/9.8.5/app-changelog.md similarity index 81% rename from stable/mysql-workbench/9.8.3/app-changelog.md rename to stable/mysql-workbench/9.8.5/app-changelog.md index d25a8c13cb6..0496d3287f4 100644 --- a/stable/mysql-workbench/9.8.3/app-changelog.md +++ b/stable/mysql-workbench/9.8.5/app-changelog.md @@ -1,11 +1,15 @@ -## [mysql-workbench-9.8.3](https://github.com/truecharts/charts/compare/mysql-workbench-9.6.0...mysql-workbench-9.8.3) (2024-04-10) +## [mysql-workbench-9.8.5](https://github.com/truecharts/charts/compare/mysql-workbench-9.6.0...mysql-workbench-9.8.5) (2024-04-13) ### Chore +- update container image ghcr.io/linuxserver/mysql-workbench to 8.0.36[@43f864a](https://github.com/43f864a) by renovate ([#20707](https://github.com/truecharts/charts/issues/20707)) + +- update container image common to v20.3.6[@27edfed](https://github.com/27edfed) by renovate ([#20599](https://github.com/truecharts/charts/issues/20599)) + - update container image common to v20.3.5[@aedd88a](https://github.com/aedd88a) by renovate ([#20535](https://github.com/truecharts/charts/issues/20535)) - update container image common to v20.3.4[@d7e1b23](https://github.com/d7e1b23) by renovate ([#20527](https://github.com/truecharts/charts/issues/20527)) diff --git a/stable/mysql-workbench/9.8.3/app-readme.md b/stable/mysql-workbench/9.8.5/app-readme.md similarity index 100% rename from stable/mysql-workbench/9.8.3/app-readme.md rename to stable/mysql-workbench/9.8.5/app-readme.md diff --git a/stable/mysql-workbench/9.8.5/charts/common-20.3.6.tgz b/stable/mysql-workbench/9.8.5/charts/common-20.3.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..bc6a9c951d66fa5c2e35a7ec56fc699fe7328e3f GIT binary patch literal 101690 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