Skip to content

Conversation

@rleidner
Copy link
Collaborator

@rleidner rleidner commented Dec 2, 2025

With more that one EV using soc module vwid, parallel execution could fail.
Added a lock to implement mutual exclusion

@LKuemmel
Copy link
Contributor

LKuemmel commented Dec 2, 2025

parallel execution could fail.

Warum sind globale Variablen erforderlich? Wenn jede Instanz ihre eigenen Attribute hat, würde es nicht zu Race Conditions kommen.

@rleidner
Copy link
Collaborator Author

rleidner commented Dec 2, 2025

Für jedes Fahrzeug wird ein eigenes Set von Attributen (Token, etc) benötigt.
Diese stecken im Kontext der connection.
Ohne das Lock meldet die verwendete library bei parelleler Ausführung folgendes:

2025-12-02 09:14:55,872 - {modules.vehicles.vwid.libvwid:1480} - {ERROR:fetch soc_ev2} - get_status failed... got Future attached to a different loop

Als Folge wird der SoC dann auf 0 gesetzt, was für die Anwender unschön ist.

Auf die Schnelle kann ich die library nicht umarbeiten..
Deshalb der Ansatz mit dem Lock.
Im Test hat das bei mir diesen Fehler beseitigt.

@LKuemmel
Copy link
Contributor

LKuemmel commented Dec 3, 2025

Verschwindet die Fehlermeldung, wenn Du global connection zu self.connection machst?

Wenn alle Fahrzeuge nacheinander das gleiche globale connection-dict benutzen, stehen darin noch die Daten vom vorherigen Fahrzeug. Dann gibt es doch dort Überschneidungen. Oder ist das bewusst so, dass die Fahrzeuge sich die connection teilen sollen?

@rleidner
Copy link
Collaborator Author

rleidner commented Dec 3, 2025

Ich habe es jetzt aufgeräumt. Connections werden je username in dict self.connection verwaltet.
Das läuft im Test auch ohne den zusätzlichen lock sauber.
Ich hoffe das kann jetzt ge-merged werden - ab Freitag bin ich für einige Tage komplett offline.
Es wäre gut wenn das von Anwendern mit mehreren VWs im master getestet werden kann.

Comment on lines 31 to 37
global a
try:
if 'a' not in globals():
a = None
# prepare and call async method
loop = new_event_loop()
set_event_loop(loop)
Copy link
Contributor

Choose a reason for hiding this comment

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

Jetzt gibt es ja wieder eine globale Variable, nur an anderer Stelle.
Wie wäre es, wenn die soc.py so aussieht, ohne api.py?

import aiohttp
import logging
from asyncio import new_event_loop, set_event_loop
from typing import Union

from modules.common.abstract_device import DeviceDescriptor
from modules.common.abstract_vehicle import VehicleUpdateData
from modules.common.component_state import CarState
from modules.common.configurable_vehicle import ConfigurableVehicle
from modules.vehicles.vwid.config import VWId
from modules.vehicles.vwid import libvwid
from modules.vehicles.vwgroup.vwgroup import VwGroup

log = logging.getLogger(__name__)


def create_vehicle(vehicle_config: VWId, vehicle: int):
    def fetch() -> CarState:
        nonlocal vw_group

        # async method, called from sync fetch_soc, required because libvwid expect async environment
        async def _fetch_soc() -> Union[int, float, str]:
            async with aiohttp.ClientSession() as session:
                return await vw_group.request_data(libvwid.vwid(session))

        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)

    vw_group = VwGroup(vehicle_config, vehicle)

    def updater(vehicle_update_data: VehicleUpdateData) -> CarState:
        return fetch()
    return ConfigurableVehicle(vehicle_config=vehicle_config,
                               component_updater=updater,
                               vehicle=vehicle,
                               calc_while_charging=vehicle_config.configuration.calculate_soc)


device_descriptor = DeviceDescriptor(configuration_factory=VWId)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hallo Lena,
danke, jetzt hat sich meine letzte Änderung gerade mit deinem review überschnitten.
Ich möchte halt den Context der libvwid (connection, vehicle) im Speicher halten bis zum Restart um unnötige Logins zu vermeiden, da sonst der VW-Server u.U. komisch reagiert.
Wenn die Objekt-Instanzen bzw. Variablen darüber neu instanziiert werden, klappt das aber nicht.
Ich werde deinen Vorschlag testen.

@rleidner
Copy link
Collaborator Author

rleidner commented Dec 4, 2025

Ich habe soc.py geändert wie von Dir vorgeschlagen.
api.py ist raus.
in libvwid.py werden die connections jetzt in class variable connection gehalten.
Es gibt einige wenige logs level INFO um zu sehen, ob das in allen Szenarien funktioniert, also

  • 1 Account mit mehreren Fahrzeugen
  • mehrere Accounts mit ein oder mehreren Fahrzeugen

@LKuemmel LKuemmel merged commit 443b430 into openWB:master Dec 5, 2025
1 check passed
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