diff --git a/grafana/dashboards/battery-health.json b/grafana/dashboards/battery-health.json new file mode 100644 index 00000000..8ba0fc64 --- /dev/null +++ b/grafana/dashboards/battery-health.json @@ -0,0 +1,1558 @@ +{ + "__elements": [], + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "8.5.15" + }, + { + "type": "panel", + "id": "natel-plotly-panel", + "name": "Plotly", + "version": "0.0.7" + }, + { + "type": "panel", + "id": "piechart", + "name": "Pie chart", + "version": "" + }, + { + "type": "datasource", + "id": "postgres", + "name": "PostgreSQL", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "iteration": 1681039491922, + "links": [ + { + "icon": "dashboard", + "tags": [], + "title": "TeslaMate", + "tooltip": "", + "type": "link", + "url": "[[base_url:raw]]" + }, + { + "asDropdown": true, + "icon": "external link", + "tags": [ + "tesla" + ], + "title": "Dashboards", + "type": "dashboards" + } + ], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "**Usable (now)** is the estimated current battery capacity. \n\n**Usable (new)** is the estimated Battery Capacity since you begun to use Teslamate. That's why, the more data you have logged from your brand new car the better. ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Usable (new)\", \n ('$aux'::json -> 'CurrentCapacity')::text::float as \"Usable (now)\",\n ('$aux'::json -> 'CurrentCapacity')::text::float - CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END as \"Difference\"\n \n \n \n \n \n \n ", + "refId": "A", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*_km/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthkm" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*_mi/" + }, + "properties": [ + { + "id": "unit", + "value": "lengthmi" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/maxrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (new)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/currentrange_.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Max range (now)" + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/range_lost.*/" + }, + "properties": [ + { + "id": "displayName", + "value": "Range lost" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END as \"maxrange_$length_unit\",\n ('$aux'::json -> 'CurrentRange')::text::float as \"currentrange_$length_unit\",\n CASE WHEN $custom_max_range > 0 THEN $custom_max_range ELSE ('$aux'::json -> 'MaxRange')::text::float END - ('$aux'::json -> 'CurrentRange')::text::float as \"range_lost_$length_unit\"", + "refId": "A", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ranges", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT ROUND(convert_km((max(odometer) - min(odometer))::numeric, '$length_unit'),0)|| ' $length_unit' as \"Logged\"\nfrom positions where car_id = $car_id;", + "refId": "DistanceLogged", + "select": [ + [ + { + "params": [ + "efficiency" + ], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select ROUND(convert_km(ROUND(odometer::numeric,0), '$length_unit'),0) || ' $length_unit' as \"Odometer\"\nfrom positions \nwhere car_id = $car_id\norder by date desc \nlimit 1;", + "refId": "Odometer", + "select": [ + [ + { + "params": [ + "efficiency" + ], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Mileage", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-yellow", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Total energy added" + }, + "properties": [ + { + "id": "unit", + "value": "kwatth" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 36, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "mean" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tsum(charge_energy_added) as \"Total energy added\"\nFROM\n\tcharging_processes\nWHERE\n\tcar_id = $car_id;", + "refId": "A", + "select": [ + [ + { + "params": [ + "efficiency" + ], + "type": "column" + } + ] + ], + "table": "cars", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n\tround(ceil(sum(charge_energy_added) / ('$aux'::json -> 'MaxCapacity')::text::numeric),0) AS \"Estimated charging cycles\"\nFROM charging_processes WHERE car_id = $car_id;", + "refId": "B", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Stats", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "This dashboard is meant to have a look of the Battery health based on the data logged in Teslamate. So, the more data you have logged from your brand new car the better.\n\n**Degradation** is just an estimated value to have a reference, measured on **usable battery level** of every charging session with enough kWh added (in order to avoid dirty data form the sample), calculated according to the rated efficiency of the car.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 10 + }, + { + "color": "red", + "value": 20 + }, + { + "color": "dark-red", + "value": 30 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 17, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "/^greatest$/", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END))\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Estimated Degradation", + "type": "gauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "light-green", + "value": 90 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 12, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n LEAST(100, (100 - GREATEST(0, 100.0 - (('$aux'::json -> 'CurrentCapacity')::text::float * 100.0 / CASE WHEN $custom_kwh_new > 0 THEN $custom_kwh_new ELSE ('$aux'::json -> 'MaxCapacity')::text::float END)))) as \"Battery Health (%)\"\n \n", + "refId": "A", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Health", + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "Estimated charging cycles are based on the whole energy added to the battery. So the more data you logged the better. \n", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "super-light-blue", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 29, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "textMode": "value_and_name" + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n round(('$aux'::json -> 'LastChargekWhAdded')::text::numeric,1) || ' kWh' as \"Last Energy added\",\n round(('$aux'::json -> 'LastMileageAdded')::text::numeric,1) || ' $length_unit' as \"Last Range added\"", + "refId": "LastChanging", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Charges", + "type": "stat" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 2, + "mappings": [], + "unit": "kwatth" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "AC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "semi-dark-green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "DC" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 34, + "links": [], + "maxDataPoints": 3, + "options": { + "displayLabels": [ + "name", + "percent", + "value" + ], + "legend": { + "displayMode": "hidden", + "placement": "bottom" + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH data AS (\n SELECT\n\t\tcp.id,\n\t\tcp.charge_energy_added,\n\t\tCASE WHEN NULLIF(mode() within group (order by charger_phases),0) is null THEN 'DC'\n\t\t\t\t ELSE 'AC'\n\t\tEND AS current\n\tFROM charging_processes cp\n RIGHT JOIN charges ON cp.id = charges.charging_process_id\n WHERE\n\t cp.car_id = $car_id\n\t AND cp.charge_energy_added > 0.01\n GROUP BY 1,2\n)\nSELECT\n\tnow() AS time,\n\tsum(charge_energy_added) AS value,\n\tcurrent AS metric\nFROM data\nGROUP BY 3\nORDER BY metric DESC;", + "refId": "A", + "select": [ + [ + { + "params": [ + "latitude" + ], + "type": "column" + } + ] + ], + "table": "addresses", + "timeColumn": "inserted_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Summary AC/DC Energy Added", + "type": "piechart" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "semi-dark-green", + "value": 20 + }, + { + "color": "semi-dark-orange", + "value": 80 + }, + { + "color": "light-blue", + "value": 100 + } + ] + }, + "unit": "%" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 9 + }, + "id": 25, + "options": { + "displayMode": "lcd", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "text": {} + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "(SELECT usable_battery_level, date\r\nFROM positions\r\nWHERE car_id = $car_id\r\nORDER BY date DESC\r\nLIMIT 1)\r\nUNION\r\nSELECT usable_battery_level, date\r\nFROM charges c\r\nJOIN charging_processes p ON p.id = c.charging_process_id\r\nWHERE p.car_id = $car_id\r\nORDER BY date DESC\r\nLIMIT 1", + "refId": "SOC", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current SOC", + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + }, + { + "color": "dark-green", + "value": 7.84 + }, + { + "color": "semi-dark-orange", + "value": 31.36 + }, + { + "color": "light-blue", + "value": 35.28 + } + ] + }, + "unit": "kwatth" + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 27, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^kwh$/", + "values": false + }, + "showUnfilled": true, + "text": {} + }, + "pluginVersion": "8.5.15", + "targets": [ + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "%", + "metricColumn": "none", + "orderByTime": "ASC", + "policy": "default", + "rawQuery": true, + "rawSql": "(SELECT usable_battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM positions\nWHERE car_id = $car_id\nORDER BY date DESC\nLIMIT 1)\nUNION\nSELECT battery_level * ('$aux'::json -> 'CurrentCapacity')::text::float / 100 as kWh, date, ('$aux'::json -> 'CurrentCapacity')::text::float as Total\nFROM charges c\nJOIN charging_processes p ON p.id = c.charging_process_id\nWHERE p.car_id = $car_id\nORDER BY date DESC\nLIMIT 1", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Current Capacity", + "type": "bargauge" + }, + { + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 28, + "links": [], + "pconfig": { + "fixScale": "", + "layout": { + "dragmode": "zoom", + "font": { + "family": "\"Open Sans\", Helvetica, Arial, sans-serif" + }, + "hovermode": "closest", + "legend": { + "orientation": "h" + }, + "showlegend": false, + "xaxis": { + "rangemode": "normal", + "showgrid": true, + "title": "Odometer", + "type": "linear", + "zeroline": false + }, + "yaxis": { + "rangemode": "normal", + "showgrid": true, + "title": "kWh", + "type": "linear", + "zeroline": false + }, + "zaxis": { + "rangemode": "normal", + "showgrid": true, + "type": "linear", + "zeroline": false + } + }, + "loadFromCDN": false, + "settings": { + "displayModeBar": false, + "type": "scatter" + }, + "showAnnotations": true, + "traces": [ + { + "mapping": { + "color": "id", + "text": "title", + "x": "odometer", + "y": "kWh" + }, + "name": "Mileage, kWh", + "settings": { + "color_option": "ramp", + "line": { + "color": "#C0D8FF", + "dash": "dashdot", + "shape": "linear", + "width": 1 + }, + "marker": { + "color": "#33B5E5", + "colorscale": "Reds", + "line": { + "color": "#DDD", + "width": 0 + }, + "showscale": false, + "size": 10, + "sizemin": 3, + "sizemode": "diameter", + "sizeref": 0.2, + "symbol": "circle" + } + }, + "show": { + "line": true, + "lines": false, + "markers": true + } + }, + { + "mapping": { + "color": "id", + "x": "M-Odometer", + "y": "M-kWh" + }, + "name": "Median", + "settings": { + "color_option": "ramp", + "line": { + "color": "#C0D8FF", + "dash": "solid", + "shape": "linear", + "width": 2 + }, + "marker": { + "color": "#33B5E5", + "colorscale": "Reds", + "line": { + "color": "#DDD", + "width": 0 + }, + "showscale": false, + "size": 3, + "sizemin": 3, + "sizemode": "diameter", + "sizeref": 0.2, + "symbol": "circle" + } + }, + "show": { + "line": true, + "lines": true, + "markers": false + } + } + ] + }, + "pluginVersion": "8.5.6", + "targets": [ + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT convert_km(AVG(p.odometer)::numeric,'$length_unit') AS odometer, \r\n\tAVG(c.rated_battery_range_km) * ('$aux'::json -> 'RatedEfficiency')::text::float / AVG(c.usable_battery_level) AS \"kWh\",\r\n\tMAX(cp.id) AS id,\r\n\tto_char(cp.end_date, 'YYYY-MM-dd') AS Title\r\n\tFROM charging_processes cp\r\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\r\n\t\tINNER JOIN charges c\r\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\r\n\t\tINNER JOIN positions p ON p.id = cp.position_id\r\n\tWHERE cp.car_id = $car_id\r\n\t\tAND cp.end_date IS NOT NULL\r\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\r\n\tGROUP BY 4", + "refId": "Projected Range", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "alias": "", + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT \n ROUND(MIN(convert_km(p.odometer::numeric,'$length_unit')),0) AS \"M-Odometer\",\n\tROUND(PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY c.rated_battery_range_km * ('$aux'::json -> 'RatedEfficiency')::text::float / c.usable_battery_level)::numeric,1) AS \"M-kWh\",\n\tto_char(cp.end_date, 'YYYYMM') || CASE WHEN to_char(cp.end_date, 'DD')::int <= 15 THEN '1' ELSE '2' END AS Title\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\tFROM charges GROUP BY charging_process_id) AS last_charges\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN positions p ON p.id = cp.position_id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\tGROUP BY 3", + "refId": "Median", + "select": [ + [ + { + "params": [ + "start_km" + ], + "type": "column" + } + ] + ], + "table": "drives", + "timeColumn": "start_date", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Battery Capacity by Mileage", + "type": "natel-plotly-panel", + "version": 1 + } + ], + "refresh": "", + "schemaVersion": 36, + "style": "dark", + "tags": [ + "tesla" + ], + "templating": { + "list": [ + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "hide": 0, + "includeAll": false, + "label": "Car", + "multi": false, + "name": "car_id", + "options": [], + "query": "SELECT name AS __text, id AS __value FROM cars ORDER BY display_priority ASC, name ASC;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select unit_of_length from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "length_unit", + "options": [], + "query": "select unit_of_length from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "select base_url from settings limit 1;", + "hide": 2, + "includeAll": false, + "label": "", + "multi": false, + "name": "base_url", + "options": [], + "query": "select base_url from settings limit 1;", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": { + "type": "postgres", + "uid": "TeslaMate" + }, + "definition": "-- CONCATENATED JOIN QUERIES TO IMPROVE PERFORMANCE\nWITH\naux\tAS\n(\n\tSELECT cp.charge_energy_added,\n\t\tcp.car_id, cp.charge_energy_added / (cp.end_rated_range_km - cp.start_rated_range_km) * 100.0 AS rated_efficiency,\n\t\t(cp.end_rated_range_km - cp.start_rated_range_km) AS added_range_km\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\tORDER BY cp.end_date DESC \n\tLIMIT 1\n), \nCurrentCapacity\t AS\n(\n\tSELECT AVG(Capacity) AS CurrentCapacity FROM\n (SELECT (100.0 * cp.charge_energy_added) / (GREATEST(1,MAX(usable_battery_level) - MIN(usable_battery_level))) AS Capacity\t\n FROM charging_processes cp\n\t INNER JOIN charges c\tON cp.id = c.charging_process_id\n INNER JOIN aux ON cp.car_id = aux.car_id\n\t WHERE cp.car_id = $car_id AND cp.charge_energy_added >= aux.rated_efficiency AND cp.end_date >= date_trunc('month', current_date - interval '1 month') \n GROUP BY cp.charge_energy_added, cp.end_date\n ) AS lastEstimatedCapacity\n), \nMaxCapacity AS\n(\n\tSELECT MAX(c.rated_battery_range_km * cars.efficiency * 100.0 / c.usable_battery_level) AS MaxCapacity\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN cars ON cp.car_id = cars.id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\t\tAND c.charge_energy_added >= cars. Efficiency\n), \nCurrentRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS timecurrent,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 1 DESC\n\tLIMIT 1\n), \nMaxRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS time,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS max_rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 2 DESC\n\tLIMIT 1\n) \nSELECT CONCAT('{\"LastChargekWhAdded\": ', aux.charge_energy_added, \n ', \"LastMileageAdded\" : ', convert_km(aux.added_range_km,'$length_unit'),\n ', \"MaxRange\": ', convert_km(MaxRange.max_rated_range_km,'$length_unit'),\n ', \"CurrentRange\": ',convert_km(CurrentRange.rated_range_km,'$length_unit'),\n ', \"MaxCapacity\": ', MaxCapacity.MaxCapacity,\n ', \"CurrentCapacity\": ',CurrentCapacity.CurrentCapacity,\n ', \"RatedEfficiency\": ',aux.rated_efficiency, '}') \nFROM MaxRange, CurrentRange, Aux, MaxCapacity, CurrentCapacity;\n-- The following query is the result of many tests and hours of work. This panel is for your own personal use. \n-- If you think you can improve it and contribute, please create a pull request and do not take it to your repository, \n-- much less upload it to another repository as if the original idea were yours, nor do you share it on social media\n-- without mentioning the author. Respect the ingenuity and work of others. Cheers!\n-- 16/04/2023\n-- By @jheredianet - Twitter: @juanheredia", + "hide": 2, + "includeAll": false, + "multi": false, + "name": "aux", + "options": [], + "query": "-- CONCATENATED JOIN QUERIES TO IMPROVE PERFORMANCE\nWITH\naux\tAS\n(\n\tSELECT cp.charge_energy_added,\n\t\tcp.car_id, cp.charge_energy_added / (cp.end_rated_range_km - cp.start_rated_range_km) * 100.0 AS rated_efficiency,\n\t\t(cp.end_rated_range_km - cp.start_rated_range_km) AS added_range_km\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\tORDER BY cp.end_date DESC \n\tLIMIT 1\n), \nCurrentCapacity\t AS\n(\n\tSELECT AVG(Capacity) AS CurrentCapacity FROM\n (SELECT (100.0 * cp.charge_energy_added) / (GREATEST(1,MAX(usable_battery_level) - MIN(usable_battery_level))) AS Capacity\t\n FROM charging_processes cp\n\t INNER JOIN charges c\tON cp.id = c.charging_process_id\n INNER JOIN aux ON cp.car_id = aux.car_id\n\t WHERE cp.car_id = $car_id AND cp.charge_energy_added >= aux.rated_efficiency AND cp.end_date >= date_trunc('month', current_date - interval '1 month') \n GROUP BY cp.charge_energy_added, cp.end_date\n ) AS lastEstimatedCapacity\n), \nMaxCapacity AS\n(\n\tSELECT MAX(c.rated_battery_range_km * cars.efficiency * 100.0 / c.usable_battery_level) AS MaxCapacity\n\tFROM charging_processes cp\n\t\tJOIN (SELECT charging_process_id, MAX(date) as date\n\t\tFROM charges\n\t\tGROUP BY charging_process_id) AS last_charges\n\t\tON cp.id = last_charges.charging_process_id\n\t\tINNER JOIN charges c\n\t\tON c.charging_process_id = cp.id AND c.date = last_charges.date\n\t\tINNER JOIN cars ON cp.car_id = cars.id\n\tWHERE cp.car_id = $car_id\n\t\tAND cp.end_date IS NOT NULL\n\t\tAND cp.end_rated_range_km > cp.start_rated_range_km\n\t\tAND c.charge_energy_added >= cars. Efficiency\n), \nCurrentRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS timecurrent,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 1 DESC\n\tLIMIT 1\n), \nMaxRange AS\n(\n SELECT\n\t\tfloor(extract(epoch from date)/86400)*86400 AS time,\n\t\tsum(rated_battery_range_km) / sum(usable_battery_level) * 100 AS max_rated_range_km\n\tFROM (\n\t\tSELECT battery_level, usable_battery_level, date, rated_battery_range_km from charges c \n\t\tJOIN charging_processes p ON p.id = c.charging_process_id \n\t\tWHERE p.car_id = $car_id AND usable_battery_level IS NOT NULL) AS data\n\tGROUP BY 1\n\tORDER BY 2 DESC\n\tLIMIT 1\n) \nSELECT CONCAT('{\"LastChargekWhAdded\": ', aux.charge_energy_added, \n ', \"LastMileageAdded\" : ', convert_km(aux.added_range_km,'$length_unit'),\n ', \"MaxRange\": ', convert_km(MaxRange.max_rated_range_km,'$length_unit'),\n ', \"CurrentRange\": ',convert_km(CurrentRange.rated_range_km,'$length_unit'),\n ', \"MaxCapacity\": ', MaxCapacity.MaxCapacity,\n ', \"CurrentCapacity\": ',CurrentCapacity.CurrentCapacity,\n ', \"RatedEfficiency\": ',aux.rated_efficiency, '}') \nFROM MaxRange, CurrentRange, Aux, MaxCapacity, CurrentCapacity;\n-- The following query is the result of many tests and hours of work. This panel is for your own personal use. \n-- If you think you can improve it and contribute, please create a pull request and do not take it to your repository, \n-- much less upload it to another repository as if the original idea were yours, nor do you share it on social media\n-- without mentioning the author. Respect the ingenuity and work of others. Cheers!\n-- 16/04/2023\n-- By @jheredianet - Twitter: @juanheredia", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the capacity of your car battery when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, it will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Battery Capacity (kWh) when new", + "name": "custom_kwh_new", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "0", + "value": "0" + }, + "description": "Set the max range to 100% of your car when it was new, in case you started using Teslamate after a while of having it. If not, leave it at 0, the degradation will be calculated with the data that is logged in Teslamate", + "hide": 0, + "label": "Custom Max Range when new", + "name": "custom_max_range", + "options": [ + { + "selected": true, + "text": "0", + "value": "0" + } + ], + "query": "0", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + + "timepicker": { + "hidden": true, + "refresh_intervals": [] + }, + "timezone": "browser", + "title": "Battery Health", + "uid": "jchmRiqUfXgTM", + "version": 7, + "weekStart": "" +} \ No newline at end of file diff --git a/website/docs/projects.md b/website/docs/projects.md index 466bd91f..4982209b 100644 --- a/website/docs/projects.md +++ b/website/docs/projects.md @@ -2,20 +2,6 @@ title: Projects using TeslaMate --- -Here is a list of projects using TeslaMate. - -- [Gaussmeter](#gaussmeter) -- [Home Assistant Addon](#home-assistant-addon) -- [MMM-Teslamate](#mmm-teslamate) -- [TeslaMateAgile](#teslamateagile) -- [TeslaMateApi](#teslamateapi) -- [TeslaMate_Telegram_Bot](#teslamate_telegram_bot) -- [TeslaMate-ABRP](#teslamate_abrp) -- [Custom Grafana Dashboards](#customgrafanadashboards) -- [Home Assistant Integration](#tesla-home-assistant-integration) - ---- - ## [Gaussmeter](https://github.com/gaussmeter/gaussmeter) An LED illuminated acrylic Tesla Model 3. Its color and scale of light depend on the cars current state. @@ -58,7 +44,7 @@ This is a telegram bot written in Python to notify by Telegram message when a ne LINK: [github.com/JakobLichterfeld/TeslaMate_Telegram_Bot](https://github.com/JakobLichterfeld/TeslaMate_Telegram_Bot) -## [TeslaMate-ABRP](https://fetzu.github.io/teslamate-abrp/) +## [TeslaMate ABRP](https://fetzu.github.io/teslamate-abrp/) A python script (also available as a lightweight docker image) that pushes car status data to [ABetterRoutePlanner](https://abetterrouteplanner.com) based on contents of TeslaMate MQTT's topic. @@ -70,6 +56,12 @@ Collection of custom dashboards for Grafana. LINK: [github.com/CarlosCuezva/dashboards-Grafana-Teslamate](https://github.com/CarlosCuezva/dashboards-Grafana-Teslamate) +## [TeslaMate Custom Dashboards](https://github.com/jheredianet/Teslamate-CustomGrafanaDashboards) + +Teslamate Custom Dashboards: Battery Health, Charging Costs Stats, Charging CurveStats, Tracking Drives and more. Also, there are two dashboards (Current Charge & Drive View) that could be browsed on the car while driving or charging. + +LINK: [github.com/jheredianet/Teslamate-CustomGrafanaDashboards](https://github.com/jheredianet/Teslamate-CustomGrafanaDashboards) + ## [Tesla Home Assistant Integration](https://github.com/alandtse/tesla) The Tesla Home Assistant integration can use the data from the TeslaMate MQTT integration to update car data in near-real time. diff --git a/website/docs/screenshots.mdx b/website/docs/screenshots.mdx index a7da97c8..577e1c50 100644 --- a/website/docs/screenshots.mdx +++ b/website/docs/screenshots.mdx @@ -57,3 +57,11 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; ## Updates Updates + +## Lifetime driving map + +Lifetime driving map + +## Visited addresses + +Visited addresses \ No newline at end of file diff --git a/website/static/screenshots/lifetime_driving_map.png b/website/static/screenshots/lifetime_driving_map.png new file mode 100644 index 00000000..1b370736 Binary files /dev/null and b/website/static/screenshots/lifetime_driving_map.png differ diff --git a/website/static/screenshots/locations.png b/website/static/screenshots/locations.png new file mode 100644 index 00000000..bf4a9a2b Binary files /dev/null and b/website/static/screenshots/locations.png differ