Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utilize charges as additional anchor points for vampire drain dashboard #769

Merged
merged 2 commits into from
May 30, 2020

Conversation

tacotran
Copy link
Contributor

This change will additionally track vampire drain periods that include charges, including periods between drives and charges, charges and drives, and between two charges.

Partial solution to #429 although it does not exclude periods where the car is preheating.

Copy link
Collaborator

@adriankumpf adriankumpf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, that's a long requested feature! I think you're the first who's ever made major changes to this monstrous query 😄 👏

While debugging, I thought of how to avoid the position_id + 1 workaround. I'll push my changes and merge this.

@@ -358,7 +358,7 @@
"group": [],
"metricColumn": "none",
"rawQuery": true,
"rawSql": "with v0 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_rated_range_km) OVER w AS start_rated_range,\n t.start_rated_range_km AS end_rated_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_position_id) OVER w AS start_position_id,\n t.start_position_id AS end_position_id\n FROM drives t\n WHERE car_id = $car_id AND $__timeFilter(start_date)\n WINDOW w AS (ORDER BY t.id ASC)\n ORDER BY id DESC\n),\nv as (\n SELECT\n *,\n start_position.battery_level AS start_soc,\n end_position.battery_level AS end_soc,\n start_position.usable_battery_level AS start_usable_soc,\n end_position.usable_battery_level AS end_usable_soc,\n greatest(start_position.battery_level - end_position.battery_level, 0) AS soc_diff,\n\t\tend_position.battery_level > end_position.usable_battery_level AS has_reduced_range\n FROM v0\n JOIN positions start_position ON start_position_id = start_position.id\n JOIN positions end_position ON end_position_id = end_position.id\n),\nc as (\n select efficiency from cars where id = $car_id\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 as start_date_[[length_unit]],\n v.end_date as end_date_[[length_unit]],\n v.duration,\n (coalesce(s_asleep.sleep, 0) + coalesce(s_offline.sleep, 0)) / v.duration as standby,\n\t-soc_diff 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) 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) END, '$length_unit') AS range_lost_per_hour_[[length_unit]]\nFROM v, c,\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\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;\n",
"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 c.position_id AS start_position_id,\n c.position_id + 1 AS end_position_id,\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 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 d.start_position_id AS start_position_id,\n d.end_position_id AS end_position_id,\n d.start_km AS start_km,\n d.end_km AS end_km\n FROM drives d\n WHERE car_id = $car_id AND $__timeFilter(start_date)\n ORDER BY start_date\n), v0 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_rated_range_km) OVER w AS start_rated_range,\n t.start_rated_range_km AS end_rated_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_position_id) OVER w AS start_position_id,\n t.start_position_id AS end_position_id\n FROM merge t\n WINDOW w AS (ORDER BY t.start_date ASC)\n ORDER BY start_date DESC\n),\nv as (\n SELECT\n *,\n start_position.battery_level AS start_soc,\n end_position.battery_level AS end_soc,\n start_position.usable_battery_level AS start_usable_soc,\n end_position.usable_battery_level AS end_usable_soc,\n greatest(start_position.battery_level - end_position.battery_level, 0) AS soc_diff,\n\t\tend_position.battery_level > end_position.usable_battery_level AS has_reduced_range\n FROM v0\n JOIN positions start_position ON start_position_id = start_position.id\n JOIN positions end_position ON end_position_id = end_position.id\n),\nc as (\n select efficiency from cars\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 as start_date_[[length_unit]],\n v.end_date as end_date_[[length_unit]],\n v.duration,\n (coalesce(s_asleep.sleep, 0) + coalesce(s_offline.sleep, 0)) / v.duration as standby,\n\t-soc_diff 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) 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) END, '$length_unit') AS range_lost_per_hour_[[length_unit]]\nFROM v, c,\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\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;\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c.position_id + 1 AS end_position_id is a clever workaround to get the end battery level of a charging session but unfortunately it cannot be relied on, especially in scenarios with multiple cars.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I just realized that as well.

Also 3a7eae4 would probably break it even if it did work.

Let me go back to the drawing board.

Unfortunately the date timestamps on the charging_processes table don't always exactly match up with what's in the positions table.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also 3a7eae4 would probably break it even if it did work.

Good point. I hadn't even thought of that.

Copy link
Collaborator

@adriankumpf adriankumpf May 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed 23f7c9c. Let me know if you spot any errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't even think of moving the SOC query up! I was working on a way to join the charges table on to my original method, but this is much cleaner.

Looks great!

@adriankumpf adriankumpf merged commit 805331f into teslamate-org:master May 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants