carconnectivity-plugin-database 0.1a16__py3-none-any.whl → 0.1a21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of carconnectivity-plugin-database might be problematic. Click here for more details.
- {carconnectivity_plugin_database-0.1a16.dist-info → carconnectivity_plugin_database-0.1a21.dist-info}/METADATA +1 -1
- {carconnectivity_plugin_database-0.1a16.dist-info → carconnectivity_plugin_database-0.1a21.dist-info}/RECORD +16 -16
- carconnectivity_plugins/database/_version.py +2 -2
- carconnectivity_plugins/database/agents/charging_agent.py +189 -88
- carconnectivity_plugins/database/agents/climatization_agent.py +13 -6
- carconnectivity_plugins/database/agents/drive_state_agent.py +148 -96
- carconnectivity_plugins/database/agents/state_agent.py +26 -14
- carconnectivity_plugins/database/agents/trip_agent.py +48 -37
- carconnectivity_plugins/database/model/charging_session.py +7 -7
- carconnectivity_plugins/database/model/drive.py +6 -6
- carconnectivity_plugins/database/model/vehicle.py +36 -34
- carconnectivity_plugins/database/plugin.py +8 -12
- {carconnectivity_plugin_database-0.1a16.dist-info → carconnectivity_plugin_database-0.1a21.dist-info}/WHEEL +0 -0
- {carconnectivity_plugin_database-0.1a16.dist-info → carconnectivity_plugin_database-0.1a21.dist-info}/entry_points.txt +0 -0
- {carconnectivity_plugin_database-0.1a16.dist-info → carconnectivity_plugin_database-0.1a21.dist-info}/licenses/LICENSE +0 -0
- {carconnectivity_plugin_database-0.1a16.dist-info → carconnectivity_plugin_database-0.1a21.dist-info}/top_level.txt +0 -0
|
@@ -22,6 +22,7 @@ if TYPE_CHECKING:
|
|
|
22
22
|
|
|
23
23
|
from carconnectivity.attributes import EnumAttribute, FloatAttribute
|
|
24
24
|
|
|
25
|
+
from carconnectivity_plugins.database.plugin import Plugin
|
|
25
26
|
from carconnectivity_plugins.database.model.vehicle import Vehicle
|
|
26
27
|
|
|
27
28
|
LOG: logging.Logger = logging.getLogger("carconnectivity.plugins.database.agents.trip_agent")
|
|
@@ -40,7 +41,7 @@ class TripAgent(BaseAgent):
|
|
|
40
41
|
of the vehicle to detect state transitions.
|
|
41
42
|
trip (Optional[Trip]): The currently active trip, if any.
|
|
42
43
|
Raises:
|
|
43
|
-
ValueError: If vehicle or
|
|
44
|
+
ValueError: If vehicle or self.carconnectivity_vehicle is None during initialization.
|
|
44
45
|
Notes:
|
|
45
46
|
- A new trip is started when the vehicle transitions to IGNITION_ON or DRIVING state.
|
|
46
47
|
- A trip is ended when the vehicle transitions from IGNITION_ON/DRIVING to another state.
|
|
@@ -49,11 +50,14 @@ class TripAgent(BaseAgent):
|
|
|
49
50
|
- Trip records include start/end dates and odometer readings when available.
|
|
50
51
|
"""
|
|
51
52
|
|
|
52
|
-
def __init__(self, session_factory: scoped_session[Session], vehicle: Vehicle) -> None:
|
|
53
|
-
if vehicle is None or
|
|
53
|
+
def __init__(self, database_plugin: Plugin, session_factory: scoped_session[Session], vehicle: Vehicle, carconnectivity_vehicle: GenericVehicle) -> None:
|
|
54
|
+
if vehicle is None or carconnectivity_vehicle is None:
|
|
54
55
|
raise ValueError("Vehicle or its carconnectivity_vehicle attribute is None")
|
|
56
|
+
self.database_plugin: Plugin = database_plugin
|
|
55
57
|
self.session_factory: scoped_session[Session] = session_factory
|
|
56
58
|
self.vehicle: Vehicle = vehicle
|
|
59
|
+
self.carconnectivity_vehicle: GenericVehicle = carconnectivity_vehicle
|
|
60
|
+
|
|
57
61
|
self.last_carconnectivity_state: Optional[GenericVehicle.State] = None
|
|
58
62
|
self.last_parked_position_latitude: Optional[float] = None
|
|
59
63
|
self.last_parked_position_longitude: Optional[float] = None
|
|
@@ -67,19 +71,19 @@ class TripAgent(BaseAgent):
|
|
|
67
71
|
LOG.info("Last trip for vehicle %s is still open during startup, closing it now", vehicle.vin)
|
|
68
72
|
self.session_factory.remove()
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
self.__on_state_change(
|
|
74
|
+
self.carconnectivity_vehicle.state.add_observer(self.__on_state_change, Observable.ObserverEvent.UPDATED)
|
|
75
|
+
self.__on_state_change(self.carconnectivity_vehicle.state, Observable.ObserverEvent.UPDATED)
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
self._on_position_latitude_change(
|
|
77
|
+
self.carconnectivity_vehicle.position.latitude.add_observer(self._on_position_latitude_change, Observable.ObserverEvent.UPDATED)
|
|
78
|
+
self._on_position_latitude_change(self.carconnectivity_vehicle.position.latitude, Observable.ObserverEvent.UPDATED)
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
self._on_position_longitude_change(
|
|
80
|
+
self.carconnectivity_vehicle.position.longitude.add_observer(self._on_position_longitude_change, Observable.ObserverEvent.UPDATED)
|
|
81
|
+
self._on_position_longitude_change(self.carconnectivity_vehicle.position.longitude, Observable.ObserverEvent.UPDATED)
|
|
78
82
|
|
|
79
83
|
def __on_state_change(self, element: EnumAttribute[GenericVehicle.State], flags: Observable.ObserverEvent) -> None:
|
|
80
84
|
del flags
|
|
81
85
|
if element.enabled:
|
|
82
|
-
if self.
|
|
86
|
+
if self.carconnectivity_vehicle is None:
|
|
83
87
|
raise ValueError("Vehicle's carconnectivity_vehicle attribute is None")
|
|
84
88
|
if element.enabled and element.value is not None:
|
|
85
89
|
if self.last_carconnectivity_state is not None:
|
|
@@ -97,9 +101,9 @@ class TripAgent(BaseAgent):
|
|
|
97
101
|
LOG.info("Starting new trip for vehicle %s", self.vehicle.vin)
|
|
98
102
|
start_date: datetime = element.last_updated if element.last_updated is not None else datetime.now(tz=timezone.utc)
|
|
99
103
|
new_trip: Trip = Trip(vin=self.vehicle.vin, start_date=start_date)
|
|
100
|
-
if self.
|
|
101
|
-
self.
|
|
102
|
-
new_trip.start_odometer = self.
|
|
104
|
+
if self.carconnectivity_vehicle.odometer.enabled and \
|
|
105
|
+
self.carconnectivity_vehicle.odometer.value is not None:
|
|
106
|
+
new_trip.start_odometer = self.carconnectivity_vehicle.odometer.value
|
|
103
107
|
if not self._update_trip_position(session=session, trip=new_trip, start=True):
|
|
104
108
|
# if now no position is available try the last known position that is not older than 5min
|
|
105
109
|
if self.last_parked_position_latitude is not None and self.last_parked_position_longitude is not None \
|
|
@@ -116,15 +120,16 @@ class TripAgent(BaseAgent):
|
|
|
116
120
|
except DatabaseError as err:
|
|
117
121
|
session.rollback()
|
|
118
122
|
LOG.error('DatabaseError while adding trip for vehicle %s to database: %s', self.vehicle.vin, err)
|
|
123
|
+
self.database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
119
124
|
elif self.last_carconnectivity_state in (GenericVehicle.State.IGNITION_ON, GenericVehicle.State.DRIVING) \
|
|
120
125
|
and element.value not in (GenericVehicle.State.IGNITION_ON, GenericVehicle.State.DRIVING):
|
|
121
126
|
if self.trip is not None and not self.trip.is_completed():
|
|
122
127
|
LOG.info("Ending trip for vehicle %s", self.vehicle.vin)
|
|
123
128
|
try:
|
|
124
129
|
self.trip.destination_date = element.last_updated if element.last_updated is not None else datetime.now(tz=timezone.utc)
|
|
125
|
-
if self.
|
|
126
|
-
self.
|
|
127
|
-
self.trip.destination_odometer = self.
|
|
130
|
+
if self.carconnectivity_vehicle.odometer.enabled and \
|
|
131
|
+
self.carconnectivity_vehicle.odometer.value is not None:
|
|
132
|
+
self.trip.destination_odometer = self.carconnectivity_vehicle.odometer.value
|
|
128
133
|
LOG.debug('Set destination odometer %.2f for trip of vehicle %s', self.trip.destination_odometer, self.vehicle.vin)
|
|
129
134
|
if self._update_trip_position(session=session, trip=self.trip, start=False):
|
|
130
135
|
self.trip = None
|
|
@@ -132,6 +137,7 @@ class TripAgent(BaseAgent):
|
|
|
132
137
|
except DatabaseError as err:
|
|
133
138
|
session.rollback()
|
|
134
139
|
LOG.error('DatabaseError while ending trip for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
140
|
+
self.database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
135
141
|
self.session_factory.remove()
|
|
136
142
|
self.last_carconnectivity_state = element.value
|
|
137
143
|
|
|
@@ -151,41 +157,43 @@ class TripAgent(BaseAgent):
|
|
|
151
157
|
|
|
152
158
|
def _on_position_change(self) -> None:
|
|
153
159
|
# Check if there is a finished trip that lacks destination position. We allow 5min after destination_date to set the position.
|
|
154
|
-
if self.trip is not None
|
|
155
|
-
and self.last_parked_position_time is not None \
|
|
156
|
-
and self.last_parked_position_time < (self.trip.destination_date + timedelta(minutes=5)):
|
|
160
|
+
if self.trip is not None:
|
|
157
161
|
with self.session_factory() as session:
|
|
158
162
|
with self.trip_lock:
|
|
159
163
|
self.trip = session.merge(self.trip)
|
|
160
164
|
session.refresh(self.trip)
|
|
161
|
-
self.
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
if self.trip.destination_date is not None and self.trip.destination_position_latitude is None \
|
|
166
|
+
and self.last_parked_position_time is not None \
|
|
167
|
+
and self.last_parked_position_time < (self.trip.destination_date + timedelta(minutes=5)):
|
|
168
|
+
self._update_trip_position(session, self.trip, start=False,
|
|
169
|
+
latitude=self.last_parked_position_latitude,
|
|
170
|
+
longitude=self.last_parked_position_longitude)
|
|
164
171
|
self.session_factory.remove()
|
|
165
172
|
|
|
166
173
|
def _update_trip_position(self, session: Session, trip: Trip, start: bool,
|
|
167
174
|
latitude: Optional[float] = None, longitude: Optional[float] = None) -> bool:
|
|
168
|
-
if self.
|
|
175
|
+
if self.carconnectivity_vehicle is None:
|
|
169
176
|
raise ValueError("Vehicle's carconnectivity_vehicle attribute is None")
|
|
170
177
|
if latitude or longitude is None:
|
|
171
|
-
if self.
|
|
172
|
-
and self.
|
|
173
|
-
and self.
|
|
174
|
-
and self.
|
|
175
|
-
latitude = self.
|
|
176
|
-
longitude = self.
|
|
178
|
+
if self.carconnectivity_vehicle.position.enabled and self.carconnectivity_vehicle.position.latitude.enabled \
|
|
179
|
+
and self.carconnectivity_vehicle.position.longitude.enabled \
|
|
180
|
+
and self.carconnectivity_vehicle.position.latitude.value is not None \
|
|
181
|
+
and self.carconnectivity_vehicle.position.longitude.value is not None:
|
|
182
|
+
latitude = self.carconnectivity_vehicle.position.latitude.value
|
|
183
|
+
longitude = self.carconnectivity_vehicle.position.longitude.value
|
|
177
184
|
if latitude is not None and longitude is not None:
|
|
178
185
|
if start:
|
|
179
186
|
if trip.start_position_latitude is None and trip.start_position_longitude is None:
|
|
180
187
|
try:
|
|
181
|
-
trip.start_position_latitude = self.
|
|
182
|
-
trip.start_position_longitude = self.
|
|
188
|
+
trip.start_position_latitude = self.carconnectivity_vehicle.position.latitude.value
|
|
189
|
+
trip.start_position_longitude = self.carconnectivity_vehicle.position.longitude.value
|
|
183
190
|
session.commit()
|
|
184
191
|
except DatabaseError as err:
|
|
185
192
|
session.rollback()
|
|
186
193
|
LOG.error('DatabaseError while updating position for trip of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
187
|
-
|
|
188
|
-
|
|
194
|
+
self.database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
195
|
+
if trip.start_location is None and self.carconnectivity_vehicle.position.location.enabled:
|
|
196
|
+
location: Location = Location.from_carconnectivity_location(location=self.carconnectivity_vehicle.position.location)
|
|
189
197
|
try:
|
|
190
198
|
location = session.merge(location)
|
|
191
199
|
trip.start_location = location
|
|
@@ -193,18 +201,20 @@ class TripAgent(BaseAgent):
|
|
|
193
201
|
except DatabaseError as err:
|
|
194
202
|
session.rollback()
|
|
195
203
|
LOG.error('DatabaseError while merging location for trip of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
204
|
+
self.database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
196
205
|
return True
|
|
197
206
|
else:
|
|
198
207
|
if trip.destination_position_latitude is None and trip.destination_position_longitude is None:
|
|
199
208
|
try:
|
|
200
|
-
trip.destination_position_latitude = self.
|
|
201
|
-
trip.destination_position_longitude = self.
|
|
209
|
+
trip.destination_position_latitude = self.carconnectivity_vehicle.position.latitude.value
|
|
210
|
+
trip.destination_position_longitude = self.carconnectivity_vehicle.position.longitude.value
|
|
202
211
|
session.commit()
|
|
203
212
|
except DatabaseError as err:
|
|
204
213
|
session.rollback()
|
|
205
214
|
LOG.error('DatabaseError while updating position for trip of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
206
|
-
|
|
207
|
-
|
|
215
|
+
self.database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
216
|
+
if trip.destination_location is None and self.carconnectivity_vehicle.position.location.enabled:
|
|
217
|
+
location: Location = Location.from_carconnectivity_location(location=self.carconnectivity_vehicle.position.location)
|
|
208
218
|
try:
|
|
209
219
|
location = session.merge(location)
|
|
210
220
|
trip.destination_location = location
|
|
@@ -212,5 +222,6 @@ class TripAgent(BaseAgent):
|
|
|
212
222
|
except DatabaseError as err:
|
|
213
223
|
session.rollback()
|
|
214
224
|
LOG.error('DatabaseError while merging location for trip of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
225
|
+
self.database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
215
226
|
return True
|
|
216
227
|
return False
|
|
@@ -77,13 +77,13 @@ class ChargingSession(Base): # pylint: disable=too-few-public-methods
|
|
|
77
77
|
location: Mapped[Optional["Location"]] = relationship("Location")
|
|
78
78
|
charging_station_uid: Mapped[Optional[str]] = mapped_column(ForeignKey("charging_stations.uid"))
|
|
79
79
|
charging_station: Mapped[Optional["ChargingStation"]] = relationship("ChargingStation")
|
|
80
|
-
meter_start_kwh
|
|
81
|
-
meter_end_kwh
|
|
82
|
-
price_per_kwh
|
|
83
|
-
price_per_min
|
|
84
|
-
price_per_session
|
|
85
|
-
real_charged
|
|
86
|
-
real_cost
|
|
80
|
+
meter_start_kwh: Mapped[Optional[float]]
|
|
81
|
+
meter_end_kwh: Mapped[Optional[float]]
|
|
82
|
+
price_per_kwh: Mapped[Optional[float]]
|
|
83
|
+
price_per_min: Mapped[Optional[float]]
|
|
84
|
+
price_per_session: Mapped[Optional[float]]
|
|
85
|
+
real_charged: Mapped[Optional[float]]
|
|
86
|
+
real_cost: Mapped[Optional[float]]
|
|
87
87
|
tags: Mapped[list["Tag"]] = relationship("Tag", secondary=charging_tag_association_table, backref=backref("charging_sessions"))
|
|
88
88
|
|
|
89
89
|
# pylint: disable-next=too-many-arguments, too-many-positional-arguments
|
|
@@ -18,6 +18,8 @@ if TYPE_CHECKING:
|
|
|
18
18
|
from sqlalchemy.orm.session import Session
|
|
19
19
|
from sqlalchemy import Constraint
|
|
20
20
|
|
|
21
|
+
from carconnectivity_plugins.database.plugin import Plugin
|
|
22
|
+
|
|
21
23
|
LOG: logging.Logger = logging.getLogger("carconnectivity.plugins.database.model.drive")
|
|
22
24
|
|
|
23
25
|
|
|
@@ -56,14 +58,13 @@ class Drive(Base):
|
|
|
56
58
|
capacity_total: Mapped[Optional[float]]
|
|
57
59
|
wltp_range: Mapped[Optional[float]]
|
|
58
60
|
|
|
59
|
-
carconnectivity_drive: Optional[GenericDrive] = None
|
|
60
61
|
agents: list[BaseAgent] = []
|
|
61
62
|
|
|
62
63
|
def __init__(self, vin, drive_id: Optional[str] = None) -> None:
|
|
63
64
|
self.vin = vin
|
|
64
65
|
self.drive_id = drive_id
|
|
65
66
|
|
|
66
|
-
def connect(self, session_factory: scoped_session[Session], carconnectivity_drive: GenericDrive) -> None:
|
|
67
|
+
def connect(self, database_plugin: Plugin, session_factory: scoped_session[Session], carconnectivity_drive: GenericDrive) -> None:
|
|
67
68
|
"""
|
|
68
69
|
Connect a CarConnectivity drive object to this database model instance.
|
|
69
70
|
This method establishes a connection between the database drive model and a CarConnectivity drive object,
|
|
@@ -78,9 +79,8 @@ class Drive(Base):
|
|
|
78
79
|
- Automatically syncs the drive type if enabled and has a value
|
|
79
80
|
- Creates and registers a DriveStateAgent for managing drive state
|
|
80
81
|
"""
|
|
81
|
-
if self.
|
|
82
|
+
if self.agents:
|
|
82
83
|
raise ValueError("Can only connect once! Drive already connected with database model")
|
|
83
|
-
self.carconnectivity_drive = carconnectivity_drive
|
|
84
|
-
drive_state_agent: DriveStateAgent = DriveStateAgent(session_factory, self) # type: ignore[assignment]
|
|
85
|
-
self.agents.append(drive_state_agent)
|
|
86
84
|
LOG.debug("Adding DriveStateAgent to drive %s of vehicle %s", self.drive_id, self.vin)
|
|
85
|
+
drive_state_agent: DriveStateAgent = DriveStateAgent(database_plugin, session_factory, self, carconnectivity_drive) # type: ignore[assignment]
|
|
86
|
+
self.agents.append(drive_state_agent)
|
|
@@ -23,6 +23,8 @@ if TYPE_CHECKING:
|
|
|
23
23
|
from sqlalchemy.orm import scoped_session
|
|
24
24
|
from sqlalchemy.orm.session import Session
|
|
25
25
|
|
|
26
|
+
from carconnectivity_plugins.database.plugin import Plugin
|
|
27
|
+
|
|
26
28
|
LOG: logging.Logger = logging.getLogger("carconnectivity.plugins.database.model.vehicle")
|
|
27
29
|
|
|
28
30
|
|
|
@@ -66,13 +68,12 @@ class Vehicle(Base):
|
|
|
66
68
|
type: Mapped[Optional[GenericVehicle.Type]]
|
|
67
69
|
license_plate: Mapped[Optional[str]]
|
|
68
70
|
|
|
69
|
-
carconnectivity_vehicle: Optional[GenericVehicle] = None
|
|
70
71
|
agents: list[BaseAgent] = []
|
|
71
72
|
|
|
72
73
|
def __init__(self, vin) -> None:
|
|
73
74
|
self.vin = vin
|
|
74
75
|
|
|
75
|
-
def connect(self, session_factory: scoped_session[Session], carconnectivity_vehicle: GenericVehicle) -> None:
|
|
76
|
+
def connect(self, database_plugin: Plugin, session_factory: scoped_session[Session], carconnectivity_vehicle: GenericVehicle) -> None:
|
|
76
77
|
"""
|
|
77
78
|
Connect a CarConnectivity vehicle instance to this database vehicle model and set up observers.
|
|
78
79
|
This method establishes a connection between a CarConnectivity vehicle object and this database vehicle model.
|
|
@@ -88,34 +89,33 @@ class Vehicle(Base):
|
|
|
88
89
|
- Only enabled attributes are synchronized
|
|
89
90
|
- The type attribute is only synchronized if it's not None
|
|
90
91
|
"""
|
|
91
|
-
if self.
|
|
92
|
+
if self.agents:
|
|
92
93
|
raise ValueError("Can only connect once! Vehicle already connected with database model")
|
|
93
|
-
self.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
self.license_plate = self.carconnectivity_vehicle.license_plate.value
|
|
94
|
+
carconnectivity_vehicle.name.add_observer(self.__on_name_change, Observable.ObserverEvent.VALUE_CHANGED, on_transaction_end=True)
|
|
95
|
+
if carconnectivity_vehicle.name.enabled and self.name != carconnectivity_vehicle.name.value:
|
|
96
|
+
self.name = carconnectivity_vehicle.name.value
|
|
97
|
+
carconnectivity_vehicle.manufacturer.add_observer(self.__on_manufacturer_change, Observable.ObserverEvent.VALUE_CHANGED,
|
|
98
|
+
on_transaction_end=True)
|
|
99
|
+
if carconnectivity_vehicle.manufacturer.enabled and self.manufacturer != carconnectivity_vehicle.manufacturer.value:
|
|
100
|
+
self.manufacturer = carconnectivity_vehicle.manufacturer.value
|
|
101
|
+
carconnectivity_vehicle.model.add_observer(self.__on_model_change, Observable.ObserverEvent.VALUE_CHANGED, on_transaction_end=True)
|
|
102
|
+
if carconnectivity_vehicle.model.enabled and self.model != carconnectivity_vehicle.model.value:
|
|
103
|
+
self.model = carconnectivity_vehicle.model.value
|
|
104
|
+
carconnectivity_vehicle.model_year.add_observer(self.__on_model_year_change, Observable.ObserverEvent.VALUE_CHANGED,
|
|
105
|
+
on_transaction_end=True)
|
|
106
|
+
if carconnectivity_vehicle.model_year.enabled and self.model_year != carconnectivity_vehicle.model_year.value:
|
|
107
|
+
self.model_year = carconnectivity_vehicle.model_year.value
|
|
108
|
+
carconnectivity_vehicle.type.add_observer(self.__on_type_change, Observable.ObserverEvent.VALUE_CHANGED, on_transaction_end=True)
|
|
109
|
+
if carconnectivity_vehicle.type.enabled and carconnectivity_vehicle.type.value is not None \
|
|
110
|
+
and self.type != carconnectivity_vehicle.type.value:
|
|
111
|
+
self.type = carconnectivity_vehicle.type.value
|
|
112
|
+
carconnectivity_vehicle.license_plate.add_observer(self.__on_license_plate_change, Observable.ObserverEvent.VALUE_CHANGED,
|
|
113
|
+
on_transaction_end=True)
|
|
114
|
+
if carconnectivity_vehicle.license_plate.enabled and self.license_plate != carconnectivity_vehicle.license_plate.value:
|
|
115
|
+
self.license_plate = carconnectivity_vehicle.license_plate.value
|
|
116
116
|
|
|
117
117
|
with session_factory() as session:
|
|
118
|
-
for drive_id, drive in
|
|
118
|
+
for drive_id, drive in carconnectivity_vehicle.drives.drives.items():
|
|
119
119
|
drive_db: Optional[Drive] = session.query(Drive).filter(Drive.vin == self.vin, Drive.drive_id == drive_id).first()
|
|
120
120
|
if drive_db is None:
|
|
121
121
|
drive_db = Drive(vin=self.vin, drive_id=drive_id)
|
|
@@ -123,30 +123,32 @@ class Vehicle(Base):
|
|
|
123
123
|
session.add(drive_db)
|
|
124
124
|
session.commit()
|
|
125
125
|
LOG.debug('Added new drive %s for vehicle %s to database', drive_id, self.vin)
|
|
126
|
-
drive_db.connect(session_factory, drive)
|
|
126
|
+
drive_db.connect(database_plugin, session_factory, drive)
|
|
127
127
|
except IntegrityError as err:
|
|
128
128
|
session.rollback()
|
|
129
129
|
LOG.error('IntegrityError while adding drive %s for vehicle %s to database, likely due to concurrent addition: %s', drive_id, self.vin,
|
|
130
130
|
err)
|
|
131
|
+
database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
131
132
|
except DatabaseError as err:
|
|
132
133
|
session.rollback()
|
|
133
134
|
LOG.error('DatabaseError while adding drive %s for vehicle %s to database: %s', drive_id, self.vin, err)
|
|
135
|
+
database_plugin.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
134
136
|
else:
|
|
135
|
-
drive_db.connect(session_factory, drive)
|
|
137
|
+
drive_db.connect(database_plugin, session_factory, drive)
|
|
136
138
|
LOG.debug('Connecting drive %s for vehicle %s', drive_id, self.vin)
|
|
137
139
|
|
|
138
|
-
state_agent: StateAgent = StateAgent(session_factory, self)
|
|
140
|
+
state_agent: StateAgent = StateAgent(database_plugin, session_factory, self, carconnectivity_vehicle)
|
|
139
141
|
self.agents.append(state_agent)
|
|
140
142
|
LOG.debug("Adding StateAgent to vehicle %s", self.vin)
|
|
141
|
-
climazination_agent: ClimatizationAgent = ClimatizationAgent(session_factory, self)
|
|
143
|
+
climazination_agent: ClimatizationAgent = ClimatizationAgent(database_plugin, session_factory, self, carconnectivity_vehicle)
|
|
142
144
|
self.agents.append(climazination_agent)
|
|
143
145
|
LOG.debug("Adding ClimatizationAgent to vehicle %s", self.vin)
|
|
144
|
-
trip_agent: TripAgent = TripAgent(session_factory, self)
|
|
146
|
+
trip_agent: TripAgent = TripAgent(database_plugin, session_factory, self, carconnectivity_vehicle)
|
|
145
147
|
self.agents.append(trip_agent)
|
|
146
148
|
LOG.debug("Adding TripAgent to vehicle %s", self.vin)
|
|
147
149
|
|
|
148
|
-
if isinstance(
|
|
149
|
-
charging_agent: ChargingAgent = ChargingAgent(session_factory, self)
|
|
150
|
+
if isinstance(carconnectivity_vehicle, ElectricVehicle):
|
|
151
|
+
charging_agent: ChargingAgent = ChargingAgent(database_plugin, session_factory, self, carconnectivity_vehicle)
|
|
150
152
|
self.agents.append(charging_agent)
|
|
151
153
|
LOG.debug("Adding ChargingAgent to vehicle %s", self.vin)
|
|
152
154
|
session_factory.remove()
|
|
@@ -93,11 +93,6 @@ class Plugin(BasePlugin): # pylint: disable=too-many-instance-attributes
|
|
|
93
93
|
session.commit()
|
|
94
94
|
self.car_connectivity.garage.add_observer(self.__on_add_vehicle, flag=Observable.ObserverEvent.ENABLED, on_transaction_end=True)
|
|
95
95
|
with self.vehicles_lock:
|
|
96
|
-
self.vehicles = {vehicle.vin: vehicle for vehicle in session.query(Vehicle).all()}
|
|
97
|
-
for vehicle in self.vehicles.values():
|
|
98
|
-
car_connectivity_vehicle: Optional[GenericVehicle] = self.car_connectivity.garage.get_vehicle(vehicle.vin)
|
|
99
|
-
if car_connectivity_vehicle is not None:
|
|
100
|
-
vehicle.connect(self.scoped_session_factory, car_connectivity_vehicle)
|
|
101
96
|
for garage_vehicle in self.car_connectivity.garage.list_vehicles():
|
|
102
97
|
if garage_vehicle.vin.value is not None and garage_vehicle.vin.value not in self.vehicles:
|
|
103
98
|
LOG.debug('New vehicle found in garage during startup: %s', garage_vehicle.vin.value)
|
|
@@ -108,15 +103,15 @@ class Plugin(BasePlugin): # pylint: disable=too-many-instance-attributes
|
|
|
108
103
|
session.add(new_vehicle)
|
|
109
104
|
session.commit()
|
|
110
105
|
LOG.debug('Added new vehicle %s to database', garage_vehicle.vin.value)
|
|
111
|
-
new_vehicle.connect(self.scoped_session_factory, garage_vehicle)
|
|
106
|
+
new_vehicle.connect(self, self.scoped_session_factory, garage_vehicle)
|
|
112
107
|
self.vehicles[garage_vehicle.vin.value] = new_vehicle
|
|
113
108
|
except DatabaseError as err:
|
|
114
109
|
session.rollback()
|
|
115
110
|
LOG.error('DatabaseError while adding vehicle %s to database: %s', garage_vehicle.vin.value, err)
|
|
111
|
+
self.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
116
112
|
else:
|
|
117
|
-
new_vehicle.connect(self.scoped_session_factory, garage_vehicle)
|
|
113
|
+
new_vehicle.connect(self, self.scoped_session_factory, garage_vehicle)
|
|
118
114
|
self.vehicles[garage_vehicle.vin.value] = new_vehicle
|
|
119
|
-
|
|
120
115
|
except OperationalError as err:
|
|
121
116
|
LOG.error('Could not establish a connection to database, will try again after 10 seconds: %s', err)
|
|
122
117
|
self.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
@@ -141,13 +136,13 @@ class Plugin(BasePlugin): # pylint: disable=too-many-instance-attributes
|
|
|
141
136
|
def __on_add_vehicle(self, element, flags) -> None:
|
|
142
137
|
del flags
|
|
143
138
|
with self.vehicles_lock:
|
|
144
|
-
if isinstance(element, GenericVehicle) and element.vin not in self.vehicles:
|
|
139
|
+
if isinstance(element, GenericVehicle) and element.vin.value not in self.vehicles:
|
|
145
140
|
LOG.debug('New vehicle added to garage: %s', element.vin)
|
|
146
141
|
if element.vin.value is not None:
|
|
147
142
|
with self.scoped_session_factory() as session:
|
|
148
143
|
if element.vin.value in self.vehicles:
|
|
149
144
|
vehicle: Vehicle = self.vehicles[element.vin.value]
|
|
150
|
-
vehicle.connect(self.scoped_session_factory, element)
|
|
145
|
+
vehicle.connect(self, self.scoped_session_factory, element)
|
|
151
146
|
else:
|
|
152
147
|
vehicle: Vehicle = session.get(Vehicle, element.vin.value)
|
|
153
148
|
if vehicle is None:
|
|
@@ -155,11 +150,12 @@ class Plugin(BasePlugin): # pylint: disable=too-many-instance-attributes
|
|
|
155
150
|
try:
|
|
156
151
|
session.add(vehicle)
|
|
157
152
|
session.commit()
|
|
158
|
-
vehicle.connect(self.scoped_session_factory, element)
|
|
153
|
+
vehicle.connect(self, self.scoped_session_factory, element)
|
|
159
154
|
except DatabaseError as err:
|
|
160
155
|
session.rollback()
|
|
161
156
|
LOG.error('DatabaseError while adding vehicle %s to database: %s', element.vin.value, err)
|
|
157
|
+
self.healthy._set_value(value=False) # pylint: disable=protected-access
|
|
162
158
|
else:
|
|
163
|
-
vehicle.connect(self.scoped_session_factory, element)
|
|
159
|
+
vehicle.connect(self, self.scoped_session_factory, element)
|
|
164
160
|
self.vehicles[element.vin.value] = vehicle
|
|
165
161
|
self.scoped_session_factory.remove()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|