teslamate icon indicating copy to clipboard operation
teslamate copied to clipboard

Trips with negative gradient do not record correctly

Open RamonMir20 opened this issue 1 year ago • 8 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

What happened?

Trips with negative gradient do not record kWh consumption, average consumption or travel efficiency, which means that the total averages do not show the real data. Living in a mountainous area, only half of the trips are recorded.

Expected Behavior

If the consumptions are 0kWh or negative, they should be displayed correctly and be part of the overall consumption calculation.

Steps To Reproduce

No response

Relevant log output

*

Screenshots

image

Additional data

No response

Type of installation

Docker

Version

v1.28.3

RamonMir20 avatar Feb 07 '24 22:02 RamonMir20

Confirmed, I am seeing this too (and I live on a mountain also...).

Not sure if the problem is recording the data or displaying the data in grafana. My suspicion is the data is good, Grafana is not displaying in correctly.

The "Drive Details" dashboard the formula is:

(NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) * car.efficiency)

Not sure I entirely understand what is going on here, but I suspect that is the problem.

brianmay avatar Feb 08 '24 05:02 brianmay

@swiffer or @oivindoh can you take a look into this, as we believe data is correct, but dashboard is not?

JakobLichterfeld avatar Feb 08 '24 07:02 JakobLichterfeld

Well, there's some logic I don't really know the reason for in the query in the drives panel that decides whether consumption/efficiency is returned:

   case when (start_position.battery_level != start_position.usable_battery_level OR end_position.battery_level != end_position.usable_battery_level) = true then true else false end  as reduced_range,
    duration_min > 1 AND distance > 1 AND ( 
      start_position.usable_battery_level IS NULL OR end_position.usable_battery_level IS NULL	OR
      (end_position.battery_level - end_position.usable_battery_level) = 0 
    ) as is_sufficiently_precise,

Then there's also the nullif(greatest()) construct. I'm thinking Adrian has gone out of his way to make this happen, so there must be some sort of reasoning behind it

oivindoh avatar Feb 11 '24 13:02 oivindoh

WITH data AS (
  SELECT
    round(extract(epoch FROM start_date)) * 1000 AS start_date_ts,
    round(extract(epoch FROM end_date)) * 1000 AS end_date_ts,
    car.id as car_id,
    CASE WHEN start_geofence.id IS NULL THEN CONCAT('new?lat=', start_position.latitude, '&lng=', start_position.longitude)
         WHEN start_geofence.id IS NOT NULL THEN CONCAT(start_geofence.id, '/edit')
    END as start_path,
    CASE WHEN end_geofence.id IS NULL THEN CONCAT('new?lat=', end_position.latitude, '&lng=', end_position.longitude)
         WHEN end_geofence.id IS NOT NULL THEN CONCAT(end_geofence.id, '/edit')
    END as end_path,
    TO_CHAR((duration_min * INTERVAL '1 minute'), 'HH24:MI') as duration_str,
    drives.id as drive_id,
    -- Columns
    start_date,
    COALESCE(start_geofence.name, CONCAT_WS(', ', COALESCE(start_address.name, nullif(CONCAT_WS(' ', start_address.road, start_address.house_number), '')), start_address.city)) AS start_address,
    COALESCE(end_geofence.name, CONCAT_WS(', ', COALESCE(end_address.name, nullif(CONCAT_WS(' ', end_address.road, end_address.house_number), '')), end_address.city)) AS end_address,
    duration_min,
    distance,
    start_position.usable_battery_level as start_usable_battery_level,
    start_position.battery_level as start_battery_level,
    end_position.usable_battery_level as end_usable_battery_level,
    end_position.battery_level as end_battery_level,
   case when (start_position.battery_level != start_position.usable_battery_level OR end_position.battery_level != end_position.usable_battery_level) = true then true else false end  as reduced_range,
    NULLIF(GREATEST(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km, 0), 0) as range_diff,
    car.efficiency as car_efficiency,
    outside_temp_avg,
    distance / NULLIF(duration_min, 0) * 60 AS avg_speed,
    power_max
  FROM drives
  LEFT JOIN addresses start_address ON start_address_id = start_address.id
  LEFT JOIN addresses end_address ON end_address_id = end_address.id
  LEFT JOIN positions start_position ON start_position_id = start_position.id
  LEFT JOIN positions end_position ON end_position_id = end_position.id
  LEFT JOIN geofences start_geofence ON start_geofence_id = start_geofence.id
  LEFT JOIN geofences end_geofence ON end_geofence_id = end_geofence.id
  LEFT JOIN cars car ON car.id = drives.car_id
  WHERE $__timeFilter(start_date) AND drives.car_id = $car_id AND convert_km(distance::numeric, '$length_unit') >= $min_dist AND convert_km(distance::numeric, '$length_unit') / NULLIF(duration_min, 0) * 60 >= $min_speed
  ORDER BY start_date DESC
)
SELECT
    start_date_ts,
    end_date_ts,
    car_id,
    start_path,
    end_path,
    duration_str,
    drive_id,
    -- Columns
    start_date,
    start_address,
    end_address,
    duration_min,
    convert_km(distance::numeric, '$length_unit') AS distance_$length_unit,
    start_battery_level as "% Start",
    end_battery_level as "% End",
    convert_celsius(outside_temp_avg, '$temp_unit') AS outside_temp_$temp_unit,
    convert_km(avg_speed::numeric, '$length_unit') AS speed_avg_$length_unit,
    power_max,
    reduced_range as has_reduced_range,
    range_diff * car_efficiency as "consumption_kWh",
    (range_diff * car_efficiency / distance * 1000) * CASE WHEN '$length_unit' = 'km' THEN 1
                                                                                                WHEN '$length_unit' = 'mi' THEN 1.60934
                                                                                           END
    AS consumption_kWh_$length_unit,
    (distance / range_diff) as efficiency
FROM data;

This would work for drives,

SELECT
	(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km) * car.efficiency
FROM
	drives d
JOIN cars car ON car.id = car_id
WHERE
	d.id = $drive_id;
select
	(start_[[preferred_range]]_range_km - end_[[preferred_range]]_range_km) * car.efficiency * 1000 /
	  convert_km(distance::numeric, '$length_unit') as "$length_unit"
from drives d
JOIN cars car ON car.id = car_id
where d.id = $drive_id;

These two for the two stat panels in drive details

oivindoh avatar Feb 11 '24 14:02 oivindoh

I guess the main reasoning is that this data is kind of rubbish for consumption comparison purposes. Fun numbers to watch, but not very useful.

oivindoh avatar Feb 11 '24 14:02 oivindoh

yepp, agree with @oivindoh - i don't see these values making sense / helping. we could adapt calculation if something else is useful

grafik

swiffer avatar Feb 11 '24 15:02 swiffer

what could be interesting would be factoring in altitude at start / end of drive and in general calculate efficiency not only by distance but also consider height gained / lossed while driving. that way drives hill up / down both could end up at 100% efficiency. but harder to calculate, don't really know if 100 meters down in altitude can be easily factored in.

swiffer avatar Feb 11 '24 15:02 swiffer

https://www.gizchina.com/2023/11/15/tesla-range-calculation/

swiffer avatar Feb 11 '24 16:02 swiffer