Skip to content

Commit 2159bf7

Browse files
authored
Merge pull request #46 from jhansche/pr/reset-energy
Reset energy-added when a new charge session is detected
2 parents 9a95f57 + a2edf57 commit 2159bf7

File tree

4 files changed

+69
-6
lines changed

4 files changed

+69
-6
lines changed

custom_components/teslafi/const.py

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
DELAY_LOCKS = timedelta(seconds=15)
2121
DELAY_WAKEUP = timedelta(seconds=30)
2222

23+
TESLAFI_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
24+
2325
ATTRIBUTION = "Data provided by Tesla and TeslaFi"
2426

2527
SHIFTER_STATES = {

custom_components/teslafi/coordinator.py

+32-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""TeslaFi data update coordinator"""
22

3-
from datetime import timedelta
4-
from typing_extensions import override
3+
from datetime import datetime, timedelta
4+
from typing import override
5+
56
from homeassistant.core import HomeAssistant, callback
67
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
78

@@ -23,7 +24,8 @@ class TeslaFiCoordinator(DataUpdateCoordinator[TeslaFiVehicle]):
2324
_vehicle: TeslaFiVehicle
2425
data: TeslaFiVehicle
2526

26-
_override_next_refresh: timedelta = None
27+
_last_charge_reset: datetime | None = None
28+
_override_next_refresh: timedelta | None = None
2729

2830
def __init__(
2931
self,
@@ -33,6 +35,7 @@ def __init__(
3335
self._client = client
3436
self.data = None
3537
self._vehicle = TeslaFiVehicle({})
38+
self._last_charge_reset = None
3639
# TODO: implement custom Debouncer to ensure no more than 2x per min,
3740
# as per API rate limit?
3841
super().__init__(
@@ -55,6 +58,11 @@ def schedule_refresh_in(self, delta: timedelta):
5558
self._override_next_refresh = delta
5659
self._schedule_refresh()
5760

61+
@property
62+
def last_charge_reset(self) -> datetime | None:
63+
"""Last charge reset time."""
64+
return self._last_charge_reset
65+
5866
@override
5967
@callback
6068
def _schedule_refresh(self) -> None:
@@ -78,9 +86,11 @@ async def _refresh(self) -> TeslaFiVehicle:
7886
"""Refresh"""
7987
current = await self._client.last_good()
8088
LOGGER.debug("Last good: %s", current)
89+
90+
self._infer_charge_session(prev=self.data, current=current)
91+
8192
self._vehicle.update_non_empty(current)
82-
last_remote_update = self._vehicle.get("Date")
83-
LOGGER.debug("Remote data last updated %s", last_remote_update)
93+
LOGGER.debug("Remote data last updated %s", self._vehicle.last_remote_update)
8494

8595
assert current.vin
8696
assert self._vehicle.vin
@@ -101,3 +111,20 @@ async def _refresh(self) -> TeslaFiVehicle:
101111
self._override_next_refresh = None
102112

103113
return self._vehicle
114+
115+
def _infer_charge_session(
116+
self,
117+
prev: TeslaFiVehicle,
118+
current: TeslaFiVehicle,
119+
):
120+
if prev and current and (prev != current):
121+
if not prev.is_plugged_in and current.is_plugged_in:
122+
LOGGER.info("Vehicle is newly plugged in: resetting charge session")
123+
self._last_charge_reset = current.last_remote_update
124+
elif current.charge_session_number and (
125+
prev.charge_session_number != current.charge_session_number
126+
):
127+
LOGGER.info(
128+
f"New charge session detected: {prev.charge_session_number} -> {current.charge_session_number}"
129+
)
130+
self._last_charge_reset = current.last_remote_update

custom_components/teslafi/model.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
from collections import UserDict
44
from dataclasses import dataclass
5+
from datetime import datetime
6+
import logging
57

68
from typing_extensions import deprecated
79

810
from homeassistant.const import UnitOfPressure
911

10-
from .const import SHIFTER_STATES, VIN_YEARS
12+
from .const import SHIFTER_STATES, TESLAFI_DATE_FORMAT, VIN_YEARS
1113
from .util import (
1214
_convert_to_bool,
1315
_int_or_none,
@@ -18,6 +20,8 @@
1820

1921
NAN: float = float("NaN")
2022

23+
LOGGER = logging.getLogger(__package__)
24+
2125
CHARGER_CONNECTED_STATES = [
2226
"charging",
2327
"complete",
@@ -92,6 +96,19 @@ def name(self) -> str:
9296
or f"{self.model_year} {self.car_type} {self.vin[-4:]}"
9397
)
9498

99+
@property
100+
def last_remote_update(self) -> datetime | None:
101+
"""Last remote update."""
102+
try:
103+
return (
104+
datetime.strptime(s, TESLAFI_DATE_FORMAT)
105+
if (s := self.get("Date", None))
106+
else None
107+
)
108+
except ValueError:
109+
LOGGER.warning("Failed to parse TeslaFi date: %s", s)
110+
return None
111+
95112
@property
96113
def car_type(self) -> str | None:
97114
"""Car type (model). E.g. 'model3', etc."""
@@ -158,6 +175,11 @@ def charging_state(self) -> str | None:
158175
"""
159176
return _lower_or_none(self.get("charging_state", None))
160177

178+
@property
179+
def charge_session_number(self) -> int | None:
180+
"""The current charge session number."""
181+
return n if (n := _int_or_none(self.get("chargeNumber"))) != 0 else None
182+
161183
@property
162184
def is_plugged_in(self) -> bool | None:
163185
"""Whether the vehicle is plugged in."""

custom_components/teslafi/sensor.py

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Sensors"""
22

3+
from datetime import datetime
4+
from functools import cached_property
35
from typing import override
46

57
from homeassistant.components.sensor import (
@@ -133,6 +135,7 @@
133135
device_class=SensorDeviceClass.ENERGY,
134136
entity_registry_visible_default=False,
135137
state_class=SensorStateClass.TOTAL,
138+
last_reset=None,
136139
available=lambda u, d, h: u and d.is_plugged_in,
137140
),
138141
TeslaFiSensorEntityDescription(
@@ -255,6 +258,15 @@ def _handle_coordinator_update(self) -> None:
255258
fixed := self.entity_description.fix_unit(self.coordinator.data, self.hass)
256259
):
257260
self._attr_native_unit_of_measurement = fixed
261+
262+
if self.entity_description.key == "charge_energy_added":
263+
if self.entity_description.state_class == SensorStateClass.TOTAL and (
264+
last_reset := self.coordinator.last_charge_reset
265+
):
266+
self._attr_last_reset = last_reset
267+
else:
268+
self._attr_last_reset = None
269+
258270
return super()._handle_coordinator_update()
259271

260272
@property

0 commit comments

Comments
 (0)