From c1fa763f31c128147a12e1b77ca868d98f06999a Mon Sep 17 00:00:00 2001 From: rleidner Date: Mon, 16 Mar 2026 23:19:22 +0100 Subject: [PATCH 1/9] add CarState.odometer (Km-Stand) --- packages/control/chargelog/chargelog.py | 2 ++ packages/control/chargepoint/chargepoint.py | 1 + packages/control/chargepoint/chargepoint_data.py | 2 ++ packages/control/ev/ev.py | 1 + .../measurement_logging/process_log.py | 1 + packages/helpermodules/setdata.py | 2 ++ packages/helpermodules/update_config.py | 12 +++++++++++- packages/modules/common/component_state.py | 7 ++++++- packages/modules/common/configurable_vehicle.py | 2 ++ packages/modules/common/store/_car.py | 1 + packages/modules/update_soc.py | 3 +++ packages/modules/vehicles/mqtt/soc.py | 3 ++- packages/modules/vehicles/ovms/api.py | 11 ++++++----- packages/modules/vehicles/ovms/soc.py | 4 ++-- packages/modules/vehicles/vwgroup/vwgroup.py | 6 +++++- packages/modules/vehicles/vwid/libvwid.py | 15 +++++++++++---- packages/modules/vehicles/vwid/soc.py | 4 ++-- web/settings/downloadChargeLog.php | 1 + 18 files changed, 61 insertions(+), 17 deletions(-) diff --git a/packages/control/chargelog/chargelog.py b/packages/control/chargelog/chargelog.py index 1bde8c85ea..bdb40e7ace 100644 --- a/packages/control/chargelog/chargelog.py +++ b/packages/control/chargelog/chargelog.py @@ -120,6 +120,7 @@ def collect_data(chargepoint): log_data.ev = get_value_or_default(lambda: chargepoint.data.set.charging_ev_data.num, 0) log_data.prio = get_value_or_default(lambda: chargepoint.data.control_parameter.prio, False) log_data.rfid = get_value_or_default(lambda: chargepoint.data.set.rfid) + log_data.odometer = get_value_or_default(lambda: charging_ev.data.get.odometer) log_data.imported_since_mode_switch = get_value_or_default( lambda: chargepoint.data.get.imported - log_data.imported_at_mode_switch, 0) log_data.exported_since_mode_switch = get_value_or_default( @@ -270,6 +271,7 @@ def _create_entry(chargepoint, charging_ev): "chargemode": get_value_or_default(lambda: log_data.chargemode_log_entry), "prio": get_value_or_default(lambda: log_data.prio), "rfid": get_value_or_default(lambda: log_data.rfid), + "odometer": get_value_or_default(lambda: log_data.odometer), "soc_at_start": get_value_or_default(lambda: log_data.soc_at_start), "soc_at_end": get_value_or_default(lambda: charging_ev.data.get.soc), "range_at_start": get_value_or_default(lambda: log_data.range_at_start), diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index ac94d529e5..4b53912047 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -778,6 +778,7 @@ def _pub_connected_vehicle(self, vehicle: Ev): self.data.get.connected_vehicle.soc.fault_state = vehicle.data.get.fault_state self.data.get.connected_vehicle.soc.fault_str = vehicle.data.get.fault_str self.data.get.connected_vehicle.soc.range = vehicle.data.get.range + self.data.get.connected_vehicle.soc.odometer = vehicle.data.get.odometer self.data.get.connected_vehicle.info = ConnectedInfo(id=vehicle.num, name=vehicle.data.name) if (self.data.set.charge_template.data.chargemode.selected == "time_charging" or diff --git a/packages/control/chargepoint/chargepoint_data.py b/packages/control/chargepoint/chargepoint_data.py index bc601a5247..c67467ec6b 100644 --- a/packages/control/chargepoint/chargepoint_data.py +++ b/packages/control/chargepoint/chargepoint_data.py @@ -21,6 +21,7 @@ class ConnectedSoc: range: float = 0 soc: int = 0 timestamp: Optional[str] = None + odometer: Optional[float] = None @dataclass @@ -96,6 +97,7 @@ class Log: soc_at_end: Optional[int] = None range_at_start: Optional[float] = None range_at_end: Optional[float] = None + odometer: Optional[float] = None def connected_vehicle_factory() -> ConnectedVehicle: diff --git a/packages/control/ev/ev.py b/packages/control/ev/ev.py index 47005c40b3..c548f5b25b 100644 --- a/packages/control/ev/ev.py +++ b/packages/control/ev/ev.py @@ -63,6 +63,7 @@ class Get: force_soc_update: bool = field(default=False, metadata={ "topic": "get/force_soc_update"}) range: Optional[float] = field(default=None, metadata={"topic": "get/range"}) + odometer: Optional[float] = field(default=None, metadata={"topic": "get/odometer"}) fault_state: int = field(default=0, metadata={"topic": "get/fault_state"}) fault_str: str = field(default=NO_ERROR, metadata={"topic": "get/fault_str"}) diff --git a/packages/helpermodules/measurement_logging/process_log.py b/packages/helpermodules/measurement_logging/process_log.py index 25ba9d314c..7b6a566529 100644 --- a/packages/helpermodules/measurement_logging/process_log.py +++ b/packages/helpermodules/measurement_logging/process_log.py @@ -34,6 +34,7 @@ def get_default_charge_log_columns() -> Dict: "vehicle_chargemode": True, "vehicle_prio": True, "vehicle_rfid": True, + "vehicle_odometer": True, "vehicle_soc_at_start": False, "vehicle_soc_at_end": False, "chargepoint_name": True, diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index d54eb93c38..455a8e4ad7 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -393,6 +393,8 @@ def process_vehicle_topic(self, msg: mqtt.MQTTMessage): self._validate_value(msg, float, [(0, 100)]) elif "/get/range" in msg.topic: self._validate_value(msg, float, [(0, 1000)]) + elif "/get/odometer" in msg.topic: + self._validate_value(msg, float, [(0, 9999999)]) elif "/get/force_soc_update" in msg.topic: self._validate_value(msg, bool) else: diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 879065bedf..a93cf38679 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -57,7 +57,7 @@ class UpdateConfig: - DATASTORE_VERSION = 112 + DATASTORE_VERSION = 113 valid_topic = [ "^openWB/bat/config/bat_control_permitted$", @@ -2858,3 +2858,13 @@ def upgrade(topic: str, payload) -> Optional[dict]: run_command(['pip', 'uninstall', 'bimmer_connected', '-y'], process_exception=True) self._loop_all_received_topics(upgrade) self._append_datastore_version(112) + + def upgrade_datastore_113(self) -> None: + def upgrade(topic: str, payload) -> None: + if "openWB/general/charge_log_data_config" == topic: + config = decode_payload(payload) + if config.get("vehicle_odometer") is None: + config["vehicle_odometer"] = False + return {topic: config} + self._loop_all_received_topics(upgrade) + self._append_datastore_version(113) diff --git a/packages/modules/common/component_state.py b/packages/modules/common/component_state.py index d483111ed8..be27fda208 100644 --- a/packages/modules/common/component_state.py +++ b/packages/modules/common/component_state.py @@ -155,11 +155,15 @@ def __init__( @auto_str class CarState: - def __init__(self, soc: float, range: Optional[float] = None, soc_timestamp: Optional[float] = None): + def __init__(self, soc: float, + range: Optional[float] = None, + soc_timestamp: Optional[float] = None, + odometer: Optional[float] = None): """Args: soc: actual state of charge in percent range: actual range in km soc_timestamp: timestamp of last request as unix timestamp + odometer: actual odometer of vehicle in km """ self.soc = soc self.range = range @@ -170,6 +174,7 @@ def __init__(self, soc: float, range: Optional[float] = None, soc_timestamp: Opt log.debug(f'Zeitstempel {soc_timestamp} ist in ms, wird in s gewandelt. Modul sollte angepasst werden.') soc_timestamp /= 1000 self.soc_timestamp = soc_timestamp + self.odometer = odometer @auto_str diff --git a/packages/modules/common/configurable_vehicle.py b/packages/modules/common/configurable_vehicle.py index 9ff600c015..3f22877b50 100644 --- a/packages/modules/common/configurable_vehicle.py +++ b/packages/modules/common/configurable_vehicle.py @@ -129,6 +129,7 @@ def _get_carstate_by_source(self, vehicle_update_data: VehicleUpdateData, source if source == SocSource.API: try: _carState = self.__component_updater(vehicle_update_data) + _odometer = _carState.odometer _now = int(time.time()) _diff = 0 if _carState.soc_timestamp: @@ -146,6 +147,7 @@ def _get_carstate_by_source(self, vehicle_update_data: VehicleUpdateData, source _carState = calc_vehicle_data.calc_vehicle_data(vehicle_update_data, self.calculated_soc_state.last_imported or vehicle_update_data.imported) + _carState.odometer = _odometer except Exception as e: if vehicle_update_data.plug_state and\ vehicle_update_data.last_soc and\ diff --git a/packages/modules/common/store/_car.py b/packages/modules/common/store/_car.py index 37c7d64a30..499e052323 100644 --- a/packages/modules/common/store/_car.py +++ b/packages/modules/common/store/_car.py @@ -25,6 +25,7 @@ def update(self): pub_to_broker("openWB/set/vehicle/"+str(self.vehicle_id)+"/get/soc", self.state.soc, 2) pub_to_broker("openWB/set/vehicle/"+str(self.vehicle_id)+"/get/range", self.state.range, 2) pub_to_broker("openWB/set/vehicle/"+str(self.vehicle_id)+"/get/soc_timestamp", self.state.soc_timestamp) + pub_to_broker("openWB/set/vehicle/"+str(self.vehicle_id)+"/get/odometer", self.state.odometer, 2) def get_car_value_store(id: int) -> ValueStore[CarState]: diff --git a/packages/modules/update_soc.py b/packages/modules/update_soc.py index 10221c6517..10c5c31cfb 100644 --- a/packages/modules/update_soc.py +++ b/packages/modules/update_soc.py @@ -63,6 +63,7 @@ def _get_threads(self) -> Tuple[List[Thread], List[Thread]]: f"EV{ev.num}: Nach dreimaliger erfolgloser SoC-Abfrage wird ein SoC von 0% angenommen.") Pub().pub(f"openWB/set/vehicle/{ev.num}/get/soc", 0) Pub().pub(f"openWB/set/vehicle/{ev.num}/get/range", None) + Pub().pub(f"openWB/set/vehicle/{ev.num}/get/odometer", None) # Es wird ein Zeitstempel gesetzt, unabhängig ob die Abfrage erfolgreich war, da einige # Hersteller bei zu häufigen Abfragen Accounts sperren. Pub().pub(f"openWB/set/vehicle/{ev.num}/get/soc_request_timestamp", @@ -86,6 +87,8 @@ def _get_threads(self) -> Tuple[List[Thread], List[Thread]]: Pub().pub(f"openWB/set/vehicle/{ev.num}/get/soc_request_timestamp", None) if ev.data.get.range is not None: Pub().pub(f"openWB/set/vehicle/{ev.num}/get/range", None) + if ev.data.get.odometer is not None: + Pub().pub(f"openWB/set/vehicle/{ev.num}/get/odometer", None) except Exception: log.exception("Fehler im update_soc-Modul") return threads_update, threads_store diff --git a/packages/modules/vehicles/mqtt/soc.py b/packages/modules/vehicles/mqtt/soc.py index b5b49524e6..fbfd56bb96 100644 --- a/packages/modules/vehicles/mqtt/soc.py +++ b/packages/modules/vehicles/mqtt/soc.py @@ -29,7 +29,8 @@ def on_message(client, userdata, message): topic_prefix = f"openWB/mqtt/vehicle/{vehicle}/get/" return CarState(soc=received_topics.get(f"{topic_prefix}soc"), range=received_topics.get(f"{topic_prefix}range"), - soc_timestamp=received_topics.get(f"{topic_prefix}soc_timestamp")) + soc_timestamp=received_topics.get(f"{topic_prefix}soc_timestamp"), + odometer=received_topics.get(f"{topic_prefix}odometer")) else: configurable_vehicle.fault_state.warning( f"Keine MQTT-Daten für Fahrzeug {vehicle_config.name} empfangen oder es werden " diff --git a/packages/modules/vehicles/ovms/api.py b/packages/modules/vehicles/ovms/api.py index 2e0b7e0caa..cdd530d5c0 100755 --- a/packages/modules/vehicles/ovms/api.py +++ b/packages/modules/vehicles/ovms/api.py @@ -187,17 +187,18 @@ async def _fetch_soc(self, if float(self.range) > 1000.0: self.range = str(float(self.range) / 10) - self.kms = float(statusDict['odometer']) / 10 + self.odometer = float(statusDict['odometer']) / 10 self.vehicle12v = statusDict['vehicle12v'] self.soc_ts = statusDict['m_msgtime_s'] self.soc_tsdt = datetime.strptime(self.soc_ts, date_fmt) self.soc_tsdtL = utc2local(self.soc_tsdt) self.soc_tsX = datetime.timestamp(self.soc_tsdtL) - log.info("soc=" + self.soc + ", range=" + self.range + ", soc_ts=" + str(self.soc_tsdtL)) + log.info("OVMS: soc=" + self.soc + ", range=" + self.range + ", soc_ts=" + str(self.soc_tsdtL) + + ", odometer=" + str(self.odometer)) log.debug("statusDict=\n" + dumps(statusDict, indent=4)) - return int(float(self.soc)), float(self.range), self.soc_tsX + return int(float(self.soc)), float(self.range), self.soc_tsX, float(self.odometer) # sync function @@ -209,6 +210,6 @@ def fetch_soc(conf: OVMS, vehicle: int) -> Union[int, float, str]: # get soc, range from server a = api() - soc, range, soc_ts = loop.run_until_complete(a._fetch_soc(conf, vehicle)) + soc, range, soc_ts, odometer = loop.run_until_complete(a._fetch_soc(conf, vehicle)) - return soc, range, soc_ts + return soc, range, soc_ts, odometer diff --git a/packages/modules/vehicles/ovms/soc.py b/packages/modules/vehicles/ovms/soc.py index efd95708b3..2c2e8fa058 100755 --- a/packages/modules/vehicles/ovms/soc.py +++ b/packages/modules/vehicles/ovms/soc.py @@ -15,8 +15,8 @@ def fetch(vehicle_update_data: VehicleUpdateData, config: OVMS, vehicle: int) -> CarState: - soc, range, soc_ts = api.fetch_soc(config, vehicle) - return CarState(soc=soc, range=range, soc_timestamp=soc_ts) + soc, range, soc_ts, odometer = api.fetch_soc(config, vehicle) + return CarState(soc=soc, range=range, soc_timestamp=soc_ts, odometer=odometer) def create_vehicle(vehicle_config: OVMS, vehicle: int): diff --git a/packages/modules/vehicles/vwgroup/vwgroup.py b/packages/modules/vehicles/vwgroup/vwgroup.py index 758cb8e0e8..35a92d0d94 100644 --- a/packages/modules/vehicles/vwgroup/vwgroup.py +++ b/packages/modules/vehicles/vwgroup/vwgroup.py @@ -86,6 +86,10 @@ async def request_data(self, library) -> Union[int, float, str]: soc_tsdtL = self.utc2local(soc_tsdtZ) self.soc_tsX = datetime.timestamp(soc_tsdtL) self.soc_ts = datetime.strftime(soc_tsdtL, ts_fmt) + if self.su.keys_exist(self.data, 'charging', 'batteryStatus', 'value', 'odometer'): + self.odometer = float(self.data['charging']['batteryStatus']['value']['odometer']) + else: + self.odometer = None except Exception as e: raise Exception("soc/range/soc_ts field missing exception: e=" + str(e)) @@ -131,4 +135,4 @@ async def request_data(self, library) -> Union[int, float, str]: if (library.tokens['accessToken'] != self.accessTokenOld): # modified accessToken? self.su.write_token_file(self.accessTokenFile, library.tokens['accessToken']) - return self.soc, self.range, self.soc_ts, self.soc_tsX + return self.soc, self.range, self.soc_ts, self.soc_tsX, self.odometer diff --git a/packages/modules/vehicles/vwid/libvwid.py b/packages/modules/vehicles/vwid/libvwid.py index 0209d1b761..2018906f56 100755 --- a/packages/modules/vehicles/vwid/libvwid.py +++ b/packages/modules/vehicles/vwid/libvwid.py @@ -62,6 +62,7 @@ class Services: CHARGING = "charging" PARAMETERS = "parameters" SERVICE_STATUS = "service_status" + MEASUREMENTS = "measurements" def find_path_in_dict(src, path) -> object: @@ -310,6 +311,7 @@ async def update(self): self.get_selectivestatus( [ Services.CHARGING, + Services.MEASUREMENTS, ] ) ) @@ -419,7 +421,7 @@ async def expired(self, service): expiration = datetime.now(UTC) + timedelta(days=1) expiration = expiration.replace(tzinfo=None) if now >= expiration: - _LOGGER.warning("Access to %s has expired!", service) + _LOGGER.info("Access to %s has expired!", service) self._discovered = False return True except Exception: @@ -1425,12 +1427,13 @@ async def get_status(self): data['charging']['batteryStatus']['value']['currentSOC_pct'] = str(0) data['charging']['batteryStatus']['value']['cruisingRangeElectric_km'] = str(0) data['charging']['batteryStatus']['value']['carCapturedTimestamp'] = _now + data['charging']['batteryStatus']['value']['odometer'] = None _k = str(vwid.connection.keys()) - _LOGGER.info(f"libvwid.get_status connections at entry: vwid.connections.keys={_k}") + _LOGGER.debug(f"libvwid.get_status connections at entry: vwid.connections.keys={_k}") _update_result = False if self.username not in vwid.connection: - _LOGGER.info(f"create new connection, key={self.username}") + _LOGGER.debug(f"create new connection, key={self.username}") vwid.connection[self.username] = Connection(session, self.username, self.password) self._connection = vwid.connection[self.username] vwid.connection[self.username]._session_tokens['identity'] = {} @@ -1440,7 +1443,7 @@ async def get_status(self): vwid.connection[self.username]._session_tokens['Legacy'][token] = self.tokens[token] _conn_reuse = False else: - _LOGGER.info(f"reuse existing connection, key={self.username}") + _LOGGER.debug(f"reuse existing connection, key={self.username}") vwid.connection[self.username]._session = session _conn_reuse = True if not _conn_reuse: @@ -1472,6 +1475,7 @@ async def get_status(self): range =\ vehicle._states['charging']['batteryStatus']['value']['cruisingRangeElectric_km'] ts = vehicle._states['charging']['batteryStatus']['value']['carCapturedTimestamp'] + odometer = vehicle._states['measurements']['odometerStatus']['value']['odometer'] _LOGGER.debug("vehicle =" + str(vehicle)) _LOGGER.debug("soc =" + str(soc)) _LOGGER.debug("range =" + str(range)) @@ -1481,10 +1485,13 @@ async def get_status(self): data['charging']['batteryStatus']['value']['currentSOC_pct'] = str(soc) data['charging']['batteryStatus']['value']['cruisingRangeElectric_km'] = str(range) data['charging']['batteryStatus']['value']['carCapturedTimestamp'] = str(tsxx) + data['charging']['batteryStatus']['value']['odometer'] = str(odometer) _LOGGER.debug("return data =" + to_json(data, indent=4)) for token in vwid.connection[self.username]._session_tokens['identity']: self.tokens[token] =\ vwid.connection[self.username]._session_tokens['identity'][token] + _LOGGER.info("VWID: soc=" + str(soc)+", range=" + str(range) + "@" + str(tsxx) + + ', odometer=' + str(odometer)) return data else: _LOGGER.error(f"SOCERR-02: Fahrzeug mit VIN {self.vin} nicht gefunden") diff --git a/packages/modules/vehicles/vwid/soc.py b/packages/modules/vehicles/vwid/soc.py index 57e31d4c2f..8fdb236392 100755 --- a/packages/modules/vehicles/vwid/soc.py +++ b/packages/modules/vehicles/vwid/soc.py @@ -25,8 +25,8 @@ async def _fetch_soc() -> Union[int, float, str]: loop = new_event_loop() set_event_loop(loop) - soc, range, soc_ts, soc_tsX = loop.run_until_complete(_fetch_soc()) - return CarState(soc=soc, range=range, soc_timestamp=soc_tsX) + soc, range, soc_ts, soc_tsX, odometer = loop.run_until_complete(_fetch_soc()) + return CarState(soc=soc, range=range, soc_timestamp=soc_tsX, odometer=odometer) vw_group = VwGroup(vehicle_config, vehicle) diff --git a/web/settings/downloadChargeLog.php b/web/settings/downloadChargeLog.php index 4f20635058..4ebe1e5266 100644 --- a/web/settings/downloadChargeLog.php +++ b/web/settings/downloadChargeLog.php @@ -17,6 +17,7 @@ "vehicle chargemode" => ["header" => "Lademodus", "type" => "chargemode"], "vehicle prio" => ["header" => "Priorität", "type" => "bool"], "vehicle rfid" => ["header" => "ID-Tag", "type" => "string"], + "vehicle odometer" => ["header" => "Km-Stand", "type" => "int"], "vehicle soc_at_start" => ["header" => "SoC Beginn", "type" => "int"], "vehicle soc_at_end" => ["header" => "SoC Ende", "type" => "int"], "vehicle range_at_start" => ["header" => "Reichweite Beginn", "type" => "range"], From 8d1b03a8adf53c32511a4954e051490b0560a5e3 Mon Sep 17 00:00:00 2001 From: rleidner Date: Wed, 18 Mar 2026 09:33:15 +0100 Subject: [PATCH 2/9] automatic calculation when timestamp old: use charge_state instead of plug_state --- packages/modules/common/configurable_vehicle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/common/configurable_vehicle.py b/packages/modules/common/configurable_vehicle.py index 3f22877b50..2bcdf37d10 100644 --- a/packages/modules/common/configurable_vehicle.py +++ b/packages/modules/common/configurable_vehicle.py @@ -135,7 +135,7 @@ def _get_carstate_by_source(self, vehicle_update_data: VehicleUpdateData, source if _carState.soc_timestamp: _diff = int(_now - _carState.soc_timestamp) if _diff > self.general_config.request_interval_charging and\ - vehicle_update_data.plug_state and\ + vehicle_update_data.charge_state and\ vehicle_update_data.last_soc and\ vehicle_update_data.last_soc_timestamp >= vehicle_update_data.plug_time and\ (self.calculated_soc_state.last_imported or vehicle_update_data.imported): From 6777fd8d80a47d0f89c65b909e8a30b4945558ba Mon Sep 17 00:00:00 2001 From: rleidner <89418596+rleidner@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:17:58 +0100 Subject: [PATCH 3/9] Update packages/control/chargepoint/chargepoint_data.py Co-authored-by: LKuemmel <76958050+LKuemmel@users.noreply.github.com> --- packages/control/chargepoint/chargepoint_data.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/control/chargepoint/chargepoint_data.py b/packages/control/chargepoint/chargepoint_data.py index c67467ec6b..63e10f4ad2 100644 --- a/packages/control/chargepoint/chargepoint_data.py +++ b/packages/control/chargepoint/chargepoint_data.py @@ -21,7 +21,6 @@ class ConnectedSoc: range: float = 0 soc: int = 0 timestamp: Optional[str] = None - odometer: Optional[float] = None @dataclass From dd908ef45ecd8209e4abea4c42bbdc92bcb4f5f7 Mon Sep 17 00:00:00 2001 From: rleidner <89418596+rleidner@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:18:11 +0100 Subject: [PATCH 4/9] Update packages/control/chargepoint/chargepoint.py Co-authored-by: LKuemmel <76958050+LKuemmel@users.noreply.github.com> --- packages/control/chargepoint/chargepoint.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index 4b53912047..ac94d529e5 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -778,7 +778,6 @@ def _pub_connected_vehicle(self, vehicle: Ev): self.data.get.connected_vehicle.soc.fault_state = vehicle.data.get.fault_state self.data.get.connected_vehicle.soc.fault_str = vehicle.data.get.fault_str self.data.get.connected_vehicle.soc.range = vehicle.data.get.range - self.data.get.connected_vehicle.soc.odometer = vehicle.data.get.odometer self.data.get.connected_vehicle.info = ConnectedInfo(id=vehicle.num, name=vehicle.data.name) if (self.data.set.charge_template.data.chargemode.selected == "time_charging" or From 46e191a8b30dc6ad885a261591e1a7b987cc9ac2 Mon Sep 17 00:00:00 2001 From: rleidner <89418596+rleidner@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:18:32 +0100 Subject: [PATCH 5/9] Update packages/helpermodules/measurement_logging/process_log.py Co-authored-by: LKuemmel <76958050+LKuemmel@users.noreply.github.com> --- packages/helpermodules/measurement_logging/process_log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/helpermodules/measurement_logging/process_log.py b/packages/helpermodules/measurement_logging/process_log.py index 7b6a566529..d54c4da024 100644 --- a/packages/helpermodules/measurement_logging/process_log.py +++ b/packages/helpermodules/measurement_logging/process_log.py @@ -34,7 +34,7 @@ def get_default_charge_log_columns() -> Dict: "vehicle_chargemode": True, "vehicle_prio": True, "vehicle_rfid": True, - "vehicle_odometer": True, + "vehicle_odometer": False, "vehicle_soc_at_start": False, "vehicle_soc_at_end": False, "chargepoint_name": True, From 5b6239bb44bdaf770ad81410fd50ee3e2f70e517 Mon Sep 17 00:00:00 2001 From: rleidner <89418596+rleidner@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:18:58 +0100 Subject: [PATCH 6/9] Update web/settings/downloadChargeLog.php Co-authored-by: LKuemmel <76958050+LKuemmel@users.noreply.github.com> --- web/settings/downloadChargeLog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/settings/downloadChargeLog.php b/web/settings/downloadChargeLog.php index 4ebe1e5266..2cb85199bd 100644 --- a/web/settings/downloadChargeLog.php +++ b/web/settings/downloadChargeLog.php @@ -17,7 +17,7 @@ "vehicle chargemode" => ["header" => "Lademodus", "type" => "chargemode"], "vehicle prio" => ["header" => "Priorität", "type" => "bool"], "vehicle rfid" => ["header" => "ID-Tag", "type" => "string"], - "vehicle odometer" => ["header" => "Km-Stand", "type" => "int"], + "vehicle odometer" => ["header" => "Kilometerstand", "type" => "int"], "vehicle soc_at_start" => ["header" => "SoC Beginn", "type" => "int"], "vehicle soc_at_end" => ["header" => "SoC Ende", "type" => "int"], "vehicle range_at_start" => ["header" => "Reichweite Beginn", "type" => "range"], From cb4ba1918a506a1d1d285d0d5deb605bb681d03e Mon Sep 17 00:00:00 2001 From: rleidner Date: Fri, 20 Mar 2026 15:29:38 +0100 Subject: [PATCH 7/9] automatic calc when timestamp too old: compare imported counter --- packages/modules/common/configurable_vehicle.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/modules/common/configurable_vehicle.py b/packages/modules/common/configurable_vehicle.py index 2bcdf37d10..80aa5645fe 100644 --- a/packages/modules/common/configurable_vehicle.py +++ b/packages/modules/common/configurable_vehicle.py @@ -135,9 +135,10 @@ def _get_carstate_by_source(self, vehicle_update_data: VehicleUpdateData, source if _carState.soc_timestamp: _diff = int(_now - _carState.soc_timestamp) if _diff > self.general_config.request_interval_charging and\ - vehicle_update_data.charge_state and\ + vehicle_update_data.plug_state and\ vehicle_update_data.last_soc and\ vehicle_update_data.last_soc_timestamp >= vehicle_update_data.plug_time and\ + vehicle_update_data.imported - self.calculated_soc_state.last_imported > 0 and\ (self.calculated_soc_state.last_imported or vehicle_update_data.imported): _age = int(self.general_config.request_interval_charging / 60) _txt1 = "Ladestand und Reichweite sind berechnet, da der von der Online-Abfrage " From 51c71423b2a7cc61d6b8bbc0a08ef6eb7ad0d383 Mon Sep 17 00:00:00 2001 From: rleidner Date: Mon, 23 Mar 2026 09:41:31 +0100 Subject: [PATCH 8/9] fix calculation --- packages/modules/common/configurable_vehicle.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/modules/common/configurable_vehicle.py b/packages/modules/common/configurable_vehicle.py index 80aa5645fe..34f70b43df 100644 --- a/packages/modules/common/configurable_vehicle.py +++ b/packages/modules/common/configurable_vehicle.py @@ -138,7 +138,8 @@ def _get_carstate_by_source(self, vehicle_update_data: VehicleUpdateData, source vehicle_update_data.plug_state and\ vehicle_update_data.last_soc and\ vehicle_update_data.last_soc_timestamp >= vehicle_update_data.plug_time and\ - vehicle_update_data.imported - self.calculated_soc_state.last_imported > 0 and\ + vehicle_update_data.imported -\ + (self.calculated_soc_state.last_imported or vehicle_update_data.imported) > 0 and\ (self.calculated_soc_state.last_imported or vehicle_update_data.imported): _age = int(self.general_config.request_interval_charging / 60) _txt1 = "Ladestand und Reichweite sind berechnet, da der von der Online-Abfrage " From 7df8ac67bc475572a8ab587a793ff3322d5dc3bf Mon Sep 17 00:00:00 2001 From: rleidner Date: Mon, 23 Mar 2026 09:50:42 +0100 Subject: [PATCH 9/9] remove redundant condition --- packages/modules/common/configurable_vehicle.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/modules/common/configurable_vehicle.py b/packages/modules/common/configurable_vehicle.py index 34f70b43df..1456f9cb36 100644 --- a/packages/modules/common/configurable_vehicle.py +++ b/packages/modules/common/configurable_vehicle.py @@ -139,8 +139,7 @@ def _get_carstate_by_source(self, vehicle_update_data: VehicleUpdateData, source vehicle_update_data.last_soc and\ vehicle_update_data.last_soc_timestamp >= vehicle_update_data.plug_time and\ vehicle_update_data.imported -\ - (self.calculated_soc_state.last_imported or vehicle_update_data.imported) > 0 and\ - (self.calculated_soc_state.last_imported or vehicle_update_data.imported): + (self.calculated_soc_state.last_imported or vehicle_update_data.imported) > 0: _age = int(self.general_config.request_interval_charging / 60) _txt1 = "Ladestand und Reichweite sind berechnet, da der von der Online-Abfrage " _txt1 = _txt1 + f"gelieferte Zeitstempel mehr als {_age} min alt ist."