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