Add TeslaMate deployment for Tesla Model Y data logging (#47)
## Summary - Add TeslaMate k8s deployment with Tailscale ingress at tesla.tail8d86e.ts.net - Add teslamate user to CloudNativePG blumeops-pg cluster - Add TeslaMate PostgreSQL datasource to Grafana - Import 18 TeslaMate Grafana dashboards for charging, drives, efficiency, etc. - Add teslamate database to borgmatic backup configuration ## Deployment and Testing - [ ] Create 1Password items: "TeslaMate DB Password" and "TeslaMate Encryption Key" - [ ] Apply database user secret: `op inject -i argocd/manifests/databases/secret-teslamate.yaml.tpl | kubectl apply -f -` - [ ] Sync blumeops-pg: `argocd app sync blumeops-pg` - [ ] Create teslamate database - [ ] Apply teslamate secrets (encryption key, db connection) - [ ] Apply Grafana datasource secret: `op inject -i argocd/manifests/grafana-config/secret-teslamate-datasource.yaml.tpl | kubectl apply -f -` - [ ] Sync apps and teslamate: `argocd app sync apps teslamate grafana grafana-config` - [ ] Complete Tesla API OAuth flow at https://tesla.tail8d86e.ts.net - [ ] Verify data collection starts - [ ] Verify Grafana dashboards show data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.tail8d86e.ts.net/eblume/blumeops/pulls/47
This commit is contained in:
parent
11075d4517
commit
272ddb213b
41 changed files with 22366 additions and 10 deletions
|
|
@ -46,3 +46,7 @@ borgmatic_postgresql_databases:
|
|||
hostname: pg.tail8d86e.ts.net
|
||||
port: 5432
|
||||
username: borgmatic
|
||||
- name: teslamate
|
||||
hostname: pg.tail8d86e.ts.net
|
||||
port: 5432
|
||||
username: borgmatic
|
||||
|
|
|
|||
|
|
@ -17,5 +17,4 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
# To pick up new apps: argocd app sync apps
|
||||
|
|
|
|||
|
|
@ -17,4 +17,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -21,4 +21,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ spec:
|
|||
sources:
|
||||
# Helm chart from forge mirror (SSH via egress)
|
||||
- repoURL: ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/cloudnative-pg-charts.git
|
||||
targetRevision: cloudnative-pg-v0.23.0
|
||||
targetRevision: cloudnative-pg-v0.27.0
|
||||
path: charts/cloudnative-pg
|
||||
helm:
|
||||
releaseName: cloudnative-pg
|
||||
|
|
@ -29,4 +29,3 @@ spec:
|
|||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
- ServerSideApply=true # Required for large CRDs that exceed annotation size limit
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -27,4 +27,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -22,4 +22,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -31,4 +31,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -25,4 +25,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
|
|
@ -23,4 +23,3 @@ spec:
|
|||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
# Manual sync only - no automated sync on git push
|
||||
|
|
|
|||
32
argocd/apps/teslamate.yaml
Normal file
32
argocd/apps/teslamate.yaml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# TeslaMate Tesla Data Logger
|
||||
# Requires: CloudNativePG PostgreSQL cluster and manual secret setup
|
||||
#
|
||||
# Before syncing, create the namespace and secrets:
|
||||
# kubectl create namespace teslamate
|
||||
# op inject -i argocd/manifests/databases/secret-teslamate.yaml.tpl | kubectl apply -f -
|
||||
# op inject -i argocd/manifests/teslamate/secret-encryption-key.yaml.tpl | kubectl apply -f -
|
||||
# op inject -i argocd/manifests/teslamate/secret-db.yaml.tpl | kubectl apply -f -
|
||||
#
|
||||
# Then create the database:
|
||||
# PGPASSWORD=$(op --vault blumeops item get <eblume-item-id> --fields password --reveal) \
|
||||
# psql -h pg.tail8d86e.ts.net -U eblume -c "CREATE DATABASE teslamate OWNER teslamate;"
|
||||
#
|
||||
# After syncing, access the TeslaMate UI at https://tesla.tail8d86e.ts.net to complete
|
||||
# Tesla API authentication via OAuth flow.
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: teslamate
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/blumeops.git
|
||||
targetRevision: main
|
||||
path: argocd/manifests/teslamate
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: teslamate
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
|
|
@ -7,6 +7,7 @@ metadata:
|
|||
namespace: databases
|
||||
spec:
|
||||
instances: 1
|
||||
imageName: ghcr.io/cloudnative-pg/postgresql:18
|
||||
|
||||
storage:
|
||||
size: 10Gi
|
||||
|
|
@ -43,6 +44,17 @@ spec:
|
|||
- pg_read_all_data
|
||||
passwordSecret:
|
||||
name: blumeops-pg-borgmatic
|
||||
# teslamate user for TeslaMate Tesla data logger
|
||||
# Note: superuser required for extension management during migrations
|
||||
- name: teslamate
|
||||
login: true
|
||||
superuser: true
|
||||
connectionLimit: -1
|
||||
ensure: present
|
||||
inherit: true
|
||||
createdb: true
|
||||
passwordSecret:
|
||||
name: blumeops-pg-teslamate
|
||||
|
||||
# Resource limits for minikube environment
|
||||
resources:
|
||||
|
|
|
|||
11
argocd/manifests/databases/secret-teslamate.yaml.tpl
Normal file
11
argocd/manifests/databases/secret-teslamate.yaml.tpl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Template for TeslaMate database user password
|
||||
# Apply with: op inject -i argocd/manifests/databases/secret-teslamate.yaml.tpl | kubectl apply -f -
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: blumeops-pg-teslamate
|
||||
namespace: databases
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
username: teslamate
|
||||
password: {{ op://blumeops/TeslaMate/db_password }}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,419 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-charge-level
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-charge-level.json: |
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "Charge Level",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"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": "line"
|
||||
}
|
||||
},
|
||||
"decimals": 0,
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "transparent",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percent"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 21,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"max",
|
||||
"min"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"maxHeight": 600,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n\tdate_bin('2 minutes'::interval, timezone('UTC', date), to_timestamp(${__from:date:seconds})) as time,\n\tavg(battery_level) AS \"Battery Level\",\n\tavg(usable_battery_level) AS \"Usable Battery Level\"\nfrom positions\n\tWHERE $__timeFilter(date) AND car_id = $car_id and ideal_battery_range_km is not null\n\tgroup by time\n\tORDER BY time ASC\n;",
|
||||
"refId": "A",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\r\n 20 as lower,\r\n CASE WHEN lfp_battery THEN 100 ELSE 80 END as upper\r\nfrom cars inner join car_settings on cars.settings_id = car_settings.id\r\nwhere cars.id = $car_id",
|
||||
"refId": "B",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "-- To be able to calculate percentiles for unevenly sampled values we are bucketing & gapfilling values before running calculations\r\nwith positions_filtered as (\r\n select\r\n date,\r\n battery_level\r\n from\r\n positions p\r\n where\r\n p.car_id = $car_id\r\n -- p.ideal_battery_range_km condition is added to reduce overall amount of data and avoid data biases while driving (unevenly sampled data)\r\n and p.ideal_battery_range_km is not null\r\n and 1 = $include_average_percentiles\r\n),\r\ngen_date_series as (\r\n select\r\n -- series is used to bucket data and avoid gaps in series used to determine percentiles\r\n generate_series(to_timestamp(${__from:date:seconds} - (86400 * $days_moving_average_percentiles / 2)), to_timestamp(${__to:date:seconds}), concat($bucket_width, ' seconds')::INTERVAL) as series_id\r\n),\r\ndate_series as (\r\n select\r\n timezone('UTC', series_id) as series_id,\r\n -- before joining, get beginning of next series to be able to left join `positions_filtered`\r\n timezone('UTC', lead(series_id) over (order by series_id asc)) as next_series_id\r\n from\r\n gen_date_series\r\n),\r\npositions_bucketed as (\r\n select\r\n series_id,\r\n -- simple average can result in loss of accuracy, see https://www.timescale.com/blog/what-time-weighted-averages-are-and-why-you-should-care/ for details\r\n avg(battery_level) as battery_level,\r\n min(positions_filtered.date) as series_min_date\r\n from\r\n date_series\r\n left join positions_filtered on\r\n positions_filtered.date >= date_series.series_id\r\n and positions_filtered.date < date_series.next_series_id\r\n group by\r\n series_id\r\n),\r\n-- PostgreSQL cannot IGNORE NULLS via Window Functions LAST_VALUE - therefore use natural behavior of COUNT & MAX, see https://www.reddit.com/r/SQL/comments/wb949v/comment/ii5mmmi/ for details\r\npositions_bucketed_gapfilling_locf_intermediate as (\r\n select\r\n series_id,\r\n battery_level,\r\n series_min_date,\r\n count(battery_level) over (order by series_id) as i\r\n from\r\n positions_bucketed\r\n\r\n),\r\npositions_bucketed_gapfilled_locf as (\r\n select\r\n series_id,\r\n series_min_date,\r\n max(battery_level) over (partition by i) as battery_level_locf\r\n from\r\n positions_bucketed_gapfilling_locf_intermediate\r\n),\r\n-- PostgreSQL cannot use PERCENTILE_DISC as Window Function - therefore use ARRAY_AGG and UNNEST, see https://stackoverflow.com/a/72718604 for details\r\npositions_bucketed_gapfilled_locf_percentile_intermediate as (\r\n select\r\n series_id,\r\n series_min_date,\r\n min(series_min_date) over () as min_date,\r\n array_agg(battery_level_locf) over w as arr,\r\n avg(battery_level_locf) over w as battery_level_avg\r\n from\r\n positions_bucketed_gapfilled_locf\r\n window w as (rows between (86400 / $bucket_width) * ($days_moving_average_percentiles / 2) preceding and (86400 / $bucket_width) * ($days_moving_average_percentiles / 2) following)\r\n)\r\n\r\nselect\r\n series_id::timestamptz,\r\n (select percentile_cont(0.075) within group (order by s) from unnest(arr) trick(s)) as \"$days_moving_average_percentiles Day Moving 7.5% Percentile (${bucket_width:text} buckets)\",\r\n battery_level_avg as \"$days_moving_average_percentiles Day Moving Average (${bucket_width:text} buckets)\",\r\n (select percentile_cont(0.5) within group (order by s) from unnest(arr) trick(s)) as \"$days_moving_average_percentiles Day Moving Median (${bucket_width:text} buckets)\",\r\n (select percentile_cont(0.925) within group (order by s) from unnest(arr) trick(s)) as \"$days_moving_average_percentiles Day Moving 92.5% Percentile (${bucket_width:text} buckets)\"\r\nfrom\r\n positions_bucketed_gapfilled_locf_percentile_intermediate where $__timeFilter(series_id) and series_min_date >= min_date",
|
||||
"refId": "C",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Charge Level",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "configFromData",
|
||||
"options": {
|
||||
"applyTo": {
|
||||
"id": "byFrameRefID",
|
||||
"options": "A"
|
||||
},
|
||||
"configRefId": "B",
|
||||
"mappings": [
|
||||
{
|
||||
"fieldName": "lower",
|
||||
"handlerArguments": {
|
||||
"threshold": {
|
||||
"color": "green"
|
||||
}
|
||||
},
|
||||
"handlerKey": "threshold1"
|
||||
},
|
||||
{
|
||||
"fieldName": "upper",
|
||||
"handlerArguments": {
|
||||
"threshold": {
|
||||
"color": "green"
|
||||
}
|
||||
},
|
||||
"handlerKey": "threshold1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "2h",
|
||||
"value": "7200"
|
||||
},
|
||||
"description": "Data used to calculate Moving Average / Percentiles is unevenly sampled in TeslaMate. To avoid biases towards more frequently sampled values, the data is bucketed. For buckets without sampled values, the last observed value is carried forward. Bucketing is not time-weighted but is a simple average. Increasing the bucket width results in a loss of accuracy.",
|
||||
"includeAll": false,
|
||||
"label": "Bucket Width",
|
||||
"name": "bucket_width",
|
||||
"options": [
|
||||
{
|
||||
"selected": false,
|
||||
"text": "1h",
|
||||
"value": "3600"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "2h",
|
||||
"value": "7200"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "4h",
|
||||
"value": "14400"
|
||||
}
|
||||
],
|
||||
"query": "1h : 3600, 2h : 7200, 4h : 14400",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "yes",
|
||||
"value": "1"
|
||||
},
|
||||
"includeAll": false,
|
||||
"label": "Include Moving Average / Percentiles",
|
||||
"name": "include_average_percentiles",
|
||||
"options": [
|
||||
{
|
||||
"selected": false,
|
||||
"text": "no",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "yes",
|
||||
"value": "1"
|
||||
}
|
||||
],
|
||||
"query": "no : 0, yes : 1",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "1/6 of interval",
|
||||
"value": "6"
|
||||
},
|
||||
"description": "",
|
||||
"includeAll": false,
|
||||
"label": "Moving Average / Percentiles Width",
|
||||
"name": "intervals_moving_average_percentiles",
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "1/6 of interval",
|
||||
"value": "6"
|
||||
},
|
||||
{
|
||||
"selected": false,
|
||||
"text": "1/12 of interval",
|
||||
"value": "12"
|
||||
}
|
||||
],
|
||||
"query": "1/6 of interval : 6, 1/12 of interval : 12",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select ((${__to:date:seconds} - ${__from:date:seconds}) / 86400 / $intervals_moving_average_percentiles)",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "days_moving_average_percentiles",
|
||||
"options": [],
|
||||
"query": "select ((${__to:date:seconds} - ${__from:date:seconds}) / 86400 / $intervals_moving_average_percentiles)",
|
||||
"refresh": 2,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6M",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Charge Level",
|
||||
"uid": "WopVO_mgz",
|
||||
"version": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,293 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-mileage
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-mileage.json: |
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 20,
|
||||
"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": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"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,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"min",
|
||||
"max"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"maxHeight": 600,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Mileage",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select unit_of_length from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "length_unit",
|
||||
"options": [],
|
||||
"query": "select unit_of_length from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6M",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Mileage",
|
||||
"uid": "NjtMTFggz",
|
||||
"version": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,772 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-projected-range
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-projected-range.json: |
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "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,
|
||||
"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,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "Projected Range",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"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": 0
|
||||
},
|
||||
{
|
||||
"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,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"max",
|
||||
"min"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"maxHeight": 600,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Projected Range - Mileage",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "Projected Range",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"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": 0
|
||||
},
|
||||
{
|
||||
"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,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"max",
|
||||
"min"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"maxHeight": 600,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n\t$__timeGroup(date, $interval) AS time,\n\tconvert_km((sum(${preferred_range}_battery_range_km) / sum(battery_level) * 100 ) - (sum(${preferred_range}_battery_range_km) / sum(battery_level) * 100 * (avg(battery_level)-avg(coalesce(usable_battery_level,battery_level)))/100 ), '$length_unit') AS \"Projected Range (using usable_battery_level) [$length_unit]\",\n\tconvert_km(max(${preferred_range}_battery_range_km) / max(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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Projected Range - Battery Level",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "Projected Range",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"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": 0
|
||||
},
|
||||
{
|
||||
"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,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [
|
||||
"mean",
|
||||
"max",
|
||||
"min"
|
||||
],
|
||||
"displayMode": "table",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"rawQuery": true,
|
||||
"rawSql": "\nSELECT\n\t$__timeGroup(date, $interval) AS time,\n\tconvert_km((sum(${preferred_range}_battery_range_km) / sum(battery_level) * 100 ) - (sum(${preferred_range}_battery_range_km) / sum(battery_level) * 100 * (avg(battery_level)-avg(coalesce(usable_battery_level,battery_level)))/100 ), '$length_unit') AS \"Projected Range (using usable_battery_level) [$length_unit]\",\n\tconvert_km(max(${preferred_range}_battery_range_km) / max(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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Projected Range - Outdoor Temp",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select unit_of_length from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "length_unit",
|
||||
"options": [],
|
||||
"query": "select unit_of_length from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select preferred_range from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "preferred_range",
|
||||
"options": [],
|
||||
"query": "select preferred_range from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select unit_of_temperature from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "temp_unit",
|
||||
"options": [],
|
||||
"query": "select unit_of_temperature from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"auto": false,
|
||||
"auto_count": 30,
|
||||
"auto_min": "10s",
|
||||
"current": {
|
||||
"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,
|
||||
"type": "interval"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6M",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Projected Range",
|
||||
"uid": "riqUfXgRz",
|
||||
"version": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,528 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-states
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-states.json: |
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 16,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"description": "Only distinguishes between online, offline and asleep.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "#c7d0d9",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "dateTimeAsLocal"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"fieldOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
]
|
||||
},
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "horizontal",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
],
|
||||
"fields": "/^time$/",
|
||||
"values": true
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "select $__time(start_date), state from states where car_id = $car_id order by start_date desc limit 1;",
|
||||
"refId": "A",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Last state change",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"description": "Only distinguishes between online, offline and asleep.",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "#c7d0d9",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "none"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 6,
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"fieldOptions": {
|
||||
"calcs": [
|
||||
"first"
|
||||
]
|
||||
},
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "horizontal",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
],
|
||||
"fields": "/^state$/",
|
||||
"values": true
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "select $__time(start_date), state from states where car_id = $car_id order by start_date desc limit 1;",
|
||||
"refId": "A",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Current State",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "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": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"fieldOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
]
|
||||
},
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "horizontal",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
],
|
||||
"fields": "",
|
||||
"values": true
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "parked (%)",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "continuous-GrYlRd"
|
||||
},
|
||||
"custom": {
|
||||
"axisPlacement": "auto",
|
||||
"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": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 4
|
||||
},
|
||||
"id": 14,
|
||||
"options": {
|
||||
"alignValue": "center",
|
||||
"legend": {
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"mergeValues": true,
|
||||
"rowHeight": 0.9,
|
||||
"showValue": "auto",
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"maxHeight": 600,
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "time_series",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "States",
|
||||
"type": "state-timeline"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-2d",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "States",
|
||||
"uid": "xo4BNRkZz",
|
||||
"version": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,619 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-updates
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-updates.json: |
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "#c7d0d9",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 8,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"count"
|
||||
],
|
||||
"fields": "",
|
||||
"values": true
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT count(*)\nFROM updates\nWHERE $__timeFilter(start_date) AND car_id = $car_id",
|
||||
"refId": "A",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Updates",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"decimals": 1,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "#c7d0d9",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "dtdurations"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 3,
|
||||
"w": 16,
|
||||
"x": 8,
|
||||
"y": 1
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
],
|
||||
"fields": "",
|
||||
"values": true
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Median time between updates",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"filterable": false,
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "time"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 210
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Date"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "dateTimeAsLocal"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "update_duration"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 120
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Duration"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "dtdurations"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "since_last_update"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 180
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Since Previous Update"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "chg_ct"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 120
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "# of Charges"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "avg_ideal_range_km"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 130
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthkm"
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Ideal range"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "avg_rated_range_km"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 130
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthkm"
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Rated range"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "avg_ideal_range_mi"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 130
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthmi"
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Ideal range"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "avg_rated_range_mi"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 130
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthmi"
|
||||
},
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Rated range"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 28,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 4
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true,
|
||||
"sortBy": [
|
||||
{
|
||||
"desc": true,
|
||||
"displayName": "Date"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"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 date_trunc('hour', timezone('UTC', date), '$__timezone') AS date,\r\n\t (sum(${preferred_range}_battery_range_km)/ nullif(sum(usable_battery_level),0) * 100 ) AS \"battery_rng\",\r\n\t sum(case when action = 'Charge' then 1 else 0 end) as chg_ct\r\n FROM (\r\n select usable_battery_level, start_date as date, start_rated_range_km as rated_battery_range_km, start_ideal_range_km as ideal_battery_range_km, 'Drive' as action\r\n from drives d\r\n inner join positions p on d.start_position_id = p.id \r\n where d.car_id = $car_id and $__timeFilter(start_date) and usable_battery_level > 0\r\n union all\r\n select end_battery_level as usable_battery_level, end_date, end_rated_range_km as rated_battery_range_km, end_ideal_range_km as ideal_battery_range_km, 'Charge' as action\r\n from charging_processes p\r\n where $__timeFilter(end_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\tage(date(u.start_date), 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\tsum(r.chg_ct) 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 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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Updates",
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select preferred_range from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "preferred_range",
|
||||
"options": [],
|
||||
"query": "select preferred_range from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select unit_of_length from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "length_unit",
|
||||
"options": [],
|
||||
"query": "select unit_of_length from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-10y",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Updates",
|
||||
"uid": "IiC07mgWz",
|
||||
"version": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,666 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-vampire-drain
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-vampire-drain.json: |
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"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/drive-details?from=${__data.fields.start_date_ts.numeric}&to=${__data.fields.end_date_ts.numeric}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 210
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "end_date"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "End"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "dateTimeAsLocal"
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 210
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "range_diff_km"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Range loss"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthkm"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 95
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "duration"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Period"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "s"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"id": "custom.cellOptions",
|
||||
"value": {
|
||||
"type": "color-text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "thresholds",
|
||||
"value": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "rgb(133, 142, 133)",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "#56A64B",
|
||||
"value": 43200
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 100
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "range_lost_per_hour_km"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Range loss / h"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthkm"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 135
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byRegexp",
|
||||
"options": "/.*_ts/"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "custom.hidden",
|
||||
"value": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "standby"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Standby"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "percentunit"
|
||||
},
|
||||
{
|
||||
"id": "custom.cellOptions",
|
||||
"value": {
|
||||
"type": "color-text"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "thresholds",
|
||||
"value": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "#FF7383",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "#FFB357",
|
||||
"value": 0.3
|
||||
},
|
||||
{
|
||||
"color": "#56A64B",
|
||||
"value": 0.85
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "consumption"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Energy drained"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "kwatth"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 125
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "avg_power"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Power"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "watt"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "range_lost_per_hour_mi"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Ø Range loss / h"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthmi"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 135
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "range_diff_mi"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Range loss"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "lengthmi"
|
||||
},
|
||||
{
|
||||
"id": "decimals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 95
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "soc_diff"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "SoC Diff"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "percent"
|
||||
},
|
||||
{
|
||||
"id": "custom.minWidth",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": 50
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 23,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"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",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Vampire Drain",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "merge",
|
||||
"options": {
|
||||
"reducers": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {
|
||||
"text": "6",
|
||||
"value": "6"
|
||||
},
|
||||
"includeAll": false,
|
||||
"label": "min. Idle Time (h)",
|
||||
"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",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select unit_of_length from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "length_unit",
|
||||
"options": [],
|
||||
"query": "select unit_of_length from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select preferred_range from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "preferred_range",
|
||||
"options": [],
|
||||
"query": "select preferred_range from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-90d",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Vampire Drain",
|
||||
"uid": "zhHx2Fggk",
|
||||
"version": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,571 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: grafana-dashboard-teslamate-visited
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_dashboard: "1"
|
||||
annotations:
|
||||
grafana_folder: "TeslaMate"
|
||||
data:
|
||||
teslamate-visited.json: |
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"collapsed": false,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"panels": [],
|
||||
"repeat": "car_id",
|
||||
"title": "$car_id",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "dark-red",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 21,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"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": "none"
|
||||
},
|
||||
"view": {
|
||||
"allLayers": true,
|
||||
"id": "fit",
|
||||
"lat": 0,
|
||||
"lon": 0,
|
||||
"zoom": 15
|
||||
}
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n date_trunc('minute', timezone('UTC', date), '$__timezone') as time,\n avg(latitude) as latitude,\n avg(longitude) as longitude\nFROM\n positions\nWHERE\n car_id = $car_id AND $__timeFilter(date) and ideal_battery_range_km is not null\nGROUP BY 1\nORDER BY 1",
|
||||
"refId": "Positions",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"type": "geomap"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "super-light-blue",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 5,
|
||||
"x": 0,
|
||||
"y": 22
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "horizontal",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "/.*/",
|
||||
"values": true
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value_and_name",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT ROUND(convert_km((max(end_km) - min(start_km))::numeric, '$length_unit'),0)|| ' $length_unit' as \"Mileage\"\nFROM drives WHERE car_id = $car_id AND $__timeFilter(start_date)",
|
||||
"refId": "distance traveled",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"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": "Charging Efficiency"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 14,
|
||||
"x": 5,
|
||||
"y": 22
|
||||
},
|
||||
"id": 6,
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "center",
|
||||
"orientation": "vertical",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value_and_name",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n\tsum(charge_energy_added) as \"Total Energy added\",\n\tSUM(greatest(charge_energy_added, charge_energy_used)) AS \"Total Energy used\",\n\tSUM(charge_energy_added) * 100 / SUM(greatest(charge_energy_added, charge_energy_used)) AS \"Charging Efficiency\"\nFROM\n\tcharging_processes\nWHERE\n\tcar_id = $car_id AND $__timeFilter(start_date) AND charge_energy_added > 0.01",
|
||||
"refId": "A",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"decimals": 2,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 2,
|
||||
"w": 5,
|
||||
"x": 19,
|
||||
"y": 22
|
||||
},
|
||||
"id": 7,
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "horizontal",
|
||||
"percentChangeColorMode": "standard",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showPercentChange": false,
|
||||
"textMode": "value_and_name",
|
||||
"wideLayout": true
|
||||
},
|
||||
"pluginVersion": "12.1.1",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"editorMode": "code",
|
||||
"format": "table",
|
||||
"rawQuery": true,
|
||||
"rawSql": "select sum(cost) as \"Total Charging Cost\" from charging_processes where $__timeFilter(start_date) AND car_id = $car_id;",
|
||||
"refId": "A",
|
||||
"sql": {
|
||||
"columns": [
|
||||
{
|
||||
"parameters": [],
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"groupBy": [
|
||||
{
|
||||
"property": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "groupBy"
|
||||
}
|
||||
],
|
||||
"limit": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "",
|
||||
"type": "stat"
|
||||
}
|
||||
],
|
||||
"preload": false,
|
||||
"refresh": "",
|
||||
"schemaVersion": 41,
|
||||
"tags": [
|
||||
"tesla"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"hide": 2,
|
||||
"includeAll": true,
|
||||
"label": "Car",
|
||||
"name": "car_id",
|
||||
"options": [],
|
||||
"query": "SELECT\n id as __value,\n CASE WHEN COUNT(id) OVER (PARTITION BY name) > 1 AND name IS NOT NULL THEN CONCAT(name, ' - ', RIGHT(vin, 6)) ELSE COALESCE(name, CONCAT('VIN ', vin)) end as __text \nFROM cars\nORDER BY display_priority ASC, name ASC, vin ASC;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "select base_url from settings limit 1;",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "base_url",
|
||||
"options": [],
|
||||
"query": "select base_url from settings limit 1;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
},
|
||||
{
|
||||
"current": {},
|
||||
"datasource": {
|
||||
"type": "grafana-postgresql-datasource",
|
||||
"uid": "TeslaMate"
|
||||
},
|
||||
"definition": "SELECT unit_of_length FROM settings LIMIT 1",
|
||||
"hide": 2,
|
||||
"includeAll": false,
|
||||
"name": "length_unit",
|
||||
"options": [],
|
||||
"query": "SELECT unit_of_length FROM settings LIMIT 1",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-90d",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Visited",
|
||||
"uid": "RG_DxSmgk",
|
||||
"version": 1
|
||||
}
|
||||
|
|
@ -15,3 +15,22 @@ resources:
|
|||
- dashboards/configmap-postgresql.yaml
|
||||
- dashboards/configmap-services.yaml
|
||||
- dashboards/configmap-zot.yaml
|
||||
# TeslaMate dashboards
|
||||
- dashboards/configmap-teslamate-overview.yaml
|
||||
- dashboards/configmap-teslamate-charges.yaml
|
||||
- dashboards/configmap-teslamate-drives.yaml
|
||||
- dashboards/configmap-teslamate-efficiency.yaml
|
||||
- dashboards/configmap-teslamate-states.yaml
|
||||
- dashboards/configmap-teslamate-vampire-drain.yaml
|
||||
- dashboards/configmap-teslamate-battery-health.yaml
|
||||
- dashboards/configmap-teslamate-statistics.yaml
|
||||
- dashboards/configmap-teslamate-charge-level.yaml
|
||||
- dashboards/configmap-teslamate-updates.yaml
|
||||
- dashboards/configmap-teslamate-trip.yaml
|
||||
- dashboards/configmap-teslamate-locations.yaml
|
||||
- dashboards/configmap-teslamate-mileage.yaml
|
||||
- dashboards/configmap-teslamate-drive-stats.yaml
|
||||
- dashboards/configmap-teslamate-charging-stats.yaml
|
||||
- dashboards/configmap-teslamate-projected-range.yaml
|
||||
- dashboards/configmap-teslamate-timeline.yaml
|
||||
- dashboards/configmap-teslamate-visited.yaml
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# TeslaMate PostgreSQL datasource password for Grafana
|
||||
# Apply with: op inject -i argocd/manifests/grafana-config/secret-teslamate-datasource.yaml.tpl | kubectl apply -f -
|
||||
#
|
||||
# This secret is mounted as environment variables in Grafana
|
||||
# The password is referenced in values.yaml datasource config as $TESLAMATE_DB_PASSWORD
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: grafana-teslamate-datasource
|
||||
namespace: monitoring
|
||||
type: Opaque
|
||||
stringData:
|
||||
TESLAMATE_DB_PASSWORD: {{ op://blumeops/TeslaMate/db_password }}
|
||||
|
|
@ -8,6 +8,11 @@ admin:
|
|||
userKey: admin-user
|
||||
passwordKey: admin-password
|
||||
|
||||
# Environment variables from secrets (for datasource credentials)
|
||||
envFromSecrets:
|
||||
- name: grafana-teslamate-datasource
|
||||
optional: true
|
||||
|
||||
# Persistence with PVC for SQLite database
|
||||
persistence:
|
||||
enabled: true
|
||||
|
|
@ -44,6 +49,22 @@ datasources:
|
|||
uid: loki
|
||||
url: http://loki.monitoring.svc.cluster.local:3100
|
||||
editable: false
|
||||
- name: TeslaMate
|
||||
type: postgres
|
||||
access: proxy
|
||||
orgId: 1
|
||||
uid: TeslaMate
|
||||
url: blumeops-pg-rw.databases.svc.cluster.local:5432
|
||||
database: teslamate
|
||||
user: teslamate
|
||||
editable: false
|
||||
jsonData:
|
||||
sslmode: disable
|
||||
maxOpenConns: 5
|
||||
maxIdleConns: 2
|
||||
connMaxLifetime: 14400
|
||||
secureJsonData:
|
||||
password: $TESLAMATE_DB_PASSWORD
|
||||
|
||||
# Dashboard provisioning - sidecar watches for ConfigMaps with label
|
||||
sidecar:
|
||||
|
|
|
|||
69
argocd/manifests/teslamate/README.md
Normal file
69
argocd/manifests/teslamate/README.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# TeslaMate
|
||||
|
||||
TeslaMate is a self-hosted Tesla data logger that collects and visualizes vehicle data.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### 1. Create 1Password Secrets
|
||||
|
||||
Create two items in the blumeops 1Password vault:
|
||||
|
||||
1. **TeslaMate DB Password**
|
||||
- Generate a secure password for the teslamate PostgreSQL user
|
||||
- Add a field named `password` with the generated value
|
||||
|
||||
2. **TeslaMate Encryption Key**
|
||||
- Generate with: `openssl rand -base64 32`
|
||||
- Add a field named `key` with the generated value
|
||||
- This encrypts Tesla API tokens at rest in the database
|
||||
|
||||
### 2. Apply Kubernetes Secrets
|
||||
|
||||
```bash
|
||||
# Create namespace
|
||||
kubectl create namespace teslamate
|
||||
|
||||
# Apply database user secret (for CNPG)
|
||||
op inject -i argocd/manifests/databases/secret-teslamate.yaml.tpl | kubectl apply -f -
|
||||
|
||||
# Apply teslamate secrets
|
||||
op inject -i argocd/manifests/teslamate/secret-encryption-key.yaml.tpl | kubectl apply -f -
|
||||
op inject -i argocd/manifests/teslamate/secret-db.yaml.tpl | kubectl apply -f -
|
||||
```
|
||||
|
||||
### 3. Create Database
|
||||
|
||||
After the teslamate user exists in PostgreSQL (sync blumeops-pg first):
|
||||
|
||||
```bash
|
||||
PGPASSWORD=$(op --vault blumeops item get <eblume-item-id> --fields password --reveal) \
|
||||
psql -h pg.tail8d86e.ts.net -U eblume -c "CREATE DATABASE teslamate OWNER teslamate;"
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
# Sync ArgoCD apps
|
||||
argocd app sync apps
|
||||
argocd app sync blumeops-pg teslamate grafana grafana-config
|
||||
```
|
||||
|
||||
## Tesla API Setup
|
||||
|
||||
1. Access TeslaMate UI at https://tesla.tail8d86e.ts.net
|
||||
2. Click "Sign in with Tesla"
|
||||
3. Complete OAuth flow in browser
|
||||
4. Tokens are encrypted and stored in database
|
||||
5. Verify vehicle appears and data collection starts
|
||||
|
||||
## Grafana Dashboards
|
||||
|
||||
TeslaMate dashboards are available in Grafana at https://grafana.tail8d86e.ts.net
|
||||
|
||||
They use the "TeslaMate" PostgreSQL datasource (not Prometheus).
|
||||
|
||||
## Notes
|
||||
|
||||
- MQTT is disabled (can be enabled later for Home Assistant integration)
|
||||
- Timezone is set to America/Los_Angeles
|
||||
- Encryption key protects Tesla API tokens at rest
|
||||
62
argocd/manifests/teslamate/deployment.yaml
Normal file
62
argocd/manifests/teslamate/deployment.yaml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: teslamate
|
||||
namespace: teslamate
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: teslamate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: teslamate
|
||||
spec:
|
||||
containers:
|
||||
- name: teslamate
|
||||
image: teslamate/teslamate:2.2.0
|
||||
ports:
|
||||
- containerPort: 4000
|
||||
env:
|
||||
- name: DATABASE_USER
|
||||
value: "teslamate"
|
||||
- name: DATABASE_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: teslamate-db
|
||||
key: password
|
||||
- name: DATABASE_NAME
|
||||
value: "teslamate"
|
||||
- name: DATABASE_HOST
|
||||
value: "blumeops-pg-rw.databases.svc.cluster.local"
|
||||
- name: ENCRYPTION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: teslamate-encryption
|
||||
key: key
|
||||
- name: DISABLE_MQTT
|
||||
value: "true"
|
||||
- name: CHECK_ORIGIN
|
||||
value: "false"
|
||||
- name: TZ
|
||||
value: "America/Los_Angeles"
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 4000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 4000
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
17
argocd/manifests/teslamate/ingress-tailscale.yaml
Normal file
17
argocd/manifests/teslamate/ingress-tailscale.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: teslamate-tailscale
|
||||
namespace: teslamate
|
||||
annotations:
|
||||
tailscale.com/proxy-class: "default"
|
||||
spec:
|
||||
ingressClassName: tailscale
|
||||
defaultBackend:
|
||||
service:
|
||||
name: teslamate
|
||||
port:
|
||||
number: 4000
|
||||
tls:
|
||||
- hosts:
|
||||
- tesla
|
||||
9
argocd/manifests/teslamate/kustomization.yaml
Normal file
9
argocd/manifests/teslamate/kustomization.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: teslamate
|
||||
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
- ingress-tailscale.yaml
|
||||
11
argocd/manifests/teslamate/secret-db.yaml.tpl
Normal file
11
argocd/manifests/teslamate/secret-db.yaml.tpl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# TeslaMate database password secret
|
||||
#
|
||||
# Apply with: op inject -i argocd/manifests/teslamate/secret-db.yaml.tpl | kubectl apply -f -
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: teslamate-db
|
||||
namespace: teslamate
|
||||
type: Opaque
|
||||
stringData:
|
||||
password: {{ op://blumeops/TeslaMate/db_password }}
|
||||
12
argocd/manifests/teslamate/secret-encryption-key.yaml.tpl
Normal file
12
argocd/manifests/teslamate/secret-encryption-key.yaml.tpl
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# TeslaMate encryption key secret
|
||||
# This key encrypts Tesla API tokens at rest in the database
|
||||
#
|
||||
# Apply with: op inject -i argocd/manifests/teslamate/secret-encryption-key.yaml.tpl | kubectl apply -f -
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: teslamate-encryption
|
||||
namespace: teslamate
|
||||
type: Opaque
|
||||
stringData:
|
||||
key: {{ op://blumeops/TeslaMate/api_enc_key }}
|
||||
12
argocd/manifests/teslamate/service.yaml
Normal file
12
argocd/manifests/teslamate/service.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: teslamate
|
||||
namespace: teslamate
|
||||
spec:
|
||||
selector:
|
||||
app: teslamate
|
||||
ports:
|
||||
- port: 4000
|
||||
targetPort: 4000
|
||||
type: ClusterIP
|
||||
Loading…
Add table
Add a link
Reference in a new issue